CREATE TABLE `challenge_session_answers` ( `id` char(36) NOT NULL, `session_id` char(36) NOT NULL, `user_id` char(36) NOT NULL, `question_id` char(36) NOT NULL, `submit_request_id` varchar(80) NOT NULL, `answer_order` tinyint NOT NULL, `answer` varchar(500), `correct` tinyint NOT NULL, `time_ms` int, `combo_count` tinyint DEFAULT 0, `result_snapshot` json, `submitted_at` datetime DEFAULT CURRENT_TIMESTAMP, CONSTRAINT `challenge_session_answers_id` PRIMARY KEY(`id`), CONSTRAINT `uk_challenge_answer_session_question` UNIQUE(`session_id`,`question_id`), CONSTRAINT `uk_challenge_answer_session_request` UNIQUE(`session_id`,`submit_request_id`) ); --> statement-breakpoint CREATE TABLE `challenge_sessions` ( `id` char(36) NOT NULL, `user_id` char(36) NOT NULL, `track_id` varchar(50) NOT NULL, `category_id` varchar(50) NOT NULL, `chapter_id` char(36), `status` enum('pending','in_progress','completed','abandoned','expired') DEFAULT 'pending', `client_request_id` varchar(80) NOT NULL, `complete_request_id` varchar(80), `question_ids` json NOT NULL, `total_questions` tinyint DEFAULT 5, `answered_count` tinyint DEFAULT 0, `correct_count` tinyint DEFAULT 0, `high_reward_eligible` tinyint DEFAULT 1, `reward_snapshot` json, `progress_before` json, `progress_after` json, `expires_at` datetime, `completed_at` datetime, `created_at` datetime DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT `challenge_sessions_id` PRIMARY KEY(`id`), CONSTRAINT `uk_challenge_session_user_client_request` UNIQUE(`user_id`,`client_request_id`), CONSTRAINT `uk_challenge_session_user_complete_request` UNIQUE(`user_id`,`complete_request_id`) ); --> statement-breakpoint CREATE TABLE `inventory_transactions` ( `id` char(36) NOT NULL, `user_id` char(36) NOT NULL, `inventory_item_id` char(36), `item_id` enum('coins','streak_shield','double_xp_potion','heart_supply','hint_feather','mascot_outfit') NOT NULL, `direction` enum('grant','consume','adjust') NOT NULL, `quantity_delta` int NOT NULL, `balance_after` int, `source_type` enum('challenge','daily_task','level_up','theme_node','chest','shop_purchase','ad_recovery','subscription','admin_grant','system_adjust') NOT NULL, `source_id` varchar(120), `idempotency_key` varchar(160), `snapshot` json, `created_at` datetime DEFAULT CURRENT_TIMESTAMP, CONSTRAINT `inventory_transactions_id` PRIMARY KEY(`id`), CONSTRAINT `uk_inventory_transaction_idempotency` UNIQUE(`user_id`,`idempotency_key`) ); --> statement-breakpoint CREATE TABLE `reward_ledger` ( `id` char(36) NOT NULL, `user_id` char(36) NOT NULL, `source_type` enum('challenge_answer','challenge_completion','daily_task','streak_milestone','level_up','theme_node','knowledge_card','chest','shop_purchase','ad_recovery','leaderboard_settlement','subscription','admin_grant','system_adjust') NOT NULL, `source_id` varchar(120), `idempotency_key` varchar(160) NOT NULL, `status` enum('pending','settling','completed','failed','reversed') DEFAULT 'pending', `reward_snapshot` json NOT NULL, `resource_deltas` json, `state_before` json, `state_after` json, `failure_reason` varchar(120), `settled_at` datetime, `created_at` datetime DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT `reward_ledger_id` PRIMARY KEY(`id`), CONSTRAINT `uk_reward_ledger_user_idempotency` UNIQUE(`user_id`,`idempotency_key`) ); --> statement-breakpoint CREATE TABLE `user_daily_progress` ( `id` char(36) NOT NULL, `user_id` char(36) NOT NULL, `progress_date` date NOT NULL, `timezone` varchar(50) DEFAULT 'UTC', `first_challenge_session_id` char(36), `first_challenge_completed_at` datetime, `challenge_sessions_completed` smallint DEFAULT 0, `high_reward_sessions_max` smallint DEFAULT 3, `high_reward_sessions_used` smallint DEFAULT 0, `high_reward_sessions_restored` smallint DEFAULT 0, `daily_tasks_completed` smallint DEFAULT 0, `daily_tasks_reward_claimed` smallint DEFAULT 0, `xp_earned` int DEFAULT 0, `coins_earned` int DEFAULT 0, `streak_counted` tinyint DEFAULT 0, `metadata` json, `created_at` datetime DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT `user_daily_progress_id` PRIMARY KEY(`id`), CONSTRAINT `uk_daily_progress_user_date` UNIQUE(`user_id`,`progress_date`) ); --> statement-breakpoint CREATE TABLE `user_daily_tasks` ( `id` char(36) NOT NULL, `daily_progress_id` char(36) NOT NULL, `user_id` char(36) NOT NULL, `task_date` date NOT NULL, `task_id` varchar(80) NOT NULL, `task_type` enum('complete_challenge','earn_xp','answer_correct','review_explanation','use_item','watch_ad') NOT NULL, `target_count` smallint DEFAULT 1, `current_count` smallint DEFAULT 0, `status` enum('active','completed','reward_claimed','expired') DEFAULT 'active', `reward_snapshot` json, `completed_at` datetime, `reward_claimed_at` datetime, `created_at` datetime DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT `user_daily_tasks_id` PRIMARY KEY(`id`), CONSTRAINT `uk_daily_task_user_date_task` UNIQUE(`user_id`,`task_date`,`task_id`) ); --> statement-breakpoint CREATE TABLE `user_inventory_items` ( `id` char(36) NOT NULL, `user_id` char(36) NOT NULL, `item_id` enum('streak_shield','double_xp_potion','heart_supply','hint_feather','mascot_outfit') NOT NULL, `quantity` int DEFAULT 0, `active_until` datetime, `metadata` json, `created_at` datetime DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT `user_inventory_items_id` PRIMARY KEY(`id`), CONSTRAINT `uk_inventory_user_item` UNIQUE(`user_id`,`item_id`) ); --> statement-breakpoint CREATE TABLE `user_wallets` ( `user_id` char(36) NOT NULL, `coins_balance` int DEFAULT 0, `lifetime_coins_earned` int DEFAULT 0, `lifetime_coins_spent` int DEFAULT 0, `created_at` datetime DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT `user_wallets_user_id` PRIMARY KEY(`user_id`) ); --> statement-breakpoint CREATE TABLE `user_weekly_xp` ( `id` char(36) NOT NULL, `user_id` char(36) NOT NULL, `week_start` date NOT NULL, `week_end` date NOT NULL, `timezone` varchar(50) DEFAULT 'UTC', `xp_earned` int DEFAULT 0, `challenge_sessions_completed` int DEFAULT 0, `group_id` varchar(80), `rank` int, `settled` tinyint DEFAULT 0, `settled_at` datetime, `last_xp_at` datetime, `next_refresh_at` datetime, `created_at` datetime DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT `user_weekly_xp_id` PRIMARY KEY(`id`), CONSTRAINT `uk_weekly_xp_user_week` UNIQUE(`user_id`,`week_start`) ); --> statement-breakpoint DROP INDEX `idx_user_week` ON `leaderboard_snapshots`;--> statement-breakpoint ALTER TABLE `leaderboard_snapshots` MODIFY COLUMN `week_start` date NOT NULL;--> statement-breakpoint ALTER TABLE `leaderboard_snapshots` MODIFY COLUMN `week_end` date NOT NULL;--> statement-breakpoint ALTER TABLE `leaderboard_snapshots` ADD `group_id` varchar(80);--> statement-breakpoint ALTER TABLE `leaderboard_snapshots` ADD `reward_snapshot` json;--> statement-breakpoint ALTER TABLE `leaderboard_snapshots` ADD `settled_at` datetime;--> statement-breakpoint ALTER TABLE `leaderboard_snapshots` ADD CONSTRAINT `uk_leaderboard_snapshot_user_week` UNIQUE(`user_id`,`week_start`);--> statement-breakpoint ALTER TABLE `challenge_session_answers` ADD CONSTRAINT `challenge_session_answers_session_id_challenge_sessions_id_fk` FOREIGN KEY (`session_id`) REFERENCES `challenge_sessions`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE `challenge_session_answers` ADD CONSTRAINT `challenge_session_answers_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE `challenge_session_answers` ADD CONSTRAINT `challenge_session_answers_question_id_questions_id_fk` FOREIGN KEY (`question_id`) REFERENCES `questions`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE `challenge_sessions` ADD CONSTRAINT `challenge_sessions_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE `challenge_sessions` ADD CONSTRAINT `challenge_sessions_category_id_categories_id_fk` FOREIGN KEY (`category_id`) REFERENCES `categories`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE `challenge_sessions` ADD CONSTRAINT `challenge_sessions_chapter_id_skill_tree_id_fk` FOREIGN KEY (`chapter_id`) REFERENCES `skill_tree`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE `inventory_transactions` ADD CONSTRAINT `inventory_transactions_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE `inventory_transactions` ADD CONSTRAINT `inventory_transactions_inventory_item_id_user_inventory_items_id_fk` FOREIGN KEY (`inventory_item_id`) REFERENCES `user_inventory_items`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE `reward_ledger` ADD CONSTRAINT `reward_ledger_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE `user_daily_progress` ADD CONSTRAINT `user_daily_progress_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE `user_daily_progress` ADD CONSTRAINT `user_daily_progress_first_challenge_session_id_challenge_sessions_id_fk` FOREIGN KEY (`first_challenge_session_id`) REFERENCES `challenge_sessions`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE `user_daily_tasks` ADD CONSTRAINT `user_daily_tasks_daily_progress_id_user_daily_progress_id_fk` FOREIGN KEY (`daily_progress_id`) REFERENCES `user_daily_progress`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE `user_daily_tasks` ADD CONSTRAINT `user_daily_tasks_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE `user_inventory_items` ADD CONSTRAINT `user_inventory_items_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE `user_wallets` ADD CONSTRAINT `user_wallets_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE `user_weekly_xp` ADD CONSTRAINT `user_weekly_xp_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint CREATE INDEX `idx_challenge_answer_user_submitted` ON `challenge_session_answers` (`user_id`,`submitted_at`);--> statement-breakpoint CREATE INDEX `idx_challenge_session_user_status_created` ON `challenge_sessions` (`user_id`,`status`,`created_at`);--> statement-breakpoint CREATE INDEX `idx_challenge_session_chapter_status` ON `challenge_sessions` (`chapter_id`,`status`);--> statement-breakpoint CREATE INDEX `idx_inventory_transaction_user_created` ON `inventory_transactions` (`user_id`,`created_at`);--> statement-breakpoint CREATE INDEX `idx_inventory_transaction_source` ON `inventory_transactions` (`source_type`,`source_id`);--> statement-breakpoint CREATE INDEX `idx_reward_ledger_user_status_created` ON `reward_ledger` (`user_id`,`status`,`created_at`);--> statement-breakpoint CREATE INDEX `idx_reward_ledger_source` ON `reward_ledger` (`source_type`,`source_id`);--> statement-breakpoint CREATE INDEX `idx_daily_progress_date` ON `user_daily_progress` (`progress_date`);--> statement-breakpoint CREATE INDEX `idx_daily_task_progress_status` ON `user_daily_tasks` (`daily_progress_id`,`status`);--> statement-breakpoint CREATE INDEX `idx_inventory_user_active` ON `user_inventory_items` (`user_id`,`active_until`);--> statement-breakpoint CREATE INDEX `idx_weekly_xp_group_rank` ON `user_weekly_xp` (`group_id`,`week_start`,`xp_earned`);--> statement-breakpoint CREATE INDEX `idx_weekly_xp_week_settled` ON `user_weekly_xp` (`week_start`,`settled`);--> statement-breakpoint CREATE INDEX `idx_leaderboard_snapshot_group_rank` ON `leaderboard_snapshots` (`group_id`,`week_start`,`rank`);