diff --git a/game-cloud/game-module-ad/game-module-ad-server/src/main/resources/db/migration/V6.0.0__create_game_ad.sql b/game-cloud/game-module-ad/game-module-ad-server/src/main/resources/db/migration/V6.0.0__create_game_ad.sql deleted file mode 100644 index c97e1489..00000000 --- a/game-cloud/game-module-ad/game-module-ad-server/src/main/resources/db/migration/V6.0.0__create_game_ad.sql +++ /dev/null @@ -1,77 +0,0 @@ --- ============================================================================= --- 契约 #2 DB 迁移 | 模块:ad(game-module-ad,Wave2 变现域「广告引擎」)| owner:WS5 --- 文件:V6.0.0__create_game_ad.sql(Flyway,只新增;已合入禁止修改,回滚写新补偿迁移) --- 内容:ad 模块核心表 —— 广告位配置 game_ad_slot(对齐契约#7)+ 广告收入台账 game_ad_revenue(ad↔trade seam 数据源) --- 职责(架构 Doc B):联盟接入/广告位 AI 植入/曝光计费/eCPM/归因;不做结算提现(归 trade)。MVP provider 默认 mock。 --- 脊柱(钱财闭环上游):SDK 拉广告位 → 有效曝光/激励完成计费上报(幂等) → mock eCPM 计收入 → 落 game_ad_revenue(settle_status=0) --- → trade 经 AdRevenueApi.getUnsettledRevenue 拉取做 T+1 分账 → markSettled 回标 settle_status=1(seam 详见 ad.yaml x-feign-contracts) --- 计费 vs 分析埋点:本模块台账=计费级(决定收入),区别于 telemetry(#5 ad_impression/ad_reward) 分析埋点(仅统计),二者并存口径不同 --- 约定:InnoDB + utf8mb4;显式列;含 Yudao 审计列 creator/create_time/updater/update_time/deleted + tenant_id; --- 金额一律「分」(BIGINT),禁浮点;状态机用 tinyint,非法流转由 Service 校验,DO 层不承载;中文列注释;关键查询建索引、禁裸 select*。 --- 错误码段:ad = 1-111-***-*** --- ============================================================================= - --- ----------------------------------------------------------------------------- --- 表:game_ad_slot —— 广告位配置表(字段严格对齐契约#7 ad-slot.schema.json) --- 用途:admin CRUD 维护;SDK Plugin.Ad 拉 enabled=true 广告位渲染(/app-api/ad/slot/list-enabled) --- Provider SPI:provider=mock 走桩(MVP 默认);csj 穿山甲 / gdt 优量汇 走审核闸门后由人填 provider_slot_id 注入 --- 唯一键:slot_id 业务唯一(uk_slot),埋点 ad_impression.slot_id 与计费上报均引用此逻辑 ID --- compliance(未成年人保护)拆为显式列 block_minor / max_per_session,不用 JSON 整块存(便于查询与计费限流) --- ----------------------------------------------------------------------------- -CREATE TABLE `game_ad_slot` ( - `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '广告位主键 ID', - `slot_id` VARCHAR(64) NOT NULL COMMENT '广告位逻辑 ID(平台内唯一,对齐契约#7 slotId;埋点/计费上报均引用)', - `type` VARCHAR(16) NOT NULL DEFAULT 'rewarded' COMMENT '广告形式(对齐#7 type):rewarded 激励视频/interstitial 插屏/banner 横幅', - `provider` VARCHAR(16) NOT NULL DEFAULT 'mock' COMMENT '联盟(对齐#7 provider,SPI AdProvider):csj 穿山甲/gdt 优量汇/mock 桩(MVP 默认)', - `placement` VARCHAR(16) NOT NULL DEFAULT 'game_end' COMMENT '触发场景(对齐#7 placement):game_end 本局结束/pause 暂停/feed 游戏流间隙', - `provider_slot_id` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '联盟侧真实广告位 ID(对齐#7 providerSlotId;provider!=mock 时由人提供——审核闸门后注入;不下发前端明文)', - `ecpm_floor` BIGINT NOT NULL DEFAULT 0 COMMENT 'eCPM 底价(单位:分,对齐#7 ecpmFloor);低于此不展示;mock 计费亦用此算单次收入', - `enabled` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否启用(对齐#7 enabled):0停用 1启用;SDK 只拉启用项', - `block_minor` BIT(1) NOT NULL DEFAULT b'1' COMMENT '合规:识别为未成年则不展示/不计费(对齐#7 compliance.blockMinor,默认 1=拦截)', - `max_per_session` INT NOT NULL DEFAULT 0 COMMENT '合规:单会话最大展示次数(对齐#7 compliance.maxPerSession;0=不限;计费上报按此限流)', - `creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者(Yudao 审计列)', - `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updater` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者', - `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除:0未删 1已删', - `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID(Yudao 多租户兼容,MVP 单租户=0)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_slot` (`slot_id`, `deleted`, `tenant_id`) COMMENT '广告位逻辑 ID 业务唯一键(含 deleted/tenant_id 适配 Yudao 逻辑删除+多租户,避免软删后无法复用 slot_id)', - KEY `idx_enabled` (`enabled`, `placement`) COMMENT 'SDK 按启用+场景拉广告位(list-enabled)', - KEY `idx_provider` (`provider`, `type`) COMMENT '管理端按联盟+形式分页/筛选' -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '广告位配置表(对齐契约#7;admin CRUD + SDK 拉取)'; - --- ----------------------------------------------------------------------------- --- 表:game_ad_revenue —— 广告收入台账(有效曝光/激励计费产出;ad↔trade seam 的数据源) --- 用途:计费上报(impression/reward)按 mock eCPM 算收入落账;trade 按 settle_status=0 拉取做 T+1 分账 --- 收入归因:creator_user_id = 由 game_id 反查 project.game_project.creator_user_id(收入归到游戏作者,trade 按此聚合分账) --- 幂等核心:uk_trace=(trace_id,event_type),同 (trace_id,event_type) 重复上报只计一条(计费幂等);同一 trace_id 的 impression 与 reward 各落一条、互不覆盖(防 reward 被 impression 静默吞掉=丢账) --- 收入口径(避免同一次展示重复计收入):type=rewarded 收入计在 reward(impression 若上报则 revenue_amount=0);type=interstitial/banner 收入计在 impression。event_type 仅区分计费事件,不对同一次展示重复计收入 --- 结算状态机 settle_status:0未结算 → 1已结算(trade 分账入账成功后经 AdRevenueApi.markSettled 回标,幂等;非法回退由 Service 拒绝) --- 扫描入口:trade 的 getUnsettledRevenue(statDate) 按 (settle_status=0, stat_date) 命中 idx_settle_date 扫描,禁裸 select* --- 金额单位:ecpm / revenue_amount 一律「分」(BIGINT),禁浮点 --- ----------------------------------------------------------------------------- -CREATE TABLE `game_ad_revenue` ( - `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '广告收入台账记录 ID(= trade 侧 game_trade_income.source_ref 对账锚点)', - `slot_id` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '广告位逻辑 ID(= game_ad_slot.slot_id)', - `game_id` BIGINT NOT NULL COMMENT '产生收入的游戏 ID(project.game_project.id)', - `creator_user_id` BIGINT NOT NULL COMMENT '收入归因到的创作者用户 ID(由 game_id 反查 game_project.creator_user_id;trade 按此聚合分账)', - `event_type` TINYINT NOT NULL DEFAULT 1 COMMENT '计费事件类型:1 impression 有效曝光 / 2 reward 激励完成', - `provider` VARCHAR(16) NOT NULL DEFAULT 'mock' COMMENT '产生收入的联盟:csj/gdt/mock(与广告位 provider 一致)', - `ecpm` BIGINT NOT NULL DEFAULT 0 COMMENT 'eCPM(单位:分;mock 取广告位 ecpm_floor)', - `revenue_amount` BIGINT NOT NULL DEFAULT 0 COMMENT '本条广告收入(单位:分,BIGINT;金额一律用分禁浮点;mock=ecpm/1000 向下取整)', - `trace_id` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '全链路追踪 ID(与 event_type 组成计费幂等键 uk_trace);透传到 trade.trace_id 供端到端对账', - `settle_status` TINYINT NOT NULL DEFAULT 0 COMMENT '结算状态机:0未结算 1已结算(trade 分账后经 markSettled 回标 1;非法回退由 Service 拒绝)', - `stat_date` DATE NOT NULL COMMENT '归集日(yyyy-MM-dd,按日归集供 trade 按日扫未结算做 T+1 分账)', - `creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者(Yudao 审计列;计费上报为 system/上报方)', - `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间(计费入账时间)', - `updater` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者(trade 回标时为结算 job)', - `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除:0未删 1已删', - `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID(Yudao 多租户兼容,MVP 单租户=0)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_trace` (`trace_id`, `event_type`, `tenant_id`) COMMENT '计费幂等键:(trace_id+event_type) 唯一——同 (trace_id,event_type) 重复上报只落一条(计费幂等);同一 trace_id 的 impression 与 reward 各计一条、不互相覆盖(防 reward 被 impression 静默吞掉)', - KEY `idx_settle_date` (`settle_status`, `stat_date`) COMMENT 'trade 扫未结算做 T+1 分账(getUnsettledRevenue 按 settle_status=0 + stat_date 扫描)', - KEY `idx_creator_date` (`creator_user_id`, `stat_date`) COMMENT '按创作者+归集日聚合分账/对账', - KEY `idx_game` (`game_id`, `stat_date`) COMMENT '按游戏查收入(归因/计费对账)' -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '广告收入台账表(计费产出;ad↔trade seam 数据源,settle_status 供 trade 分账)'; diff --git a/game-cloud/game-module-compliance/game-module-compliance-server/src/main/resources/db/migration/V9.0.0__create_game_compliance.sql b/game-cloud/game-module-compliance/game-module-compliance-server/src/main/resources/db/migration/V9.0.0__create_game_compliance.sql deleted file mode 100644 index 696a49dd..00000000 --- a/game-cloud/game-module-compliance/game-module-compliance-server/src/main/resources/db/migration/V9.0.0__create_game_compliance.sql +++ /dev/null @@ -1,84 +0,0 @@ --- ============================================================================= --- 契约 #2 DB 迁移 | 模块:compliance(game-module-compliance,Wave3 合规域「锁风门 Gate」)| owner:Wave3 compliance 子 agent --- 文件:V9.0.0__create_game_compliance.sql(Flyway,只新增;已合入禁止修改,回滚写新补偿迁移 V9.0.1 DROP TABLE) --- 内容:compliance 模块三张表 —— 锁风门评估台账 game_compliance_gate_result + 内容分级 game_content_rating + 封禁台账 game_user_ban --- 职责(架构 Doc B + D2 范围铁律):只做 Gate(聚合风格/IP 原子→verdict + 内容分级 + 封禁台账); --- 【明确不建】审核状态机表 / audit_record —— 审核状态机权威归 project(game_review_record),compliance 绝不重写。 --- 锁风门 seam(R1):project.submitPublish 同进程调 ComplianceGateApi.evaluate → 聚合裁决落 game_compliance_gate_result + 分级落 game_content_rating --- → 返回 verdict 供 project 据此置 admitted(block→admitted=false 不抛异常)。 --- 封禁联动(R3 状态分支):写 game_user_ban 台账(主操作恒执行);下架仅当 project 状态==PUBLISHED 时才调 project reviewProject(3); --- 非 PUBLISHED 只记封禁不调状态机。【本波说明】ProjectApi 暂无 reviewProject seam,下架联动标 TODO 留 Phase C 主 agent 收口,本波仅写台账。 --- 降权出流屏蔽:P1 本波不生效(R5,不建 FeedDownweightApi 孤儿 seam)。 --- 约定:InnoDB + utf8mb4;显式列;含 Yudao 审计列 creator/create_time/updater/update_time/deleted + tenant_id; --- 状态机用 tinyint,非法流转由 Service 校验,DO 层不承载;中文列注释;关键查询建索引、禁裸 select*。 --- 错误码段:compliance = 1-109-***-*** --- ============================================================================= - --- ----------------------------------------------------------------------------- --- 表:game_compliance_gate_result —— 锁风门评估台账(每次 publish 评估各落一条,审计/溯源用) --- 用途:project.publish 注入 evaluate 时落聚合裁决 + 各原子明细 JSON;admin 复核与合规溯源据此查 --- 写口径:非幂等(每次评估各落一条审计记录,不去重);verdict 为聚合结果 max(各原子) --- ----------------------------------------------------------------------------- -CREATE TABLE `game_compliance_gate_result` ( - `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '锁风门评估记录 ID', - `game_id` BIGINT NOT NULL COMMENT '评估的游戏 ID(project.game_project.id)', - `version_id` BIGINT NOT NULL DEFAULT 0 COMMENT '评估的版本 ID(待发布版本;无版本时为 0)', - `verdict` VARCHAR(16) NOT NULL DEFAULT 'pass' COMMENT '聚合裁决:pass 通过/review 需人工复核/block 拦截(= max(各原子))', - `rating` VARCHAR(16) NOT NULL DEFAULT '' COMMENT '本次评估落定的内容分级:all/8+/12+/16+(可空)', - `details` VARCHAR(2048) NOT NULL DEFAULT '' COMMENT '各合规原子明细 JSON([{atom,verdict,reason}],便于复核溯源)', - `trace_id` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '全链路追踪 ID(与 publish 链路对账)', - `creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者(Yudao 审计列;锁风门评估为 system/发布发起方)', - `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间(评估时间)', - `updater` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者', - `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除:0未删 1已删', - `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID(Yudao 多租户兼容,MVP 单租户=0)', - PRIMARY KEY (`id`), - KEY `idx_game_version` (`game_id`, `version_id`) COMMENT '按游戏+版本查最近一次锁风门评估(复核/溯源)' -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '锁风门评估台账(每次 publish 评估落一条,聚合裁决+原子明细;审计/溯源)'; - --- ----------------------------------------------------------------------------- --- 表:game_content_rating —— 内容分级表(按游戏+版本唯一;评估时落、admin 复核可改) --- 用途:/app-api/compliance/rating/get 读分级;分级写入仅由 Gate evaluate 落定 + admin 复核产生 --- 唯一键:(game_id,version_id) 业务唯一(含 deleted/tenant_id 适配逻辑删+多租户),同游戏同版本只存一条最新分级 --- ----------------------------------------------------------------------------- -CREATE TABLE `game_content_rating` ( - `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '内容分级记录 ID', - `game_id` BIGINT NOT NULL COMMENT '游戏 ID(project.game_project.id)', - `version_id` BIGINT NOT NULL DEFAULT 0 COMMENT '版本 ID(无版本时为 0)', - `rating` VARCHAR(16) NOT NULL DEFAULT 'all' COMMENT '内容分级:all 全年龄/8+/12+/16+', - `rated_by` VARCHAR(32) NOT NULL DEFAULT 'gate' COMMENT '分级来源:gate 锁风门自动/admin 人工复核', - `creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者(Yudao 审计列)', - `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updater` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者(admin 复核改分级时记录)', - `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除:0未删 1已删', - `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID(Yudao 多租户兼容,MVP 单租户=0)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_game_version` (`game_id`, `version_id`, `deleted`, `tenant_id`) COMMENT '游戏+版本分级业务唯一键(含 deleted/tenant_id 适配逻辑删+多租户)' -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '内容分级表(评估落定+admin 复核;/app-api 只读取)'; - --- ----------------------------------------------------------------------------- --- 表:game_user_ban —— 封禁台账(封禁/降权的权威台账;主操作恒执行) --- 用途:admin 封禁游戏/用户落台账(恒执行);R3 下架联动仅当游戏==PUBLISHED 时才调 project 状态机(本波标 TODO); --- R5 降权出流屏蔽 P1 本波不生效(不建 feed seam) --- 唯一键:(target_type,target_id,status) 生效中唯一(status=1 生效,含 deleted/tenant_id),同目标不可重复生效封禁;解封后(status=0)可再次封禁 --- 状态机 status:1 生效 → 0 已解封(解封由 admin 触发,Service 校验合法流转) --- ----------------------------------------------------------------------------- -CREATE TABLE `game_user_ban` ( - `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '封禁台账记录 ID', - `target_type` TINYINT NOT NULL COMMENT '封禁目标类型:1 游戏 / 2 用户', - `target_id` BIGINT NOT NULL COMMENT '封禁目标 ID(游戏=game_id / 用户=user_id)', - `ban_type` TINYINT NOT NULL DEFAULT 1 COMMENT '处置类型:1 封禁(下架/禁用)/ 2 降权(出流屏蔽,P1 本波不生效)', - `status` TINYINT NOT NULL DEFAULT 1 COMMENT '封禁状态机:1 生效 / 0 已解封(合法流转由 Service 校验)', - `reason` VARCHAR(512) NOT NULL DEFAULT '' COMMENT '封禁/降权原因(合规处置说明)', - `creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者(Yudao 审计列;封禁操作的 admin userId)', - `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间(封禁时间)', - `updater` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者(解封操作的 admin userId)', - `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除:0未删 1已删', - `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID(Yudao 多租户兼容,MVP 单租户=0)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_target_active` (`target_type`, `target_id`, `status`, `deleted`, `tenant_id`) COMMENT '生效中封禁业务唯一键:同目标 status=1 不可重复(含 deleted/tenant_id 适配逻辑删+多租户)', - KEY `idx_type_status` (`target_type`, `status`) COMMENT 'admin 按目标类型+状态分页查封禁台账' -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '封禁台账表(封禁/降权权威台账;主操作恒执行,下架联动按 project 状态分支)'; diff --git a/game-cloud/game-module-studio/game-module-studio-server/src/main/resources/db/migration/V18.0.0__create_game_source_project.sql b/game-cloud/game-module-studio/game-module-studio-server/src/main/resources/db/migration/V18.0.0__create_game_source_project.sql deleted file mode 100644 index e2f9e267..00000000 --- a/game-cloud/game-module-studio/game-module-studio-server/src/main/resources/db/migration/V18.0.0__create_game_source_project.sql +++ /dev/null @@ -1,49 +0,0 @@ --- ============================================================================= --- 契约 #2 DB 迁移 | 模块:studio(game-module-studio)| owner:后端线(6c6g 编辑 / mini-desktop 验迁移) --- 文件:V18.0.0__create_game_source_project.sql(Flyway,只新增;接 V17.0.0 之后; --- 已合入禁止修改,回滚写新补偿迁移 V18.0.1 DROP TABLE,遵 V2.0.0/V17 头注铁律) --- 背书:HJ 固定架构+SAA agentic studio execution §5.2(2026-06-17)——「源项目存储=独立 game_source_project 表,勿塞 game_version」。 --- 内容:新增源项目工件表 game_source_project —— 生成主线「改源不改打包产物」基座的源侧存储面(与 GamePackage 产物面解耦)。 --- 范式(生命周期项目模型):游戏 = 长生命周期源项目(LLM as 工作室);本表存「可维护的结构化源项目工件」 --- (SourceProject schema = contracts/agent-loop/source-project.schema.json);构建产物(bundle/manifest)仍存 --- game_version + game_runtime_package(GamePackage 产物 schema 不变)。 --- 边界纪律: --- - 源/产物物理解耦:源项目存本表(additive 新存储面),打包产物存 game_version(既冻 GamePackage schema 不变);勿把源字段塞进 game_version。 --- - 版本产物权威仍归 project(game_version);本表 version_id 仅持引用(构建成功建包后回填),不在本模块建版本表。 --- - 事务边界(化解孤儿,execution §5.2):源落库(status=0) → 触发确定性构建 → 成功建 preview package 回填 version_id+status=1; --- 失败 status=2(孤儿)、不建包、不动 currentVersion。源落库与建包非同一大事务(构建数十秒级,长事务=连接池杀手),用 status 机器态串联。 --- - modify「改源不改产物」:base_version_id 记血缘(create 时 NULL);modify 产新源行 → 新预览版,不动 currentVersion、不自动入 feed,走发布审核。 --- 约定:InnoDB + utf8mb4;显式列;含 Yudao 审计列 creator/create_time/updater/update_time/deleted + tenant_id; --- 状态机用 tinyint,非法流转由 Service 校验,DO 层不承载;中文列注释;关键查询建索引、禁裸 select*。 --- 错误码段:studio = 1-112-***-***(本迁移不引入新错误码)。 --- ============================================================================= - --- ----------------------------------------------------------------------------- --- 表:game_source_project —— 游戏源项目工件表(改源不改产物的源侧存储面) --- 用途:studio 工作室编排(create/modify/extend)产出的结构化源项目工件落库;构建从源重新产出字节等价 bundle(可寻址/幂等/可复现)。 --- 可寻址/幂等:source_hash = 源规范化 sha256(= SourceProject.sourceHash);按 game_id 查历史、按 version_id 反查源、按 source_hash 去重。 --- 源态 status:0 草稿 → 1 已构建(建包回填 version_id) / 2 孤儿(构建失败,不建包) / 3 已发布。 --- M0 存储:source_json 走 DB(LONGTEXT),大资产经 ref 外置;切对象存储后改用 source_url(与 source_json 二选一)。 --- ----------------------------------------------------------------------------- -CREATE TABLE `game_source_project` ( - `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '源项目工件 ID', - `game_id` BIGINT NOT NULL COMMENT '所属游戏 ID(project.game_project.id)', - `version_id` BIGINT NULL DEFAULT NULL COMMENT '关联产物版本 ID(project.game_version.id);构建成功建包后回填,失败留 NULL=孤儿', - `source_json` LONGTEXT NULL COMMENT '源项目工件 JSON(SourceProject schema;M0 走 DB,大资产经 ref 外置)', - `source_url` VARCHAR(512) NOT NULL DEFAULT '' COMMENT '源项目对象存储 URL(切对象存储后用,与 source_json 二选一)', - `source_hash` CHAR(64) NOT NULL DEFAULT '' COMMENT '源规范化 sha256(可寻址/幂等键;= SourceProject.sourceHash)', - `schema_version` VARCHAR(16) NOT NULL DEFAULT '1.0' COMMENT '源项目契约版本(独立于 GamePackage 版本)', - `build_profile` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '构建画像(目标引擎/优化档;= buildProfile,影响 buildInputHash)', - `status` TINYINT NOT NULL DEFAULT 0 COMMENT '源态:0草稿 1已构建 2孤儿(构建失败) 3已发布(Service 校验流转)', - `base_version_id` BIGINT NULL DEFAULT NULL COMMENT 'modify 血缘:本源派生自的 base 版本 ID(create 时 NULL)', - `creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者(Yudao 审计列)', - `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updater` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者', - `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除:0未删 1已删', - `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID(Yudao 多租户兼容,MVP 单租户=0)', - PRIMARY KEY (`id`), - KEY `idx_game` (`game_id`, `id`) COMMENT '按游戏查源项目历史(按 id 倒序)', - KEY `idx_version` (`version_id`) COMMENT '按产物版本反查源', - KEY `idx_source_hash` (`source_hash`) COMMENT '可寻址/幂等去重' -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '游戏源项目工件表(改源不改产物;与 game_version 产物面解耦)'; diff --git a/game-cloud/game-module-studio/game-module-studio-server/src/main/resources/db/migration/V8.0.0__create_game_studio.sql b/game-cloud/game-module-studio/game-module-studio-server/src/main/resources/db/migration/V8.0.0__create_game_studio.sql deleted file mode 100644 index 9e2f2e0b..00000000 --- a/game-cloud/game-module-studio/game-module-studio-server/src/main/resources/db/migration/V8.0.0__create_game_studio.sql +++ /dev/null @@ -1,92 +0,0 @@ --- ============================================================================= --- 契约 #2 DB 迁移 | 模块:studio(game-module-studio,Wave3 创作主链路最小版)| owner:studio 路 --- 文件:V8.0.0__create_game_studio.sql(Flyway,只新增;已合入禁止修改,回滚写新补偿迁移 V8.0.1 DROP TABLE) --- 内容:studio 模块核心表 —— 创作会话 game_studio_session + 创作任务链 game_studio_taskchain + 资产槽位 game_studio_asset --- 职责(架构 Doc B §71-76):有状态创作工作台后端。编排「建草稿(委托 project createProject)→一句话生成(委托 aigc) --- →进度轮询→重生成→模板应用」。不跑 LLM(委托 aigc)、不持久化项目版本(交 project)、不做锁风裁决(调 compliance)。 --- 边界纪律: --- - 项目/版本权威归 project(game_project / game_version);studio 仅持 game_id/version_id 引用,不在本模块建版本表。 --- - 生成任务权威归 aigc(game_aigc_task);studio 任务链仅持 aigc_task_id 引用 + 自身链态,不在本模块重建生成状态机。 --- - attachments 本波仅持久化(R7),不透传 aigc(aigc reqDTO 无 attachments 字段)。 --- - MVP 进度推送走轮询(D4),非 MQ/SSE。 --- 约定:InnoDB + utf8mb4;显式列;含 Yudao 审计列 creator/create_time/updater/update_time/deleted + tenant_id; --- 状态机用 tinyint,非法流转由 Service 校验,DO 层不承载;中文列注释;关键查询建索引、禁裸 select*。 --- 错误码段:studio = 1-112-***-*** --- ============================================================================= - --- ----------------------------------------------------------------------------- --- 表:game_studio_session —— 创作会话表(有状态创作工作台主记录,对齐 P-CRT-10 进工作坊) --- 用途:创作者进工作坊 upsert 一条会话,承载草稿入参(title/prompt/templateId/attachments)+ 移交后的 game_id。 --- 移交:createDraft 调 project ProjectApi.createProject 拿 gameId 回写本表 game_id(草稿移交 project,P-TPL-03)。 --- attachments:JSON 持久化(本波仅持久化不透传 aigc,R7)。 --- 状态机 status:0 草稿 → 1 生成中 → 2 完成 / 3 失败(StudioSessionStatusEnum;由 generate/getTask 透传 aigc 终态映射)。 --- ----------------------------------------------------------------------------- -CREATE TABLE `game_studio_session` ( - `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '创作会话 ID', - `creator_user_id` BIGINT NOT NULL COMMENT '创作者用户 ID(业务字段;DataPermission:创作者只见自己会话。区别于审计列 creator)', - `game_id` BIGINT NULL DEFAULT NULL COMMENT '移交后的游戏 ID(project.game_project.id);createDraft 调 createProject 后回写', - `template_id` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '玩法模板 ID(透传 aigc,如 dodge/runner/clicker/puzzle/shooter)', - `title` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '作品标题(建草稿入参,透传 project createProject)', - `prompt` VARCHAR(1000) NOT NULL DEFAULT '' COMMENT '一句话自然语言 Prompt(透传 aigc submitGenerate)', - `attachments` JSON NULL DEFAULT NULL COMMENT '附件上下文(P-CRT-04,JSON 数组);本波仅持久化,P1 透传 aigc', - `status` TINYINT NOT NULL DEFAULT 0 COMMENT '会话状态机:0草稿 1生成中 2完成 3失败(StudioSessionStatusEnum;Service 校验流转)', - `creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者(Yudao 审计列)', - `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updater` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者', - `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除:0未删 1已删', - `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID(Yudao 多租户兼容,MVP 单租户=0)', - PRIMARY KEY (`id`), - KEY `idx_creator` (`creator_user_id`, `id`) COMMENT '创作者「我的创作会话」列表(DataPermission 边界 + 按 id 倒序)', - KEY `idx_game` (`game_id`) COMMENT '按移交后的游戏 ID 反查会话' -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '创作会话表(有状态创作工作台主记录;草稿入参 + 移交 game_id)'; - --- ----------------------------------------------------------------------------- --- 表:game_studio_taskchain —— 创作任务链表(线性单步编排,对齐 P-CRT-01/09 一句话生成 + 重生成血缘) --- 用途:generate 时落一条任务链(status=1),回填 aigc_task_id;getTask 轮询透传 aigc 进度/状态映射链态。 --- 引用边界:aigc_task_id 引用 aigc.game_aigc_task.id(生成权威归 aigc);version_id 引用 project.game_version.id --- (aigc succeeded 后回填,版本权威归 project);本表只持引用 + 自身链态,不重建生成状态机。 --- 重生成血缘:retry_of 指向原任务链 id(P-CRT-09);regenerate 新建一条 retry_of=原 id 的链。 --- 链态 status:0 初始 → 1 生成中 → 2 完成(回填 version_id) / 3 失败(透传 aigc failed/timed_out)。 --- ----------------------------------------------------------------------------- -CREATE TABLE `game_studio_taskchain` ( - `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '创作任务链 ID', - `session_id` BIGINT NOT NULL COMMENT '所属创作会话 ID(= game_studio_session.id)', - `creator_user_id` BIGINT NOT NULL COMMENT '创作者用户 ID(DataPermission 边界,归属校验用)', - `aigc_task_id` BIGINT NULL DEFAULT NULL COMMENT '委托的 aigc 生成任务 ID(= aigc.game_aigc_task.id);generate 后回填,轮询据此查 aigc', - `game_id` BIGINT NULL DEFAULT NULL COMMENT '关联游戏 ID(project.game_project.id,透传 aigc 用)', - `version_id` BIGINT NULL DEFAULT NULL COMMENT '产物版本 ID(project.game_version.id);aigc succeeded 后由 getTask 回填', - `status` TINYINT NOT NULL DEFAULT 0 COMMENT '任务链状态机:0初始 1生成中 2完成 3失败(Service 校验流转,透传 aigc 终态映射)', - `progress` INT NOT NULL DEFAULT 0 COMMENT '进度百分比 0-100(透传 aigc progress,供前端进度条 P-CRT-12)', - `retry_of` BIGINT NULL DEFAULT NULL COMMENT '若为重生成,指向原任务链 ID(P-CRT-09 重生成血缘)', - `creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者(Yudao 审计列)', - `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updater` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者', - `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除:0未删 1已删', - `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID(Yudao 多租户兼容,MVP 单租户=0)', - PRIMARY KEY (`id`), - KEY `idx_session` (`session_id`, `id`) COMMENT '按会话查任务链(含重生成历史,按 id 倒序)', - KEY `idx_aigc` (`aigc_task_id`) COMMENT '按 aigc 任务 ID 反查任务链(轮询回写映射)' -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '创作任务链表(线性单步编排;持 aigc_task_id/version_id 引用 + 链态)'; - --- ----------------------------------------------------------------------------- --- 表:game_studio_asset —— 创作资产槽位表(单步出整包,对齐 P-CRT-02;MVP 仅落槽位 seam,不六路并发) --- 用途:单步生成产物的资产槽位记录(asset_type 槽位 + asset_url + 槽位状态)。 --- 狠切(R7/草稿 scope):MVP 只建槽位表占位 seam,不实现六路并发资产生成;资产由 aigc 单步整包产出,studio 仅登记槽位。 --- ----------------------------------------------------------------------------- -CREATE TABLE `game_studio_asset` ( - `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '资产槽位 ID', - `session_id` BIGINT NOT NULL COMMENT '所属创作会话 ID(= game_studio_session.id)', - `asset_type` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '资产槽位类型(如 sprite/background/audio/icon;MVP 槽位占位)', - `asset_url` VARCHAR(512) NOT NULL DEFAULT '' COMMENT '资产 URL(OSS/MinIO;单步整包产出后登记)', - `status` TINYINT NOT NULL DEFAULT 0 COMMENT '槽位状态:0未生成 1已生成(Service 校验,MVP 单步直填)', - `creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者(Yudao 审计列)', - `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updater` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者', - `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除:0未删 1已删', - `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID(Yudao 多租户兼容,MVP 单租户=0)', - PRIMARY KEY (`id`), - KEY `idx_session_type` (`session_id`, `asset_type`) COMMENT '按会话+槽位类型查资产' -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '创作资产槽位表(单步出整包槽位 seam;MVP 不六路并发)'; diff --git a/game-cloud/game-module-trade/game-module-trade-server/src/main/resources/db/migration/V7.0.0__create_game_trade.sql b/game-cloud/game-module-trade/game-module-trade-server/src/main/resources/db/migration/V7.0.0__create_game_trade.sql deleted file mode 100644 index 91c705f3..00000000 --- a/game-cloud/game-module-trade/game-module-trade-server/src/main/resources/db/migration/V7.0.0__create_game_trade.sql +++ /dev/null @@ -1,118 +0,0 @@ --- ============================================================================= --- 契约 #2 DB 迁移 | 模块:trade(game-module-trade,Wave2 变现域「分账/结算/提现」)| owner:WS5 --- 文件:V7.0.0__create_game_trade.sql(Flyway,只新增;已合入禁止修改,回滚写新补偿迁移) --- 内容:trade 模块核心表 —— 收益账户 game_trade_account + 收益流水 game_trade_income + 提现申请 game_trade_withdraw --- 职责(架构 Doc B):多源收入分账/归集/结算/对账;钱包打款/提现门槛与打款执行属 trade(不属 pay);不做支付收单(归 pay)。 --- MVP 钱财闭环(决策 D3):广告收入 → trade 分账(创作者 80%) → 创作者收益账户 → 提现(满 5 元)。会员订阅/支付收单=P1,本轮不做。 --- 上游 seam:消费 ad 模块 AdRevenueApi.getUnsettledRevenue/markSettled(详见 ad.yaml x-feign-contracts),T+1 SettlementJob 据此分账。 --- --- 【配置化(决策 D3,全配置走 Nacos/DB,严禁硬编码)—— 本迁移不建死值,运行时读 Nacos】: --- - trade.creator-share = 0.80 (MVP 全档统一 80% 分账比例;分层结构 creator_share_tier 保留、值后期填,见下方占位说明) --- - trade.withdraw-min = 500 (单位:分,满 5 元可提现门槛) --- 分账规则不建表(走 Nacos 配置);分层占位说明(later):若引入分层分账,可加 game_trade_share_rule --- (tier 等级/min_income 门槛/share_rate 比例),按创作者等级取不同 share_rate;MVP 不建,统一读 trade.creator-share。 --- 落账定格:game_trade_income.share_rate 落账时定格当时的 Nacos 比例快照,不随后续配置变动重算(保证历史流水可对账、金额不漂移)。 --- --- 约定:InnoDB + utf8mb4;显式列;含 Yudao 审计列 creator/create_time/updater/update_time/deleted + tenant_id; --- 金额一律「分」(BIGINT) 禁浮点,比例用 DECIMAL;资金写入有幂等键(biz_no/source_ref + uk);状态机用 tinyint,非法流转 Service 拒绝; --- 账户表 = 流水的物化汇总,余额变更必有对应流水/单据;中文列注释;关键查询建索引、禁裸 select*。 --- 错误码段:trade = 1-106-***-*** --- ============================================================================= - --- ----------------------------------------------------------------------------- --- 表:game_trade_account —— 创作者收益账户(物化汇总;余额变更必有对应流水/提现单) --- 不变式:total_income = Σ game_trade_income.net_amount(本人分账)+ Σ game_trade_grant.amount(本人 admin 赋余额)—— --- 即「累计入账」= 分账入账 + admin 赋余额两类资金来源之和(U2 起 admin 赋余额也计入,维持下方账面恒等式); --- balance + frozen + total_withdraw = total_income(余额 + 冻结中 + 已提现 = 累计入账,恒等式始终成立) --- 写入点:① 分账入账(SettlementJob)→ total_income += net、balance += net; --- ②′ admin 赋余额(U2,AccountService.grant)→ total_income += amount、balance += amount(记 game_trade_grant 流水佐证); --- ② 提现申请 → balance -= amount、frozen += amount(冻结); --- ③ 打款成功 → frozen -= amount、total_withdraw += amount; --- ④ 驳回/打款失败 → frozen -= amount、balance += amount(退回)。 --- 并发:余额增减用行级原子更新(UPDATE ... SET balance = balance ± ? WHERE user_id=? AND balance >= ?),扣减带余额充足条件防超扣。 --- ----------------------------------------------------------------------------- -CREATE TABLE `game_trade_account` ( - `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '收益账户 ID', - `user_id` BIGINT NOT NULL COMMENT '创作者用户 ID(DataPermission:创作者只见自己账户)', - `balance` BIGINT NOT NULL DEFAULT 0 COMMENT '可提现余额(单位:分,BIGINT 禁浮点)', - `frozen` BIGINT NOT NULL DEFAULT 0 COMMENT '冻结中(提现处理中占用,单位:分;提现申请时从 balance 转入)', - `total_income` BIGINT NOT NULL DEFAULT 0 COMMENT '累计入账(单位:分;= Σ 本人收益流水 net_amount + Σ 本人 admin 赋余额 grant.amount;U2 起含赋余额,维持 balance+frozen+total_withdraw 恒等式)', - `total_withdraw` BIGINT NOT NULL DEFAULT 0 COMMENT '累计已提现(已打款成功总额,单位:分)', - `creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者(Yudao 审计列)', - `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间(账户初始化时间)', - `updater` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者', - `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除:0未删 1已删', - `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID(Yudao 多租户兼容,MVP 单租户=0)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_user` (`user_id`, `tenant_id`) COMMENT '一个创作者一个收益账户(幂等初始化,防并发重复建账户)' -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '创作者收益账户表(流水物化汇总,余额变更必有流水)'; - --- ----------------------------------------------------------------------------- --- 表:game_trade_income —— 收益流水(分账后入账,每笔来源收入一条;账户余额的明细来源) --- 分账:net_amount = gross_amount × share_rate(创作者实得,落账时按分计算定格);平台分成 = gross - net(不单独存,报表算) --- 幂等核心:uk_source(source, source_ref) 防同一笔来源收入重复分账—— --- 广告:source=1(ad)、source_ref=game_ad_revenue.id;打赏:source=2(tip)、source_ref=打赏单 id。 --- SettlementJob 重跑/补偿时,命中 uk_source 即跳过该笔,保证不重复入账(不重复发钱)。 --- 对账锚点:source_ref + trace_id 与 ad 侧 game_ad_revenue.id + trace_id 对齐,端到端可对账。 --- 注:本流水即「income_settled 已落账」事实;契约#5 income_settled 事件(props:amount/source)为分析埋点镜像,不替代本表。 --- 金额单位:gross_amount / net_amount 一律「分」(BIGINT) 禁浮点;share_rate 用 DECIMAL(5,4)(如 0.8000)。 --- ----------------------------------------------------------------------------- -CREATE TABLE `game_trade_income` ( - `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '收益流水 ID', - `user_id` BIGINT NOT NULL COMMENT '创作者用户 ID(收入归属,DataPermission:只见自己)', - `source` TINYINT NOT NULL COMMENT '收入来源:1 ad 广告 / 2 tip 打赏(MVP 仅 ad;tip 留位)', - `source_ref` VARCHAR(64) NOT NULL COMMENT '来源单号(对账锚点):广告=game_ad_revenue.id;打赏=打赏单 id。与 source 组成幂等唯一键', - `gross_amount` BIGINT NOT NULL DEFAULT 0 COMMENT '原始收入(分账前,单位:分)', - `share_rate` DECIMAL(5,4) NOT NULL DEFAULT 0.0000 COMMENT '分账比例(如 0.8000=创作者得 80%;落账时定格 Nacos trade.creator-share 快照,不随配置变动重算)', - `net_amount` BIGINT NOT NULL DEFAULT 0 COMMENT '创作者实得 = gross_amount × share_rate(单位:分,落账定格;累加入账户 balance/total_income)', - `settle_date` DATE NOT NULL COMMENT 'T+1 结算日(yyyy-MM-dd;= 上游 game_ad_revenue.stat_date)', - `trace_id` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '全链路 traceId(广告来源透传自 game_ad_revenue.trace_id,供端到端对账)', - `creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者(Yudao 审计列;分账 job 为 system)', - `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间(入账时间)', - `updater` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者', - `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除:0未删 1已删', - `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID(Yudao 多租户兼容,MVP 单租户=0)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_source` (`source`, `source_ref`, `tenant_id`) COMMENT '幂等核心:同一笔来源收入(source+source_ref)只分账入账一次,防重复发钱', - KEY `idx_user_settle` (`user_id`, `settle_date`) COMMENT '我的收益流水分页(创作者+结算日)', - KEY `idx_settle_date` (`settle_date`) COMMENT '平台营收报表按日聚合 gross/net' -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '收益流水表(分账后入账;账户余额明细来源,uk 防重复分账)'; - --- ----------------------------------------------------------------------------- --- 表:game_trade_withdraw —— 提现申请(提现门槛/冻结/审核/打款执行,属 trade 不属 pay) --- 状态机 status:0待审核 →(1审核通过打款中 / 3驳回) ;1 →(2已打款 / 4打款失败) --- 合法流转(非法流转由 WithdrawService 拒绝,DO 层不承载校验): --- 0 → 1(审核通过) :管理端审核通过 --- 0 → 3(审核驳回) :冻结金额 frozen 退回 balance(资金原路退回,必填 reject_reason) --- 1 → 2(打款成功,终态) :frozen 扣减、total_withdraw 累加;MVP mock 渠道审核通过即置 2 --- 1 → 4(打款失败,终态) :frozen 退回 balance,可重新发起新单 --- 终态:2/3/4 不可再变;非法如 0→2(未审核直接打款)、2→*(已打款再变)一律拒绝。 --- 幂等核心:uk_biz_no(biz_no) 防重复提现申请——同一 biz_no 重复提交返回已有申请,不重复冻结余额。 --- 资金安全:申请时原子校验 amount ≥ Nacos trade.withdraw-min 且 ≤ balance,扣 balance 加 frozen;金额单位「分」。 --- ----------------------------------------------------------------------------- -CREATE TABLE `game_trade_withdraw` ( - `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '提现申请 ID', - `user_id` BIGINT NOT NULL COMMENT '创作者用户 ID(DataPermission:只见自己提现)', - `amount` BIGINT NOT NULL COMMENT '提现金额(单位:分,BIGINT 禁浮点;申请时校验 ≥Nacos trade.withdraw-min 且 ≤可提现余额)', - `status` TINYINT NOT NULL DEFAULT 0 COMMENT '状态机:0待审核 1审核通过打款中 2已打款 3驳回 4打款失败(合法流转见表头注释,非法流转 Service 拒绝)', - `biz_no` VARCHAR(64) NOT NULL COMMENT '提现业务单号 = 幂等键(前端生成唯一;重复提交同一 biz_no 不重复冻结)', - `channel` VARCHAR(16) NOT NULL DEFAULT 'mock' COMMENT '打款渠道:MVP=mock 桩;真实 later 接 pay 渠道异步回调', - `apply_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '申请时间', - `audit_time` DATETIME NULL COMMENT '审核时间(审核后写入)', - `audit_user_id` BIGINT NULL COMMENT '审核人用户 ID(管理端 RBAC)', - `pay_time` DATETIME NULL COMMENT '打款时间(打款成功 status=2 时写入)', - `reject_reason` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '驳回理由(status=3 时必填,回填创作者)', - `remark` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '备注(申请/审核备注)', - `creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者(Yudao 审计列;申请人)', - `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updater` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者', - `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除:0未删 1已删', - `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID(Yudao 多租户兼容,MVP 单租户=0)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_biz_no` (`biz_no`, `tenant_id`) COMMENT '提现幂等键:同一 biz_no 只受理一次(防重复提现/重复冻结)', - KEY `idx_user_status` (`user_id`, `status`) COMMENT '我的提现记录分页(创作者+状态)', - KEY `idx_status_apply` (`status`, `apply_time`) COMMENT '管理端提现审核队列(按状态+申请时间)' -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '提现申请表(提现门槛/冻结/审核/打款,属 trade)';