-- Yumi Gift Challenge: ordinary GOLD gift ledger, daily/overall ranking, three daily tasks, -- frozen reward templates and two-phase item-level settlement. -- -- Performance review: -- 1. The MQ hot path resolves at most one enabled activity through -- (sys_origin, enabled, start_time, end_time), deduplicates by a unique event key, and updates -- one overall plus one daily aggregate primary key. Ranking never GROUP BYs the gift ledger. -- 2. Daily/overall ranks use covering order indexes matching -- score DESC, score_reached_time ASC, user_id ASC; user-rank counts remain activity/date scoped. -- 3. Settlement discovery uses (status, snapshot_due_time), while parent and delivery claims use -- unique owner/business keys and narrow owner/status indexes. UNKNOWN items are never auto-retried. -- 4. This migration creates empty tables only: no UPDATE, DELETE, backfill, table-copy ALTER, or -- unbounded scan is executed. Run DDL under the target database's normal online-DDL policy. SET NAMES utf8mb4; CREATE TABLE IF NOT EXISTS `yumi_gift_challenge_activity` ( `id` BIGINT NOT NULL, `activity_code` VARCHAR(64) NOT NULL, `activity_name` VARCHAR(128) NOT NULL, `activity_desc` VARCHAR(1000) NOT NULL DEFAULT '', `sys_origin` VARCHAR(32) NOT NULL, `time_zone` VARCHAR(64) NOT NULL DEFAULT 'Asia/Riyadh', `start_time` DATETIME(3) NOT NULL, `end_time` DATETIME(3) NOT NULL, `daily_settlement_delay_minutes` INT NOT NULL DEFAULT 30, `overall_settlement_delay_minutes` INT NOT NULL DEFAULT 30, `overall_settlement_time` DATETIME(3) NOT NULL, `display_top_n` INT NOT NULL DEFAULT 100, `enabled` TINYINT(1) NOT NULL DEFAULT 0, `overall_settlement_status` VARCHAR(32) NOT NULL DEFAULT 'NOT_STARTED', `version` INT NOT NULL DEFAULT 0, `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`id`), UNIQUE KEY `uk_yumi_gc_activity_code` (`activity_code`), KEY `idx_yumi_gc_activity_window` (`sys_origin`, `enabled`, `start_time`, `end_time`), KEY `idx_yumi_gc_activity_settle` (`overall_settlement_status`, `overall_settlement_time`, `id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Yumi gift challenge activity cycle'; CREATE TABLE IF NOT EXISTS `yumi_gift_challenge_task_config` ( `id` BIGINT NOT NULL, `activity_id` BIGINT NOT NULL, `task_code` VARCHAR(64) NOT NULL, `task_type` VARCHAR(32) NOT NULL, `task_title` VARCHAR(128) NOT NULL, `task_desc` VARCHAR(500) NOT NULL DEFAULT '', `target_value` DECIMAL(24,2) NOT NULL, `resource_group_id` BIGINT NULL, `enabled` TINYINT(1) NOT NULL DEFAULT 1, `sort_order` TINYINT NOT NULL, `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`id`), UNIQUE KEY `uk_yumi_gc_task_code` (`activity_id`, `task_code`), UNIQUE KEY `uk_yumi_gc_task_sort` (`activity_id`, `sort_order`), KEY `idx_yumi_gc_task_enabled` (`activity_id`, `enabled`, `sort_order`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Exactly three Yumi gift challenge daily tasks'; CREATE TABLE IF NOT EXISTS `yumi_gift_challenge_rank_reward` ( `id` BIGINT NOT NULL, `activity_id` BIGINT NOT NULL, `period_type` VARCHAR(16) NOT NULL, `start_rank` INT NOT NULL, `end_rank` INT NOT NULL, `resource_group_id` BIGINT NOT NULL, `reward_name` VARCHAR(128) NOT NULL DEFAULT '', `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`id`), UNIQUE KEY `uk_yumi_gc_rank_range` (`activity_id`, `period_type`, `start_rank`, `end_rank`), KEY `idx_yumi_gc_rank_match` (`activity_id`, `period_type`, `start_rank`, `end_rank`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Configurable daily and overall rank reward ranges'; CREATE TABLE IF NOT EXISTS `yumi_gift_challenge_reward_snapshot` ( `id` BIGINT NOT NULL, `activity_id` BIGINT NOT NULL, `resource_group_id` BIGINT NOT NULL, `reward_config_id` BIGINT NOT NULL, `reward_type` VARCHAR(64) NOT NULL, `detail_type` VARCHAR(64) NOT NULL DEFAULT '', `content` TEXT NOT NULL, `quantity` BIGINT NOT NULL, `sort_order` INT NOT NULL DEFAULT 0, `remark` VARCHAR(500) NOT NULL DEFAULT '', `cover` TEXT NOT NULL, `source_url` TEXT NOT NULL, `display_name` VARCHAR(500) NOT NULL DEFAULT '', `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), PRIMARY KEY (`id`), UNIQUE KEY `uk_yumi_gc_snapshot_item` (`activity_id`, `resource_group_id`, `reward_config_id`), KEY `idx_yumi_gc_snapshot_group` (`activity_id`, `resource_group_id`, `sort_order`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Full reward item template frozen when activity is enabled'; CREATE TABLE IF NOT EXISTS `yumi_gift_challenge_gift_ledger` ( `id` BIGINT NOT NULL, `activity_id` BIGINT NOT NULL, `source_event_track_id` VARCHAR(128) NOT NULL, `user_id` BIGINT NOT NULL, `gift_id` BIGINT NOT NULL, `gift_tab` VARCHAR(32) NOT NULL, `amount` DECIMAL(24,2) NOT NULL, `event_time` DATETIME(3) NOT NULL, `stat_date` DATE NOT NULL, `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), PRIMARY KEY (`id`), UNIQUE KEY `uk_yumi_gc_ledger_event` (`activity_id`, `source_event_track_id`), KEY `idx_yumi_gc_ledger_user` (`activity_id`, `user_id`, `event_time`), KEY `idx_yumi_gc_ledger_date` (`activity_id`, `stat_date`, `event_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Idempotent ordinary GOLD gift activity ledger'; CREATE TABLE IF NOT EXISTS `yumi_gift_challenge_user_score` ( `activity_id` BIGINT NOT NULL, `user_id` BIGINT NOT NULL, `score` DECIMAL(24,2) NOT NULL DEFAULT 0.00, `score_reached_time` DATETIME(3) NOT NULL, `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`activity_id`, `user_id`), KEY `idx_yumi_gc_overall_rank` (`activity_id`, `score` DESC, `score_reached_time` ASC, `user_id` ASC) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Materialized overall gift challenge score'; CREATE TABLE IF NOT EXISTS `yumi_gift_challenge_user_daily_score` ( `activity_id` BIGINT NOT NULL, `stat_date` DATE NOT NULL, `user_id` BIGINT NOT NULL, `score` DECIMAL(24,2) NOT NULL DEFAULT 0.00, `score_reached_time` DATETIME(3) NOT NULL, `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`activity_id`, `stat_date`, `user_id`), KEY `idx_yumi_gc_daily_rank` (`activity_id`, `stat_date`, `score` DESC, `score_reached_time` ASC, `user_id` ASC) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Materialized activity-timezone daily gift challenge score'; CREATE TABLE IF NOT EXISTS `yumi_gift_challenge_user_task_daily` ( `id` BIGINT NOT NULL, `activity_id` BIGINT NOT NULL, `stat_date` DATE NOT NULL, `user_id` BIGINT NOT NULL, `task_config_id` BIGINT NOT NULL, `task_code` VARCHAR(64) NOT NULL, `task_type` VARCHAR(32) NOT NULL, `task_title` VARCHAR(128) NOT NULL, `sort_order` TINYINT NOT NULL, `target_value` DECIMAL(24,2) NOT NULL, `progress_value` DECIMAL(24,2) NOT NULL DEFAULT 0.00, `completed_time` DATETIME(3) NULL, `resource_group_id` BIGINT NULL, `business_no` VARCHAR(160) NOT NULL, `claim_request_id` VARCHAR(128) NOT NULL DEFAULT '', `delivery_status` VARCHAR(32) NOT NULL DEFAULT 'NOT_CLAIMED', `retry_count` INT NOT NULL DEFAULT 0, `failure_reason` VARCHAR(500) NOT NULL DEFAULT '', `claimed_time` DATETIME(3) NULL, `deliver_time` DATETIME(3) NULL, `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`id`), UNIQUE KEY `uk_yumi_gc_user_task` (`activity_id`, `stat_date`, `user_id`, `task_code`), UNIQUE KEY `uk_yumi_gc_task_business` (`business_no`), KEY `idx_yumi_gc_user_task_page` (`activity_id`, `stat_date`, `user_id`, `sort_order`), KEY `idx_yumi_gc_task_delivery` (`delivery_status`, `update_time`, `id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Frozen per-user per-day task state and reward owner'; CREATE TABLE IF NOT EXISTS `yumi_gift_challenge_period_settlement` ( `id` BIGINT NOT NULL, `activity_id` BIGINT NOT NULL, `period_type` VARCHAR(16) NOT NULL, `period_key` VARCHAR(16) NOT NULL, `stat_date` DATE NULL, `snapshot_due_time` DATETIME(3) NOT NULL, `status` VARCHAR(32) NOT NULL DEFAULT 'NOT_STARTED', `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`id`), UNIQUE KEY `uk_yumi_gc_period` (`activity_id`, `period_type`, `period_key`), KEY `idx_yumi_gc_period_due` (`status`, `snapshot_due_time`, `id`), KEY `idx_yumi_gc_period_activity` (`activity_id`, `status`, `period_type`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Daily and overall write gates including empty periods'; CREATE TABLE IF NOT EXISTS `yumi_gift_challenge_settlement` ( `id` BIGINT NOT NULL, `activity_id` BIGINT NOT NULL, `period_type` VARCHAR(16) NOT NULL, `period_key` VARCHAR(16) NOT NULL, `stat_date` DATE NULL, `user_id` BIGINT NOT NULL, `rank_no` INT NOT NULL, `score` DECIMAL(24,2) NOT NULL, `rank_reward_id` BIGINT NOT NULL, `resource_group_id` BIGINT NOT NULL, `business_no` VARCHAR(180) NOT NULL, `delivery_status` VARCHAR(32) NOT NULL DEFAULT 'PENDING', `retry_count` INT NOT NULL DEFAULT 0, `failure_reason` VARCHAR(500) NOT NULL DEFAULT '', `deliver_time` DATETIME(3) NULL, `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`id`), UNIQUE KEY `uk_yumi_gc_settle_user` (`activity_id`, `period_type`, `period_key`, `user_id`), UNIQUE KEY `uk_yumi_gc_settle_rank` (`activity_id`, `period_type`, `period_key`, `rank_no`), UNIQUE KEY `uk_yumi_gc_settle_business` (`business_no`), KEY `idx_yumi_gc_settle_status` (`activity_id`, `period_type`, `period_key`, `delivery_status`, `rank_no`), KEY `idx_yumi_gc_settle_recovery` (`delivery_status`, `update_time`, `id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Frozen rank winner parent records'; CREATE TABLE IF NOT EXISTS `yumi_gift_challenge_delivery_item` ( `id` BIGINT NOT NULL, `owner_type` VARCHAR(16) NOT NULL COMMENT 'TASK or SETTLEMENT', `owner_id` BIGINT NOT NULL, `activity_id` BIGINT NOT NULL, `user_id` BIGINT NOT NULL, `reward_config_id` BIGINT NOT NULL, `resource_group_id` BIGINT NOT NULL, `reward_type` VARCHAR(64) NOT NULL, `detail_type` VARCHAR(64) NOT NULL DEFAULT '', `content` TEXT NOT NULL, `quantity` BIGINT NOT NULL, `sort_order` INT NOT NULL DEFAULT 0, `remark` VARCHAR(500) NOT NULL DEFAULT '', `delivery_status` VARCHAR(32) NOT NULL DEFAULT 'PENDING', `retry_count` INT NOT NULL DEFAULT 0, `failure_reason` VARCHAR(500) NOT NULL DEFAULT '', `deliver_time` DATETIME(3) NULL, `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`id`), UNIQUE KEY `uk_yumi_gc_delivery_item` (`owner_type`, `owner_id`, `reward_config_id`), KEY `idx_yumi_gc_delivery_claim` (`owner_type`, `owner_id`, `delivery_status`, `sort_order`, `id`), KEY `idx_yumi_gc_delivery_stale` (`delivery_status`, `update_time`, `id`), KEY `idx_yumi_gc_delivery_activity` (`activity_id`, `delivery_status`, `id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Item-level idempotent frozen reward delivery';