@@ -1,724 +0,0 @@
< ? php
// Güvenlik: secret key olmadan çalışması n
if (( $_GET [ 'key' ] ? ? '' ) !== 'animexe2025' ) {
die ( 'Yetkisiz erişim.' );
}
define ( 'LARAVEL_START' , microtime ( true ));
require __DIR__ . '/../vendor/autoload.php' ;
$app = require __DIR__ . '/../bootstrap/app.php' ;
$kernel = $app -> make ( Illuminate\Contracts\Console\Kernel :: class );
$kernel -> bootstrap ();
echo '<pre style="background:#111;color:#0f0;padding:20px;font-size:13px">' ;
echo " === Animexe Migration & Seed === \n \n " ;
$db = app ( 'db' );
$sch = app ( 'db' ) -> getSchemaBuilder ();
$batch = ( $db -> table ( 'migrations' ) -> max ( 'batch' ) ? ? 0 ) + 1 ;
// Üretimde zaten uygulanmış ama migrations tablosuna kayı t edilmemiş migration'ları işaretle
// [ migration_name => kontrol fonksiyonu (true = zaten uygulanmış) ]
$alreadyApplied = [
'2024_01_01_000150_add_trending_to_animes' => fn () =>
$sch -> hasColumn ( 'animes' , 'is_trending' ),
'2024_01_01_000200_add_profile_fields_to_users' => fn () =>
$sch -> hasColumn ( 'users' , 'bio' ),
'2026_04_17_000001_create_blog_posts_table' => fn () =>
$sch -> hasTable ( 'blog_posts' ),
'2024_01_01_000200_add_intro_times_to_episodes' => fn () =>
$sch -> hasColumn ( 'episodes' , 'intro_start' ),
'2026_04_17_200001_create_social_features_tables' => fn () =>
$sch -> hasTable ( 'episode_timestamp_comments' ),
'2026_04_17_300000_create_community_features_tables' => fn () =>
$sch -> hasTable ( 'tribunals' ),
'2026_04_17_310000_add_extra_sides_to_tribunals' => fn () =>
$sch -> hasColumn ( 'tribunals' , 'extra_sides' ),
'2026_04_18_000001_create_bot_protection_tables' => fn () =>
$sch -> hasTable ( 'analytics_bot_logs' ),
'2026_04_19_000001_create_moderator_permissions_table' => fn () =>
$sch -> hasTable ( 'moderator_permissions' ) && $sch -> hasTable ( 'user_activity_logs' ),
'2026_04_19_000002_add_bot_columns_to_analytics_pageviews' => fn () =>
$sch -> hasColumn ( 'analytics_pageviews' , 'is_bot' ),
'2026_04_19_000010_create_seo_keyword_tracker_table' => fn () =>
$sch -> hasTable ( 'seo_keyword_tracker' ),
'2026_04_19_000011_create_seo_redirects_table' => fn () =>
$sch -> hasTable ( 'seo_redirects' ),
'2026_04_19_000012_add_seo_columns_to_animes' => fn () =>
$sch -> hasColumn ( 'animes' , 'seo_title' ),
];
// Kolon yoksa direkt SQL ile ekle (artisan fallback)
if ( ! $sch -> hasColumn ( 'episodes' , 'intro_start' )) {
echo " ▶ intro_start / intro_end kolonları ekleniyor... \n " ;
try {
$db -> statement ( " ALTER TABLE `episodes` ADD COLUMN `intro_start` SMALLINT UNSIGNED NULL DEFAULT NULL AFTER `duration`, ADD COLUMN `intro_end` SMALLINT UNSIGNED NULL DEFAULT NULL AFTER `intro_start` " );
$db -> table ( 'migrations' ) -> insertOrIgnore ([ 'migration' => '2024_01_01_000200_add_intro_times_to_episodes' , 'batch' => $batch ]);
echo " ✓ Kolonlar eklendi \n \n " ;
} catch ( \Throwable $e ) {
echo " ✗ HATA: " . $e -> getMessage () . " \n \n " ;
}
} else {
echo " ✓ intro_start / intro_end kolonları zaten mevcut \n \n " ;
}
foreach ( $alreadyApplied as $migration => $check ) {
$alreadyInDb = $db -> table ( 'migrations' ) -> where ( 'migration' , $migration ) -> exists ();
if ( $alreadyInDb ) {
echo " ✓ Kayı tlı : $migration \n " ;
continue ;
}
if ( $check ()) {
$db -> table ( 'migrations' ) -> insert ([ 'migration' => $migration , 'batch' => $batch ]);
echo " ⚡ Zaten uygulanmış, atlandı : $migration \n " ;
} else {
echo " ⏳ Beklemede (migrate ile çalışacak): $migration \n " ;
}
}
echo " \n " ;
// Kritik: blog_posts tablosu yoksa direkt SQL ile oluştur (migration başarı sı z olsa bile)
if ( ! $sch -> hasTable ( 'blog_posts' )) {
echo " ▶ blog_posts tablosu oluşturuluyor (fallback)... \n " ;
try {
$db -> statement ( " CREATE TABLE IF NOT EXISTS `blog_posts` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`title` varchar ( 255 ) NOT NULL ,
`slug` varchar ( 255 ) NOT NULL UNIQUE ,
`excerpt` text ,
`content` longtext ,
`cover_image` varchar ( 255 ) DEFAULT NULL ,
`focus_keyword` varchar ( 255 ) DEFAULT NULL ,
`meta_title` varchar ( 255 ) DEFAULT NULL ,
`meta_description` text ,
`meta_keywords` varchar ( 255 ) DEFAULT NULL ,
`status` enum ( 'draft' , 'published' , 'generating' ) NOT NULL DEFAULT 'draft' ,
`ai_generated` tinyint ( 1 ) NOT NULL DEFAULT 0 ,
`anime_id` bigint unsigned DEFAULT NULL ,
`linked_anime_ids` json DEFAULT NULL ,
`faq` json DEFAULT NULL ,
`views` int unsigned NOT NULL DEFAULT 0 ,
`reading_time` smallint unsigned NOT NULL DEFAULT 5 ,
`published_at` timestamp NULL DEFAULT NULL ,
`created_at` timestamp NULL DEFAULT NULL ,
`updated_at` timestamp NULL DEFAULT NULL ,
PRIMARY KEY ( `id` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci " );
// migrations tablosuna kaydet
$db -> table ( 'migrations' ) -> insert ([ 'migration' => '2026_04_17_000001_create_blog_posts_table' , 'batch' => $batch ]);
echo " ✓ blog_posts tablosu oluşturuldu \n \n " ;
} catch ( \Throwable $e ) {
echo " ✗ blog_posts fallback HATA: " . $e -> getMessage () . " \n \n " ;
}
} else {
echo " ✓ blog_posts tablosu zaten mevcut \n \n " ;
}
// Sosyal özellikler tabloları nı oluştur (fallback)
if ( ! $sch -> hasTable ( 'episode_timestamp_comments' )) {
echo " ▶ Sosyal özellikler tabloları oluşturuluyor... \n " ;
try {
$db -> statement ( " CREATE TABLE IF NOT EXISTS `episode_timestamp_comments` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`episode_id` bigint unsigned NOT NULL ,
`user_id` bigint unsigned DEFAULT NULL ,
`timestamp_sec` smallint unsigned NOT NULL ,
`body` varchar ( 100 ) NOT NULL ,
`color` varchar ( 7 ) NOT NULL DEFAULT '#ffffff' ,
`is_hidden` tinyint ( 1 ) NOT NULL DEFAULT 0 ,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ,
PRIMARY KEY ( `id` ),
KEY `idx_ep_ts` ( `episode_id` , `timestamp_sec` ),
KEY `idx_user` ( `user_id` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci " );
$db -> statement ( " CREATE TABLE IF NOT EXISTS `episode_predictions` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`episode_id` bigint unsigned NOT NULL ,
`user_id` bigint unsigned NOT NULL ,
`body` varchar ( 280 ) NOT NULL ,
`is_correct` tinyint ( 1 ) DEFAULT NULL ,
`vote_count` smallint unsigned NOT NULL DEFAULT 0 ,
`created_at` timestamp NULL DEFAULT NULL ,
`updated_at` timestamp NULL DEFAULT NULL ,
PRIMARY KEY ( `id` ),
UNIQUE KEY `uniq_ep_user` ( `episode_id` , `user_id` ),
KEY `idx_ep_votes` ( `episode_id` , `vote_count` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci " );
$db -> statement ( " CREATE TABLE IF NOT EXISTS `prediction_votes` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`prediction_id` bigint unsigned NOT NULL ,
`user_id` bigint unsigned NOT NULL ,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ,
PRIMARY KEY ( `id` ),
UNIQUE KEY `uniq_pred_user` ( `prediction_id` , `user_id` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci " );
$db -> statement ( " CREATE TABLE IF NOT EXISTS `watch_parties` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`room_code` varchar ( 10 ) NOT NULL ,
`host_user_id` bigint unsigned NOT NULL ,
`episode_id` bigint unsigned NOT NULL ,
`current_sec` int unsigned NOT NULL DEFAULT 0 ,
`is_playing` tinyint ( 1 ) NOT NULL DEFAULT 0 ,
`synced_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ,
`max_members` tinyint unsigned NOT NULL DEFAULT 10 ,
`is_private` tinyint ( 1 ) NOT NULL DEFAULT 0 ,
`password` varchar ( 60 ) DEFAULT NULL ,
`created_at` timestamp NULL DEFAULT NULL ,
`updated_at` timestamp NULL DEFAULT NULL ,
PRIMARY KEY ( `id` ),
UNIQUE KEY `uniq_code` ( `room_code` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci " );
$db -> statement ( " CREATE TABLE IF NOT EXISTS `watch_party_members` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`party_id` bigint unsigned NOT NULL ,
`user_id` bigint unsigned NOT NULL ,
`joined_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ,
`last_ping` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ,
PRIMARY KEY ( `id` ),
UNIQUE KEY `uniq_party_user` ( `party_id` , `user_id` ),
KEY `idx_party_ping` ( `party_id` , `last_ping` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci " );
$db -> statement ( " CREATE TABLE IF NOT EXISTS `first_watch_sessions` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`episode_id` bigint unsigned NOT NULL ,
`user_id` bigint unsigned DEFAULT NULL ,
`session_id` varchar ( 64 ) DEFAULT NULL ,
`is_first_time` tinyint ( 1 ) NOT NULL DEFAULT 1 ,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ,
`last_seen` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ,
PRIMARY KEY ( `id` ),
KEY `idx_ep_seen` ( `episode_id` , `last_seen` ),
KEY `idx_user` ( `user_id` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci " );
$db -> table ( 'migrations' ) -> insertOrIgnore ([ 'migration' => '2026_04_17_200001_create_social_features_tables' , 'batch' => $batch ]);
echo " ✓ Sosyal özellikler tabloları oluşturuldu \n \n " ;
} catch ( \Throwable $e ) {
echo " ✗ HATA: " . $e -> getMessage () . " \n \n " ;
}
} else {
echo " ✓ Sosyal özellikler tabloları zaten mevcut \n \n " ;
}
// Topluluk özellikleri tabloları (Mahkeme, Kapsül, Spoiler)
if ( ! $sch -> hasTable ( 'tribunals' )) {
echo " ▶ Topluluk özellikleri tabloları oluşturuluyor... \n " ;
try {
$db -> statement ( " CREATE TABLE IF NOT EXISTS `tribunals` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`anime_id` bigint unsigned NOT NULL ,
`episode_id` bigint unsigned DEFAULT NULL ,
`created_by` bigint unsigned NOT NULL ,
`question` varchar ( 280 ) NOT NULL ,
`side_a` varchar ( 100 ) NOT NULL ,
`side_b` varchar ( 100 ) NOT NULL ,
`extra_sides` json DEFAULT NULL ,
`status` enum ( 'open' , 'closed' ) NOT NULL DEFAULT 'open' ,
`verdict` varchar ( 1 ) DEFAULT NULL ,
`closes_at` timestamp NULL DEFAULT NULL ,
`created_at` timestamp NULL DEFAULT NULL ,
`updated_at` timestamp NULL DEFAULT NULL ,
PRIMARY KEY ( `id` ),
KEY `idx_anime` ( `anime_id` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci " );
$db -> statement ( " CREATE TABLE IF NOT EXISTS `tribunal_votes` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`tribunal_id` bigint unsigned NOT NULL ,
`user_id` bigint unsigned NOT NULL ,
`side` varchar ( 1 ) NOT NULL ,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ,
PRIMARY KEY ( `id` ),
UNIQUE KEY `uniq_t_user` ( `tribunal_id` , `user_id` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci " );
$db -> statement ( " CREATE TABLE IF NOT EXISTS `tribunal_arguments` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`tribunal_id` bigint unsigned NOT NULL ,
`user_id` bigint unsigned NOT NULL ,
`side` varchar ( 1 ) NOT NULL ,
`body` varchar ( 500 ) NOT NULL ,
`vote_count` smallint unsigned NOT NULL DEFAULT 0 ,
`created_at` timestamp NULL DEFAULT NULL ,
`updated_at` timestamp NULL DEFAULT NULL ,
PRIMARY KEY ( `id` ),
UNIQUE KEY `uniq_t_arg_user` ( `tribunal_id` , `user_id` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci " );
$db -> statement ( " CREATE TABLE IF NOT EXISTS `tribunal_argument_votes` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`argument_id` bigint unsigned NOT NULL ,
`user_id` bigint unsigned NOT NULL ,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ,
PRIMARY KEY ( `id` ),
UNIQUE KEY `uniq_av_user` ( `argument_id` , `user_id` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci " );
$db -> statement ( " CREATE TABLE IF NOT EXISTS `time_capsules` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`user_id` bigint unsigned NOT NULL ,
`anime_id` bigint unsigned NOT NULL ,
`message` text NOT NULL ,
`unlock_at` timestamp NOT NULL ,
`opened_at` timestamp NULL DEFAULT NULL ,
`created_at` timestamp NULL DEFAULT NULL ,
`updated_at` timestamp NULL DEFAULT NULL ,
PRIMARY KEY ( `id` ),
KEY `idx_user_unlock` ( `user_id` , `unlock_at` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci " );
$db -> statement ( " CREATE TABLE IF NOT EXISTS `spoiler_boxes` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`episode_id` bigint unsigned NOT NULL ,
`user_id` bigint unsigned NOT NULL ,
`body` text NOT NULL ,
`is_spoiler` tinyint ( 1 ) NOT NULL DEFAULT 0 ,
`spoiler_score` tinyint NOT NULL DEFAULT 0 ,
`likes` smallint unsigned NOT NULL DEFAULT 0 ,
`created_at` timestamp NULL DEFAULT NULL ,
`updated_at` timestamp NULL DEFAULT NULL ,
PRIMARY KEY ( `id` ),
KEY `idx_ep` ( `episode_id` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci " );
$db -> statement ( " CREATE TABLE IF NOT EXISTS `spoiler_box_likes` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`box_id` bigint unsigned NOT NULL ,
`user_id` bigint unsigned NOT NULL ,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ,
PRIMARY KEY ( `id` ),
UNIQUE KEY `uniq_box_user` ( `box_id` , `user_id` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci " );
$db -> statement ( " CREATE TABLE IF NOT EXISTS `mood_logs` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`user_id` bigint unsigned DEFAULT NULL ,
`episode_id` bigint unsigned NOT NULL ,
`mood` varchar ( 20 ) NOT NULL ,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ,
PRIMARY KEY ( `id` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci " );
$db -> table ( 'migrations' ) -> insertOrIgnore ([ 'migration' => '2026_04_17_300000_create_community_features_tables' , 'batch' => $batch ]);
echo " ✓ Topluluk özellikleri tabloları oluşturuldu \n \n " ;
} catch ( \Throwable $e ) {
echo " ✗ HATA: " . $e -> getMessage () . " \n \n " ;
}
} else {
echo " ✓ Topluluk özellikleri tabloları zaten mevcut \n \n " ;
}
// ── Bot koruma & gelişmiş analitik tabloları ─────────────────────────────────
if ( ! $sch -> hasTable ( 'analytics_bot_logs' ) || ! $sch -> hasTable ( 'analytics_sessions' ) || ! $sch -> hasTable ( 'blocked_ips' )) {
echo " ▶ Bot koruma tabloları oluşturuluyor... \n " ;
try {
if ( ! $sch -> hasTable ( 'analytics_bot_logs' )) {
$db -> statement ( " CREATE TABLE `analytics_bot_logs` (
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY ,
`ip` VARCHAR ( 45 ) NOT NULL ,
`user_agent` VARCHAR ( 500 ) NULL ,
`path` VARCHAR ( 500 ) NULL ,
`method` VARCHAR ( 10 ) NULL ,
`action` VARCHAR ( 20 ) NOT NULL DEFAULT 'allowed' ,
`bot_name` VARCHAR ( 100 ) NULL ,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ,
INDEX `idx_ip` ( `ip` ),
INDEX `idx_action` ( `action` ),
INDEX `idx_created` ( `created_at` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 " );
echo " ✓ analytics_bot_logs \n " ;
}
if ( ! $sch -> hasTable ( 'blocked_ips' )) {
$db -> statement ( " CREATE TABLE `blocked_ips` (
`id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY ,
`ip` VARCHAR ( 45 ) NOT NULL ,
`reason` VARCHAR ( 255 ) NULL ,
`auto_blocked` TINYINT ( 1 ) DEFAULT 0 ,
`blocked_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ,
`expires_at` TIMESTAMP NULL ,
UNIQUE KEY `uk_ip` ( `ip` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 " );
echo " ✓ blocked_ips \n " ;
}
if ( ! $sch -> hasTable ( 'analytics_sessions' )) {
$db -> statement ( " CREATE TABLE `analytics_sessions` (
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY ,
`session_id` VARCHAR ( 100 ) NOT NULL ,
`user_id` BIGINT UNSIGNED NULL ,
`ip` VARCHAR ( 45 ) NULL ,
`country` VARCHAR ( 100 ) NULL ,
`city` VARCHAR ( 100 ) NULL ,
`device` VARCHAR ( 20 ) NULL ,
`browser` VARCHAR ( 50 ) NULL ,
`referrer` VARCHAR ( 500 ) NULL ,
`landing_page` VARCHAR ( 500 ) NULL ,
`pages_visited` INT DEFAULT 1 ,
`total_seconds` INT DEFAULT 0 ,
`is_bot` TINYINT ( 1 ) DEFAULT 0 ,
`bot_type` VARCHAR ( 50 ) NULL ,
`user_agent` VARCHAR ( 500 ) NULL ,
`started_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ,
`last_seen_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ,
INDEX `idx_session` ( `session_id` ),
INDEX `idx_started` ( `started_at` ),
INDEX `idx_bot` ( `is_bot` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 " );
echo " ✓ analytics_sessions \n " ;
}
$db -> table ( 'migrations' ) -> insertOrIgnore ([ 'migration' => '2026_04_18_000001_create_bot_protection_tables' , 'batch' => $batch ]);
echo " ✓ Bot koruma tabloları hazı r \n \n " ;
} catch ( \Throwable $e ) {
echo " ✗ HATA: " . $e -> getMessage () . " \n \n " ;
}
} else {
echo " ✓ Bot koruma tabloları zaten mevcut \n \n " ;
}
// analytics_pageviews: is_bot, user_agent, time_on_page kolonları ekle
if ( $sch -> hasTable ( 'analytics_pageviews' )) {
$cols = [ 'is_bot' => 'TINYINT(1) DEFAULT 0' , 'user_agent' => 'VARCHAR(500) NULL' , 'time_on_page' => 'INT DEFAULT 0' ];
foreach ( $cols as $col => $def ) {
if ( ! $sch -> hasColumn ( 'analytics_pageviews' , $col )) {
try {
$db -> statement ( " ALTER TABLE `analytics_pageviews` ADD COLUMN ` { $col } ` { $def } " );
echo " ✓ analytics_pageviews. { $col } eklendi \n " ;
} catch ( \Throwable $e ) {
echo " ✗ { $col } : " . $e -> getMessage () . " \n " ;
}
}
}
}
// ── Moderatör izinleri & kullanı cı aktivite logları ──────────────────────────
if ( ! $sch -> hasTable ( 'moderator_permissions' )) {
echo " ▶ moderator_permissions tablosu oluşturuluyor... \n " ;
try {
$db -> statement ( " CREATE TABLE IF NOT EXISTS `moderator_permissions` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`user_id` bigint unsigned NOT NULL ,
`permission` varchar ( 80 ) NOT NULL ,
`granted_by` bigint unsigned NULL ,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ,
PRIMARY KEY ( `id` ),
UNIQUE KEY `uniq_user_perm` ( `user_id` , `permission` ),
KEY `idx_user_id` ( `user_id` ),
CONSTRAINT `fk_modperm_user` FOREIGN KEY ( `user_id` ) REFERENCES `users` ( `id` ) ON DELETE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 " );
$db -> table ( 'migrations' ) -> insertOrIgnore ([ 'migration' => '2026_04_19_000001_create_moderator_permissions_table' , 'batch' => $batch ]);
echo " ✓ moderator_permissions tablosu oluşturuldu \n \n " ;
} catch ( \Throwable $e ) {
echo " ✗ HATA: " . $e -> getMessage () . " \n \n " ;
}
} else {
echo " ✓ moderator_permissions tablosu zaten mevcut \n \n " ;
}
if ( ! $sch -> hasTable ( 'user_activity_logs' )) {
echo " ▶ user_activity_logs tablosu oluşturuluyor... \n " ;
try {
$db -> statement ( " CREATE TABLE IF NOT EXISTS `user_activity_logs` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`user_id` bigint unsigned NULL ,
`session_id` varchar ( 64 ) NULL ,
`action` varchar ( 60 ) NOT NULL ,
`subject_type` varchar ( 60 ) NULL ,
`subject_id` bigint unsigned NULL ,
`ip` varchar ( 45 ) NULL ,
`country` varchar ( 80 ) NULL ,
`city` varchar ( 80 ) NULL ,
`device` varchar ( 20 ) NULL ,
`browser` varchar ( 50 ) NULL ,
`user_agent` varchar ( 500 ) NULL ,
`is_bot` tinyint ( 1 ) NOT NULL DEFAULT 0 ,
`meta` json NULL ,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ,
PRIMARY KEY ( `id` ),
KEY `idx_user_created` ( `user_id` , `created_at` ),
KEY `idx_action_created` ( `action` , `created_at` ),
KEY `idx_country` ( `country` ),
KEY `idx_is_bot` ( `is_bot` ),
KEY `idx_session` ( `session_id` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 " );
$db -> table ( 'migrations' ) -> insertOrIgnore ([ 'migration' => '2026_04_19_000001_create_moderator_permissions_table' , 'batch' => $batch ]);
echo " ✓ user_activity_logs tablosu oluşturuldu \n \n " ;
} catch ( \Throwable $e ) {
echo " ✗ HATA: " . $e -> getMessage () . " \n \n " ;
}
} else {
echo " ✓ user_activity_logs tablosu zaten mevcut \n \n " ;
}
// analytics_pageviews: is_bot, user_agent, time_on_page kolonları (önceki bloktan bağımsı z tekrar kontrol)
if ( $sch -> hasTable ( 'analytics_pageviews' )) {
foreach ([ 'is_bot' => 'TINYINT(1) DEFAULT 0' , 'user_agent' => 'VARCHAR(500) NULL' , 'time_on_page' => 'SMALLINT UNSIGNED DEFAULT 0' ] as $col => $def ) {
if ( ! $sch -> hasColumn ( 'analytics_pageviews' , $col )) {
try {
$db -> statement ( " ALTER TABLE `analytics_pageviews` ADD COLUMN ` { $col } ` { $def } " );
echo " ✓ analytics_pageviews. { $col } eklendi \n " ;
} catch ( \Throwable $e ) {
echo " ✗ { $col } : " . $e -> getMessage () . " \n " ;
}
}
}
$db -> table ( 'migrations' ) -> insertOrIgnore ([ 'migration' => '2026_04_19_000002_add_bot_columns_to_analytics_pageviews' , 'batch' => $batch ]);
}
echo " \n " ;
// ── SEO tabloları ─────────────────────────────────────────────────────────
if ( ! $sch -> hasTable ( 'seo_keyword_tracker' )) {
echo " ▶ seo_keyword_tracker tablosu oluşturuluyor... \n " ;
try {
$db -> statement ( " CREATE TABLE IF NOT EXISTS `seo_keyword_tracker` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`keyword` varchar ( 255 ) NOT NULL ,
`target_url` varchar ( 500 ) NULL ,
`search_volume` int DEFAULT NULL ,
`difficulty` tinyint unsigned DEFAULT NULL ,
`notes` text NULL ,
`created_at` timestamp NULL ,
`updated_at` timestamp NULL ,
PRIMARY KEY ( `id` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 " );
$db -> table ( 'migrations' ) -> insertOrIgnore ([ 'migration' => '2026_04_19_000010_create_seo_keyword_tracker_table' , 'batch' => $batch ]);
echo " ✓ seo_keyword_tracker oluşturuldu \n \n " ;
} catch ( \Throwable $e ) { echo " ✗ HATA: " . $e -> getMessage () . " \n \n " ; }
} else { echo " ✓ seo_keyword_tracker zaten mevcut \n \n " ; }
if ( ! $sch -> hasTable ( 'seo_redirects' )) {
echo " ▶ seo_redirects tablosu oluşturuluyor... \n " ;
try {
$db -> statement ( " CREATE TABLE IF NOT EXISTS `seo_redirects` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`from_path` varchar ( 500 ) NOT NULL ,
`to_path` varchar ( 500 ) NOT NULL ,
`type` smallint NOT NULL DEFAULT 301 ,
`hits` int NOT NULL DEFAULT 0 ,
`is_active` tinyint ( 1 ) NOT NULL DEFAULT 1 ,
`created_at` timestamp NULL ,
`updated_at` timestamp NULL ,
PRIMARY KEY ( `id` ),
UNIQUE KEY `seo_redirects_from_unique` ( `from_path` ( 191 ))
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 " );
$db -> table ( 'migrations' ) -> insertOrIgnore ([ 'migration' => '2026_04_19_000011_create_seo_redirects_table' , 'batch' => $batch ]);
echo " ✓ seo_redirects oluşturuldu \n \n " ;
} catch ( \Throwable $e ) { echo " ✗ HATA: " . $e -> getMessage () . " \n \n " ; }
} else { echo " ✓ seo_redirects zaten mevcut \n \n " ; }
foreach ([ 'seo_title' => 'VARCHAR(100) NULL' , 'seo_meta_desc' => 'VARCHAR(320) NULL' , 'seo_keywords' => 'VARCHAR(500) NULL' ] as $col => $def ) {
if ( ! $sch -> hasColumn ( 'animes' , $col )) {
try {
$db -> statement ( " ALTER TABLE `animes` ADD COLUMN ` { $col } ` { $def } " );
echo " ✓ animes. { $col } eklendi \n " ;
} catch ( \Throwable $e ) { echo " ✗ { $col } : " . $e -> getMessage () . " \n " ; }
}
}
$db -> table ( 'migrations' ) -> insertOrIgnore ([ 'migration' => '2026_04_19_000012_add_seo_columns_to_animes' , 'batch' => $batch ]);
echo " \n " ;
// extra_sides kolonu yoksa ekle (tribunals tablosu önceden oluşturulmuşsa)
if ( $sch -> hasTable ( 'tribunals' ) && ! $sch -> hasColumn ( 'tribunals' , 'extra_sides' )) {
echo " ▶ tribunals.extra_sides kolonu ekleniyor... \n " ;
try {
$db -> statement ( " ALTER TABLE `tribunals` ADD COLUMN `extra_sides` json DEFAULT NULL AFTER `side_b` " );
$db -> table ( 'migrations' ) -> insertOrIgnore ([ 'migration' => '2026_04_17_310000_add_extra_sides_to_tribunals' , 'batch' => $batch ]);
echo " ✓ extra_sides eklendi \n \n " ;
} catch ( \Throwable $e ) {
echo " ✗ HATA: " . $e -> getMessage () . " \n \n " ;
}
} else {
echo " ✓ tribunals.extra_sides zaten mevcut \n \n " ;
}
// ── Animecix scraper tabloları ────────────────────────────────────────────────
// 1. import_jobs: source, animecix_title_id, animecix_slug kolonları
if ( ! $sch -> hasColumn ( 'import_jobs' , 'animecix_title_id' )) {
echo " ▶ import_jobs animecix kolonları ekleniyor... \n " ;
try {
if ( ! $sch -> hasColumn ( 'import_jobs' , 'source' )) {
$db -> statement ( " ALTER TABLE `import_jobs` ADD COLUMN `source` VARCHAR(30) NOT NULL DEFAULT 'anizium' AFTER `id` " );
}
$db -> statement ( " ALTER TABLE `import_jobs` ADD COLUMN `animecix_title_id` VARCHAR(50) NULL AFTER `source` " );
$db -> statement ( " ALTER TABLE `import_jobs` ADD COLUMN `animecix_slug` VARCHAR(300) NULL AFTER `animecix_title_id` " );
$db -> table ( 'migrations' ) -> insertOrIgnore ([ 'migration' => '2024_01_01_000120_add_animecix_fields_to_import_jobs' , 'batch' => $batch ]);
echo " ✓ import_jobs animecix kolonları eklendi \n \n " ;
} catch ( \Throwable $e ) {
echo " ✗ HATA: " . $e -> getMessage () . " \n \n " ;
}
} else {
echo " ✓ import_jobs animecix kolonları zaten mevcut \n \n " ;
}
// 2. video_sources tablosu
if ( ! $sch -> hasTable ( 'video_sources' )) {
echo " ▶ video_sources tablosu oluşturuluyor... \n " ;
try {
$db -> statement ( " CREATE TABLE IF NOT EXISTS `video_sources` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`episode_id` bigint unsigned NOT NULL ,
`label` varchar ( 120 ) NOT NULL DEFAULT '' ,
`url` varchar ( 2000 ) NOT NULL ,
`type` enum ( 'mp4' , 'hls' , 'embed' ) NOT NULL DEFAULT 'mp4' ,
`quality` varchar ( 20 ) NOT NULL DEFAULT '' ,
`translator_id` varchar ( 60 ) NULL ,
`sort_order` smallint unsigned NOT NULL DEFAULT 0 ,
`is_default` tinyint ( 1 ) NOT NULL DEFAULT 0 ,
`source` varchar ( 30 ) NOT NULL DEFAULT 'animecix' ,
`created_at` timestamp NULL DEFAULT NULL ,
`updated_at` timestamp NULL DEFAULT NULL ,
PRIMARY KEY ( `id` ),
KEY `idx_episode_sort` ( `episode_id` , `sort_order` ),
KEY `idx_source` ( `source` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci " );
$db -> table ( 'migrations' ) -> insertOrIgnore ([ 'migration' => '2024_01_01_000121_create_video_sources_table' , 'batch' => $batch ]);
echo " ✓ video_sources tablosu oluşturuldu \n \n " ;
} catch ( \Throwable $e ) {
echo " ✗ HATA: " . $e -> getMessage () . " \n \n " ;
}
} else {
echo " ✓ video_sources tablosu zaten mevcut \n \n " ;
}
// 3. episodes.source ENUM'a 'animecix' ekle
try {
$enumCheck = $db -> select ( " SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'episodes' AND COLUMN_NAME = 'source' " );
$enumDef = $enumCheck [ 0 ] -> COLUMN_TYPE ? ? '' ;
if ( ! str_contains ( $enumDef , 'animecix' )) {
echo " ▶ episodes.source ENUM'a animecix ekleniyor... \n " ;
$db -> statement ( " ALTER TABLE `episodes` MODIFY COLUMN `source` ENUM('bunnycdn','external','direct','anizium','animecix') NOT NULL DEFAULT 'bunnycdn' " );
$db -> table ( 'migrations' ) -> insertOrIgnore ([ 'migration' => '2024_01_01_000122_add_animecix_to_episodes_source_enum' , 'batch' => $batch ]);
echo " ✓ episodes.source güncellendi \n \n " ;
} else {
echo " ✓ episodes.source zaten animecix içeriyor \n \n " ;
}
} catch ( \Throwable $e ) {
echo " ✗ HATA: " . $e -> getMessage () . " \n \n " ;
}
// 4. nextJob() için: import_jobs.source kolonu varsa INDEX ekle (performans)
try {
$idxCheck = $db -> select ( " SHOW INDEX FROM import_jobs WHERE Key_name = 'idx_source_status' " );
if ( empty ( $idxCheck ) && $sch -> hasColumn ( 'import_jobs' , 'source' )) {
$db -> statement ( " ALTER TABLE `import_jobs` ADD INDEX `idx_source_status` (`source`, `status`) " );
echo " ✓ import_jobs(source, status) index eklendi \n \n " ;
}
} catch ( \Throwable $e ) {}
// ── 2026_05_14_000001: membership_plans.is_public, visible_until / users.admin_badge ──
echo " ▶ Plan görünürlük & admin rozet kolonları kontrol ediliyor... \n " ;
$planVis = [
'is_public' => " TINYINT(1) NOT NULL DEFAULT 1 AFTER `is_active` " ,
'visible_until' => " TIMESTAMP NULL DEFAULT NULL AFTER `is_public` " ,
];
foreach ( $planVis as $col => $def ) {
if ( ! $sch -> hasColumn ( 'membership_plans' , $col )) {
try {
$db -> statement ( " ALTER TABLE `membership_plans` ADD COLUMN ` { $col } ` { $def } " );
echo " ✓ membership_plans. { $col } eklendi \n " ;
} catch ( \Throwable $e ) { echo " ✗ { $col } : " . $e -> getMessage () . " \n " ; }
} else {
echo " ✓ membership_plans. { $col } zaten mevcut \n " ;
}
}
if ( ! $sch -> hasColumn ( 'users' , 'admin_badge' )) {
try {
$db -> statement ( " ALTER TABLE `users` ADD COLUMN `admin_badge` VARCHAR(32) NULL " );
echo " ✓ users.admin_badge eklendi \n " ;
} catch ( \Throwable $e ) { echo " ✗ admin_badge: " . $e -> getMessage () . " \n " ; }
} else {
echo " ✓ users.admin_badge zaten mevcut \n " ;
}
$db -> table ( 'migrations' ) -> insertOrIgnore ([ 'migration' => '2026_05_14_000001_add_plan_visibility_and_admin_badge' , 'batch' => $batch ]);
echo " \n " ;
// ── 2026_05_14_000002: membership_plans.trial_days / users.profile_music_url ──
echo " ▶ Deneme süresi & profil müzik kolonları kontrol ediliyor... \n " ;
if ( ! $sch -> hasColumn ( 'membership_plans' , 'trial_days' )) {
try {
$db -> statement ( " ALTER TABLE `membership_plans` ADD COLUMN `trial_days` SMALLINT UNSIGNED NOT NULL DEFAULT 0 AFTER `duration_days` " );
echo " ✓ membership_plans.trial_days eklendi \n " ;
} catch ( \Throwable $e ) { echo " ✗ trial_days: " . $e -> getMessage () . " \n " ; }
} else {
echo " ✓ membership_plans.trial_days zaten mevcut \n " ;
}
if ( ! $sch -> hasColumn ( 'users' , 'profile_music_url' )) {
try {
$db -> statement ( " ALTER TABLE `users` ADD COLUMN `profile_music_url` VARCHAR(500) NULL " );
echo " ✓ users.profile_music_url eklendi \n " ;
} catch ( \Throwable $e ) { echo " ✗ profile_music_url: " . $e -> getMessage () . " \n " ; }
} else {
echo " ✓ users.profile_music_url zaten mevcut \n " ;
}
$db -> table ( 'migrations' ) -> insertOrIgnore ([ 'migration' => '2026_05_14_000002_add_trial_days_and_profile_music' , 'batch' => $batch ]);
echo " \n " ;
// ── payments tablosu ──────────────────────────────────────────────────────────
if ( ! $sch -> hasTable ( 'payments' )) {
echo " ▶ payments tablosu oluşturuluyor... \n " ;
try {
$db -> statement ( " CREATE TABLE IF NOT EXISTS `payments` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT ,
`user_id` bigint unsigned NOT NULL ,
`plan_id` bigint unsigned NOT NULL ,
`conversation_id` varchar ( 100 ) NOT NULL ,
`token` varchar ( 200 ) NULL ,
`amount` decimal ( 10 , 2 ) NOT NULL ,
`status` enum ( 'pending' , 'success' , 'failed' ) NOT NULL DEFAULT 'pending' ,
`iyzico_payment_id` varchar ( 100 ) NULL ,
`error_message` text NULL ,
`paid_at` timestamp NULL ,
`created_at` timestamp NULL ,
`updated_at` timestamp NULL ,
PRIMARY KEY ( `id` ),
UNIQUE KEY `uniq_conversation` ( `conversation_id` ),
KEY `idx_user` ( `user_id` ),
KEY `idx_token` ( `token` ( 191 )),
KEY `idx_status` ( `status` )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci " );
$db -> table ( 'migrations' ) -> insertOrIgnore ([ 'migration' => '2026_05_14_000003_create_payments_table' , 'batch' => $batch ]);
echo " ✓ payments tablosu oluşturuldu \n \n " ;
} catch ( \Throwable $e ) {
echo " ✗ HATA: " . $e -> getMessage () . " \n \n " ;
}
} else {
echo " ✓ payments tablosu zaten mevcut \n \n " ;
}
$commands = [
[ 'migrate' , [ '--force' => true ]],
[ 'db:seed' , [ '--class' => 'AchievementSeeder' , '--force' => true ]],
[ 'config:clear' , []],
[ 'view:clear' , []],
[ 'route:clear' , []],
];
foreach ( $commands as [ $cmd , $args ]) {
echo " ▶ php artisan $cmd " . implode ( ' ' , array_keys ( $args )) . " \n " ;
try {
Illuminate\Support\Facades\Artisan :: call ( $cmd , $args );
echo Illuminate\Support\Facades\Artisan :: output ();
echo " ✓ Tamam \n \n " ;
} catch ( \Throwable $e ) {
echo " ✗ HATA: " . $e -> getMessage () . " \n \n " ;
}
}
echo " === Tamamlandı === \n " ;
echo '</pre>' ;