SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci; -- 使用 utf8mb4 连接字符集,保证中文注释、中文名称和 emoji 在导入时不被降级。 CREATE DATABASE IF NOT EXISTS hyapp_game DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE hyapp_game; CREATE TABLE IF NOT EXISTS game_platforms ( app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离', platform_code VARCHAR(64) NOT NULL COMMENT '平台编码', platform_name VARCHAR(128) NOT NULL COMMENT '平台名称', status VARCHAR(32) NOT NULL COMMENT '业务状态', api_base_url VARCHAR(512) NOT NULL DEFAULT '' COMMENT 'API 基准 URL', adapter_type VARCHAR(64) NOT NULL DEFAULT '' COMMENT '适配器类型', callback_secret_ciphertext VARCHAR(1024) NOT NULL DEFAULT '' COMMENT '回调密钥密文', callback_ip_whitelist JSON NULL COMMENT '回调IP白名单', adapter_config JSON NULL COMMENT '适配器配置', sort_order INT NOT NULL DEFAULT 0 COMMENT '排序权重,数值越小越靠前', created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms', updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms', PRIMARY KEY(app_code, platform_code) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='游戏平台表'; CREATE TABLE IF NOT EXISTS game_catalog ( app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离', game_id VARCHAR(96) NOT NULL COMMENT '游戏 ID', platform_code VARCHAR(64) NOT NULL COMMENT '平台编码', provider_game_id VARCHAR(128) NOT NULL COMMENT '提供方游戏 ID', game_name VARCHAR(128) NOT NULL COMMENT '游戏名称', category VARCHAR(64) NOT NULL DEFAULT '' COMMENT '分类', icon_url VARCHAR(512) NOT NULL DEFAULT '' COMMENT '图标 URL', cover_url VARCHAR(512) NOT NULL DEFAULT '' COMMENT '封面 URL', launch_mode VARCHAR(32) NOT NULL DEFAULT 'h5_popup' COMMENT '启动模式', orientation VARCHAR(32) NOT NULL DEFAULT 'portrait' COMMENT '屏幕方向', safe_height INT NOT NULL DEFAULT 0 COMMENT '游戏安全高', min_coin BIGINT NOT NULL DEFAULT 0 COMMENT '最小金币', status VARCHAR(32) NOT NULL COMMENT '业务状态', sort_order INT NOT NULL DEFAULT 0 COMMENT '排序权重,数值越小越靠前', tags JSON NULL COMMENT '标签', created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms', updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms', PRIMARY KEY(app_code, game_id), UNIQUE KEY uk_game_provider(app_code, platform_code, provider_game_id), KEY idx_game_platform_status(app_code, platform_code, status, sort_order) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='游戏目录表'; CREATE TABLE IF NOT EXISTS game_display_rules ( app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离', rule_id VARCHAR(96) NOT NULL COMMENT '规则 ID', game_id VARCHAR(96) NOT NULL COMMENT '游戏 ID', scene VARCHAR(64) NOT NULL COMMENT '场景', region_id BIGINT NOT NULL DEFAULT 0 COMMENT '区域 ID', language VARCHAR(32) NOT NULL DEFAULT '' COMMENT '语言', platform VARCHAR(16) NOT NULL DEFAULT '' COMMENT '平台', visible TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否可见', enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '启用', sort_order INT NOT NULL DEFAULT 0 COMMENT '排序权重,数值越小越靠前', created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms', updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms', PRIMARY KEY(app_code, rule_id), KEY idx_game_display(app_code, scene, region_id, visible, sort_order) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='游戏展示规则表'; CREATE TABLE IF NOT EXISTS game_launch_sessions ( app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离', session_id VARCHAR(96) NOT NULL COMMENT '会话 ID', user_id BIGINT NOT NULL COMMENT '用户 ID', display_user_id VARCHAR(32) NOT NULL COMMENT '展示用户 ID', room_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '房间 ID', region_id BIGINT NOT NULL DEFAULT 0 COMMENT '用户启动游戏时的区域 ID', scene VARCHAR(64) NOT NULL COMMENT '场景', platform_code VARCHAR(64) NOT NULL COMMENT '平台编码', game_id VARCHAR(96) NOT NULL COMMENT '游戏 ID', provider_game_id VARCHAR(128) NOT NULL COMMENT '提供方游戏 ID', launch_token_hash VARCHAR(128) NOT NULL COMMENT '启动令牌哈希值', status VARCHAR(32) NOT NULL COMMENT '业务状态', expires_at_ms BIGINT NOT NULL COMMENT '过期时间,UTC epoch ms', created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms', updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms', PRIMARY KEY(app_code, session_id), KEY idx_game_launch_user(app_code, user_id, created_at_ms), KEY idx_game_launch_recent(app_code, user_id, scene, created_at_ms, game_id), KEY idx_game_launch_token(app_code, launch_token_hash) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='游戏启动会话表'; CREATE TABLE IF NOT EXISTS game_orders ( app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离', order_id VARCHAR(96) NOT NULL COMMENT '订单 ID', platform_code VARCHAR(64) NOT NULL COMMENT '平台编码', provider_order_id VARCHAR(160) NOT NULL COMMENT '提供方订单 ID', provider_round_id VARCHAR(160) NOT NULL DEFAULT '' COMMENT '提供方轮次 ID', game_id VARCHAR(96) NOT NULL COMMENT '游戏 ID', provider_game_id VARCHAR(128) NOT NULL COMMENT '提供方游戏 ID', user_id BIGINT NOT NULL COMMENT '用户 ID', room_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '房间 ID', region_id BIGINT NOT NULL DEFAULT 0 COMMENT '用户启动游戏时的区域 ID', op_type VARCHAR(32) NOT NULL COMMENT 'op类型', coin_amount BIGINT NOT NULL COMMENT '金币数量', status VARCHAR(32) NOT NULL COMMENT '业务状态', wallet_transaction_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '钱包交易 ID', wallet_balance_after BIGINT NOT NULL DEFAULT 0 COMMENT '钱包余额后', request_hash VARCHAR(128) NOT NULL COMMENT '请求哈希值', raw_payload_ref VARCHAR(256) NOT NULL DEFAULT '' COMMENT '原始负载外部引用', failure_code VARCHAR(64) NOT NULL DEFAULT '' COMMENT '失败编码', failure_message VARCHAR(256) NOT NULL DEFAULT '' COMMENT '失败消息', created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms', updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms', PRIMARY KEY(app_code, order_id), UNIQUE KEY uk_game_provider_order(app_code, platform_code, provider_order_id), KEY idx_game_order_user_time(app_code, user_id, created_at_ms), KEY idx_game_order_round(app_code, platform_code, provider_round_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='游戏钱包订单表'; CREATE TABLE IF NOT EXISTS game_dice_matches ( app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离', match_id VARCHAR(96) NOT NULL COMMENT '骰子局 ID', game_id VARCHAR(96) NOT NULL COMMENT '内部游戏 ID', platform_code VARCHAR(64) NOT NULL COMMENT '平台编码快照', provider_game_id VARCHAR(128) NOT NULL COMMENT '提供方游戏 ID 快照', room_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '房间 ID', region_id BIGINT NOT NULL DEFAULT 0 COMMENT '用户区域 ID', min_players INT NOT NULL COMMENT '最少开局人数', max_players INT NOT NULL COMMENT '最多参与人数', current_players INT NOT NULL DEFAULT 0 COMMENT '当前参与人数', stake_coin BIGINT NOT NULL COMMENT '单人下注金币', round_no INT NOT NULL DEFAULT 1 COMMENT '轮次', status VARCHAR(32) NOT NULL COMMENT '局状态', result VARCHAR(64) NOT NULL DEFAULT '' COMMENT '局结果', join_deadline_ms BIGINT NOT NULL DEFAULT 0 COMMENT '加入截止时间,UTC epoch ms', ready_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '匹配完成时间,UTC epoch ms', created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms', updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms', settled_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '结算时间,UTC epoch ms', canceled_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '取消时间,UTC epoch ms', fee_bps INT NOT NULL DEFAULT 500 COMMENT '本局平台抽水万分比快照', pool_bps INT NOT NULL DEFAULT 100 COMMENT '本局奖池入池万分比快照', match_mode VARCHAR(32) NOT NULL DEFAULT '' COMMENT '匹配模式 human/robot', forced_result VARCHAR(32) NOT NULL DEFAULT '' COMMENT '机器人奖池不足时的强制结果', pool_delta_coin BIGINT NOT NULL DEFAULT 0 COMMENT '本局对奖池的净变化', PRIMARY KEY(app_code, match_id), KEY idx_game_dice_room_active(app_code, room_id, status, created_at_ms), KEY idx_game_dice_status_time(app_code, status, updated_at_ms, match_id), KEY idx_game_dice_waiting(app_code, game_id, stake_coin, status, created_at_ms, match_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='骰子游戏局表'; CREATE TABLE IF NOT EXISTS game_dice_participants ( app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离', match_id VARCHAR(96) NOT NULL COMMENT '骰子局 ID', user_id BIGINT NOT NULL COMMENT '用户 ID', participant_type VARCHAR(32) NOT NULL DEFAULT 'user' COMMENT '参与者类型 user/robot', seat_no INT NOT NULL COMMENT '座位号', status VARCHAR(32) NOT NULL COMMENT '参与状态', stake_coin BIGINT NOT NULL COMMENT '下注金币', dice_points_json JSON NULL COMMENT '骰子点数', result VARCHAR(32) NOT NULL DEFAULT '' COMMENT '参与结果', payout_coin BIGINT NOT NULL DEFAULT 0 COMMENT '返奖金币', debit_order_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '下注订单 ID', payout_order_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '派奖订单 ID', refund_order_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '退款订单 ID', balance_after BIGINT NOT NULL DEFAULT 0 COMMENT '最近一次钱包账后余额', joined_at_ms BIGINT NOT NULL COMMENT '加入时间,UTC epoch ms', updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms', PRIMARY KEY(app_code, match_id, user_id), UNIQUE KEY uk_game_dice_seat(app_code, match_id, seat_no), KEY idx_game_dice_participant_user(app_code, user_id, updated_at_ms), KEY idx_game_dice_participant_status(app_code, match_id, status, seat_no) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='骰子游戏参与者表'; -- 骰子旧库已经存在 match/participant 表时,CREATE TABLE 不会补列;这里把 H5 实时流程依赖的阶段、费率、机器人和奖池快照列幂等补齐。 SET @ddl := IF( (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'game_dice_matches' AND COLUMN_NAME = 'ready_at_ms') = 0, 'ALTER TABLE game_dice_matches ADD COLUMN ready_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT ''匹配完成时间,UTC epoch ms'' AFTER join_deadline_ms', 'SELECT 1' ); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl := IF( (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'game_dice_matches' AND COLUMN_NAME = 'canceled_at_ms') = 0, 'ALTER TABLE game_dice_matches ADD COLUMN canceled_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT ''取消时间,UTC epoch ms'' AFTER settled_at_ms', 'SELECT 1' ); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl := IF( (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'game_dice_matches' AND COLUMN_NAME = 'fee_bps') = 0, 'ALTER TABLE game_dice_matches ADD COLUMN fee_bps INT NOT NULL DEFAULT 500 COMMENT ''本局平台抽水万分比快照'' AFTER canceled_at_ms', 'SELECT 1' ); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl := IF( (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'game_dice_matches' AND COLUMN_NAME = 'pool_bps') = 0, 'ALTER TABLE game_dice_matches ADD COLUMN pool_bps INT NOT NULL DEFAULT 100 COMMENT ''本局奖池入池万分比快照'' AFTER fee_bps', 'SELECT 1' ); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl := IF( (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'game_dice_matches' AND COLUMN_NAME = 'match_mode') = 0, 'ALTER TABLE game_dice_matches ADD COLUMN match_mode VARCHAR(32) NOT NULL DEFAULT '''' COMMENT ''匹配模式 human/robot'' AFTER pool_bps', 'SELECT 1' ); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl := IF( (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'game_dice_matches' AND COLUMN_NAME = 'forced_result') = 0, 'ALTER TABLE game_dice_matches ADD COLUMN forced_result VARCHAR(32) NOT NULL DEFAULT '''' COMMENT ''机器人奖池不足时的强制结果'' AFTER match_mode', 'SELECT 1' ); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl := IF( (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'game_dice_matches' AND COLUMN_NAME = 'pool_delta_coin') = 0, 'ALTER TABLE game_dice_matches ADD COLUMN pool_delta_coin BIGINT NOT NULL DEFAULT 0 COMMENT ''本局对奖池的净变化'' AFTER forced_result', 'SELECT 1' ); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- 参与者类型是机器人扩展的事实字段;旧局默认真人,避免历史数据阻塞查询和结算。 SET @ddl := IF( (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'game_dice_participants' AND COLUMN_NAME = 'participant_type') = 0, 'ALTER TABLE game_dice_participants ADD COLUMN participant_type VARCHAR(32) NOT NULL DEFAULT ''user'' COMMENT ''参与者类型 user/robot'' AFTER user_id', 'SELECT 1' ); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- 全服等待队列按 app/game/stake/status 命中;旧库没有这个索引时,高并发匹配会退化成扫描历史局。 SET @ddl := IF( (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'game_dice_matches' AND INDEX_NAME = 'idx_game_dice_waiting') = 0, 'ALTER TABLE game_dice_matches ADD INDEX idx_game_dice_waiting (app_code, game_id, stake_coin, status, created_at_ms, match_id)', 'SELECT 1' ); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl := IF( (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'game_dice_participants' AND INDEX_NAME = 'idx_game_dice_participant_status') = 0, 'ALTER TABLE game_dice_participants ADD INDEX idx_game_dice_participant_status (app_code, match_id, status, seat_no)', 'SELECT 1' ); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; CREATE TABLE IF NOT EXISTS game_self_game_configs ( app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离', game_id VARCHAR(96) NOT NULL COMMENT '自研游戏 ID', status VARCHAR(32) NOT NULL DEFAULT 'active' COMMENT '配置状态', stake_options_json JSON NULL COMMENT '可下注金币档位', fee_bps INT NOT NULL DEFAULT 500 COMMENT '平台抽水万分比', pool_bps INT NOT NULL DEFAULT 100 COMMENT '奖池入池万分比', min_players INT NOT NULL DEFAULT 2 COMMENT '最少开局人数', max_players INT NOT NULL DEFAULT 2 COMMENT '最多参与人数', robot_enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用机器人补位', robot_match_wait_ms BIGINT NOT NULL DEFAULT 3000 COMMENT '等待真人后机器人补位毫秒数', created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms', updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms', PRIMARY KEY(app_code, game_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='自研游戏配置表'; CREATE TABLE IF NOT EXISTS game_self_game_pools ( app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离', game_id VARCHAR(96) NOT NULL COMMENT '自研游戏 ID', balance_coin BIGINT NOT NULL DEFAULT 0 COMMENT '机器人共享奖池余额', created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms', updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms', PRIMARY KEY(app_code, game_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='自研游戏机器人奖池表'; -- 默认骰子配置只在新环境插入一次;后台后续修改必须保留,不用初始化脚本覆盖线上运营参数。 SET @now_ms := CAST(UNIX_TIMESTAMP(CURRENT_TIMESTAMP(3)) * 1000 AS UNSIGNED); INSERT INTO game_self_game_configs ( app_code, game_id, status, stake_options_json, fee_bps, pool_bps, min_players, max_players, robot_enabled, robot_match_wait_ms, created_at_ms, updated_at_ms ) VALUES ( 'lalu', 'dice', 'active', CAST('[{"stake_coin":100,"enabled":true,"sort_order":10},{"stake_coin":500,"enabled":true,"sort_order":20},{"stake_coin":1000,"enabled":true,"sort_order":30},{"stake_coin":8000,"enabled":true,"sort_order":40}]' AS JSON), 500, 100, 2, 2, 1, 3000, @now_ms, @now_ms ) ON DUPLICATE KEY UPDATE updated_at_ms = updated_at_ms; INSERT INTO game_self_game_pools (app_code, game_id, balance_coin, created_at_ms, updated_at_ms) VALUES ('lalu', 'dice', 0, @now_ms, @now_ms) ON DUPLICATE KEY UPDATE updated_at_ms = updated_at_ms; CREATE TABLE IF NOT EXISTS game_self_game_pool_transactions ( app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离', adjustment_id VARCHAR(96) NOT NULL COMMENT '奖池流水 ID', game_id VARCHAR(96) NOT NULL COMMENT '自研游戏 ID', match_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '关联骰子局 ID', user_id BIGINT NOT NULL DEFAULT 0 COMMENT '关联真实用户 ID', direction VARCHAR(16) NOT NULL COMMENT '方向 in/out', amount_coin BIGINT NOT NULL COMMENT '变化金币', reason VARCHAR(128) NOT NULL DEFAULT '' COMMENT '变化原因', balance_after BIGINT NOT NULL COMMENT '变化后奖池余额', created_by BIGINT NOT NULL DEFAULT 0 COMMENT '后台操作者或系统用户', created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms', PRIMARY KEY(app_code, adjustment_id), KEY idx_game_pool_tx_game_time(app_code, game_id, created_at_ms), KEY idx_game_pool_tx_match(app_code, match_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='自研游戏奖池流水表'; CREATE TABLE IF NOT EXISTS game_self_game_robots ( app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离', game_id VARCHAR(96) NOT NULL COMMENT '自研游戏 ID', user_id BIGINT NOT NULL COMMENT '真实 App 机器人用户 ID', status VARCHAR(32) NOT NULL DEFAULT 'active' COMMENT '机器人状态', created_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '创建管理员 ID', created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms', updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms', PRIMARY KEY(app_code, game_id, user_id), KEY idx_game_robot_status(app_code, game_id, status, updated_at_ms, user_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='自研游戏机器人登记表'; CREATE TABLE IF NOT EXISTS game_callback_logs ( app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离', callback_id VARCHAR(96) NOT NULL COMMENT '回调 ID', platform_code VARCHAR(64) NOT NULL COMMENT '平台编码', operation VARCHAR(64) NOT NULL COMMENT '操作', request_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '链路请求 ID,用于排查问题', provider_request_id VARCHAR(160) NOT NULL DEFAULT '' COMMENT '提供方请求 ID', signature_valid TINYINT(1) NOT NULL DEFAULT 0 COMMENT '签名有效', request_hash VARCHAR(128) NOT NULL COMMENT '请求哈希值', response_code VARCHAR(64) NOT NULL DEFAULT '' COMMENT '响应编码', response_body_hash VARCHAR(128) NOT NULL DEFAULT '' COMMENT '响应正文哈希值', status VARCHAR(32) NOT NULL COMMENT '业务状态', created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms', PRIMARY KEY(app_code, callback_id), KEY idx_game_callback_platform_time(app_code, platform_code, created_at_ms) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='游戏回调日志表'; CREATE TABLE IF NOT EXISTS game_repair_orders ( app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离', repair_id VARCHAR(96) NOT NULL COMMENT '修复 ID', platform_code VARCHAR(64) NOT NULL COMMENT '平台编码', provider_order_id VARCHAR(160) NOT NULL COMMENT '提供方订单 ID', reason VARCHAR(128) NOT NULL COMMENT '原因', status VARCHAR(32) NOT NULL COMMENT '业务状态', operator_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '操作管理员 ID', attempts INT NOT NULL DEFAULT 0 COMMENT '尝试次数', next_run_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '下一个运行时间,UTC epoch ms', last_error_code VARCHAR(64) NOT NULL DEFAULT '' COMMENT '最后错误编码', created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms', updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms', PRIMARY KEY(app_code, repair_id), UNIQUE KEY uk_game_repair_provider_order(app_code, platform_code, provider_order_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='游戏修复订单表'; CREATE TABLE IF NOT EXISTS game_level_event_outbox ( app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离', event_id VARCHAR(160) NOT NULL COMMENT '事件幂等 ID', order_id VARCHAR(96) NOT NULL COMMENT '订单 ID', user_id BIGINT NOT NULL COMMENT '用户 ID', game_id VARCHAR(96) NOT NULL COMMENT '游戏 ID', provider_order_id VARCHAR(160) NOT NULL COMMENT '提供方订单 ID', provider_round_id VARCHAR(160) NOT NULL DEFAULT '' COMMENT '提供方轮次 ID', coin_amount BIGINT NOT NULL COMMENT '金币数量', wallet_transaction_id VARCHAR(96) NOT NULL COMMENT '钱包交易 ID', payload_json JSON NULL COMMENT '业务负载 JSON 快照', status VARCHAR(32) NOT NULL COMMENT '业务状态', attempt_count INT NOT NULL DEFAULT 0 COMMENT '尝试次数', next_retry_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '下一次重试时间,UTC epoch ms', locked_by VARCHAR(128) NOT NULL DEFAULT '' COMMENT '当前锁定 worker', locked_until_ms BIGINT NOT NULL DEFAULT 0 COMMENT '锁定截止时间,UTC epoch ms', failure_reason VARCHAR(255) NOT NULL DEFAULT '' COMMENT '失败原因', occurred_at_ms BIGINT NOT NULL COMMENT '业务发生时间,UTC epoch ms', created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms', updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms', PRIMARY KEY(app_code, event_id), UNIQUE KEY uk_game_level_event_order(app_code, order_id), KEY idx_game_level_event_pending(app_code, status, next_retry_at_ms, created_at_ms), KEY idx_game_level_event_claim(app_code, status, locked_until_ms, next_retry_at_ms, created_at_ms, event_id), KEY idx_game_level_event_claim_order(app_code, status, locked_until_ms, created_at_ms, event_id, next_retry_at_ms), KEY idx_game_level_event_retention(app_code, status, updated_at_ms, event_id), KEY idx_game_level_event_user(app_code, user_id, created_at_ms) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='游戏等级事件 outbox 表'; CREATE TABLE IF NOT EXISTS game_outbox ( app_code VARCHAR(32) NOT NULL COMMENT '应用编码,用于多租户隔离', event_id VARCHAR(160) NOT NULL COMMENT '事件幂等 ID', event_type VARCHAR(64) NOT NULL COMMENT '事件类型', order_id VARCHAR(96) NOT NULL COMMENT '订单 ID', user_id BIGINT NOT NULL COMMENT '用户 ID', platform_code VARCHAR(64) NOT NULL COMMENT '平台编码', game_id VARCHAR(96) NOT NULL COMMENT '游戏 ID', op_type VARCHAR(32) NOT NULL COMMENT '游戏改账方向', coin_amount BIGINT NOT NULL COMMENT '金币数量', payload_json JSON NOT NULL COMMENT '业务负载 JSON 快照', status VARCHAR(32) NOT NULL COMMENT '业务状态', worker_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT 'MQ 投递 worker ID', lock_until_ms BIGINT NOT NULL DEFAULT 0 COMMENT 'MQ 投递锁过期时间,UTC epoch ms', retry_count INT NOT NULL DEFAULT 0 COMMENT '重试次数', next_retry_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '下一次 MQ 投递重试时间,UTC epoch ms', last_error VARCHAR(512) NOT NULL DEFAULT '' COMMENT '最后一次失败原因', created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms', updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms', PRIMARY KEY(app_code, event_id), KEY idx_game_outbox_status_created(app_code, status, next_retry_at_ms, created_at_ms, event_id), KEY idx_game_outbox_lock(app_code, status, lock_until_ms, created_at_ms, event_id), KEY idx_game_outbox_retention(app_code, status, updated_at_ms, event_id), KEY idx_game_outbox_order(app_code, order_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='游戏统计事件 outbox 表';