内测 per-user ¥100 额度落 new-api 网关账本,game-cloud 维护一张预置池表: ops 脚本离线预建 (user+token+¥100) 灌成 FREE 条目,注册/懒 claim 时 CAS 抢一个绑玩家。 - V32.0.0 迁移双落契约源 + huijing-server 执行副本(守门①),列名对齐 ops 脚本 INSERT, uk_newapi_user/uk_claimed_by/uk_biz_no 三键仿 trade GrantDO 的 uk_biz_no 保幂等。 - NewapiQuotaPoolDO 继承 TenantBaseDO(系统级池,运行时 executeIgnore 跨租户); Mapper 提供 selectClaimedByPlayer/countFree 水位/claimOneFree 单条 FREE→CLAIMED CAS。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
59 lines
6.9 KiB
SQL
59 lines
6.9 KiB
SQL
-- =============================================================================
|
||
-- 契约 #2 DB 迁移 | 主题:内测·new-api per-user ¥100 额度池(WU2,2026-07-07 设计 §3.5)| owner:aigc(派发期映射查询 co-locate)
|
||
-- 文件:V32.0.0__create_newapi_quota_pool.sql(Flyway,纯新增表;已合入禁止修改,回滚 = drop 表 + 摘事件消费者)
|
||
-- 依据:docs/agent-specs/2026-07-07-内测-WU2-newapi额度接入-设计.md(草案,创始人拍定「离线预置池 + 注册 claim」)。
|
||
-- 版本定序:执行副本 db/migration/ 实测已连续到 V31.0.0(WU1 game_player 增列 + outbox),本件顺延取 V32.0.0(已 ls|sort -V|tail 复核)。
|
||
-- WU1 与 WU2 同批新增迁移——WU1 取 V31、WU2 顺延 V32,避免 Flyway 撞号校验失败。
|
||
-- 守门①(沿用 V11/V31):本件同时落 contracts/db-schemas/(契约源)+ huijing-server 执行副本(唯一执行 classpath),
|
||
-- 不放任何单模块 -server/db/migration/(避免同版本出现在多个 classpath jar 触发 Flyway 重复校验失败)。
|
||
-- 守门②:含中文 SQL,mini-desktop 执行必须 --default-character-set=utf8mb4。
|
||
-- 内容:CREATE newapi_quota_pool —— 离线 ops 脚本预建 FREE 条目 + 注册 claim 绑玩家(FREE→CLAIMED),账本在 new-api 网关。
|
||
-- =============================================================================
|
||
|
||
-- -----------------------------------------------------------------------------
|
||
-- CREATE newapi_quota_pool —— new-api per-user 额度预置池(§3.5)
|
||
-- 语义:ops 脚本(game-runtime/tools/newapi_pool_provision.py)离线预建 N 个 (new-api user + token + ¥100),
|
||
-- 按条目 INSERT(status=FREE、claimed_* 空);注册/懒 claim 时某条被 CAS 抢占翻转 CLAIMED 并绑 game_player。
|
||
-- 账本口径唯一 = new-api 网关(权威余额=token remain_quota、权威消耗=user used_quota);本表只存 grant_quota 审计快照,不在 game-cloud 记余额。
|
||
-- 列名严格对齐 ops 脚本 emit 的 INSERT:(newapi_user_id, newapi_token_id, newapi_token_key, grant_quota,
|
||
-- quota_per_unit_snapshot, usd_rate_snapshot, status),去重键 uk_newapi_user(newapi_user_id) 供 ON DUPLICATE KEY UPDATE 幂等补池。
|
||
-- 审计列(creator/create_time/updater/update_time/deleted)与 tenant_id 均给默认值:ops 脚本 raw INSERT 只给业务列,
|
||
-- 审计列/租户列走 DB 默认落值;运行时 claim/查询经 TenantUtils.executeIgnore 跨租户存取(池是系统级资源)。
|
||
-- 幂等三键(仿 game_trade_grant 的 uk_biz_no):
|
||
-- · uk_newapi_user —— 预建条目按 new-api 用户去重(脚本补池锚);
|
||
-- · uk_claimed_by —— 一玩家至多一条 CLAIMED(FREE 时 claimed_by 为 NULL,NULL 不参与唯一约束,多条 FREE 并存);
|
||
-- · uk_biz_no —— claim 幂等键 claim_<gamePlayerId>(FREE 时为 NULL)。
|
||
-- 并发/重投由 status='FREE' 单条 CAS + 上述两 NULL 唯一键三重收敛成一条:同玩家不占第二条、两玩家不抢同一条。
|
||
-- newapi_token_key 是 new-api 调用凭据明文落库(内测可接受、须视为敏感):随 job 内网下发须日志脱敏,生产化应加密列(红线待办,本阶段不做)。
|
||
-- 前后兼容:纯新增表,不改任何既有表结构,无迁移风险。
|
||
-- ⚠ 再 claim(S4 凭据失效路,本单不实现):将 CLAIMED 隔离为 INVALID 时必须同步清空 claimed_by_game_player_id/biz_no,
|
||
-- 否则与该玩家新 CLAIMED 条目撞 uk_claimed_by/uk_biz_no。本单只落 FREE→CLAIMED,INVALID 转换延后到 S4。
|
||
-- -----------------------------------------------------------------------------
|
||
CREATE TABLE `newapi_quota_pool` (
|
||
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '池条目编号',
|
||
`newapi_user_id` BIGINT NOT NULL COMMENT '预建的 new-api users.id(脚本灌数去重键)',
|
||
`newapi_token_id` BIGINT NOT NULL COMMENT '预建的 new-api tokens.id',
|
||
`newapi_token_key` VARCHAR(64) NOT NULL COMMENT 'new-api tokens.key(48 位 sk-…;⚠ 敏感,随 job 下发须脱敏,永不整条落日志)',
|
||
`grant_quota` BIGINT NOT NULL COMMENT '该条目预置的 ¥100 折算 quota(审计快照;权威余额以网关 token.remain_quota 为准)',
|
||
`quota_per_unit_snapshot` BIGINT NOT NULL COMMENT '折算时网关 quota_per_unit(默认 500000,审计追溯用)',
|
||
`usd_rate_snapshot` DECIMAL(10,4) NOT NULL COMMENT '折算时 usd_exchange_rate(默认 7.3,审计追溯用)',
|
||
`status` VARCHAR(16) NOT NULL DEFAULT 'FREE' COMMENT '状态:FREE可claim / CLAIMED已绑玩家 / INVALID token失效隔离(S4);claim CAS 抢占锚',
|
||
`claimed_by_game_player_id` BIGINT NULL COMMENT 'claim 后 ↔ game_player.id;FREE 时 NULL(uk 允许多 NULL,CLAIMED 保证一玩家至多一条)',
|
||
`claimed_at` DATETIME NULL COMMENT 'claim 时间(CLAIMED 时回填)',
|
||
`biz_no` VARCHAR(64) NULL COMMENT 'claim 幂等键 claim_<gamePlayerId>;FREE 时 NULL',
|
||
`retry_count` INT NOT NULL DEFAULT 0 COMMENT '预留:claim/隔离重试计数',
|
||
`remark` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '备注(隔离原因等)',
|
||
-- 标准审计列(DO 继承 TenantBaseDO;ops 脚本 raw INSERT 不给这些列,走默认落值,运行时 executeIgnore 跨租户)
|
||
`creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者(审计列)',
|
||
`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 '租户编号(系统级池资源,运行时 executeIgnore 跨租户存取,值仅占位)',
|
||
PRIMARY KEY (`id`),
|
||
UNIQUE KEY `uk_newapi_user` (`newapi_user_id`) COMMENT '预建条目按 new-api 用户去重(脚本 ON DUPLICATE KEY UPDATE 补池锚)',
|
||
UNIQUE KEY `uk_claimed_by` (`claimed_by_game_player_id`) COMMENT '一玩家至多一条 CLAIMED(NULL 不参与约束,多条 FREE 并存)',
|
||
UNIQUE KEY `uk_biz_no` (`biz_no`) COMMENT 'claim 幂等键唯一(NULL 不参与约束)',
|
||
KEY `idx_status` (`status`) COMMENT 'claim 抢占按 status=FREE 扫、水位按 FREE 计数'
|
||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = 'new-api per-user ¥100 额度预置池(离线预建 FREE + 注册 claim 绑玩家,WU2 §3.5)';
|