feat(aigc): WU2① new-api 额度池表 V32 + DO/Mapper——离线预建 FREE 条目 claim 抢占
内测 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>
This commit is contained in:
parent
28bd5339d4
commit
c13595fbc2
58
contracts/db-schemas/V32.0.0__create_newapi_quota_pool.sql
Normal file
58
contracts/db-schemas/V32.0.0__create_newapi_quota_pool.sql
Normal file
@ -0,0 +1,58 @@
|
||||
-- =============================================================================
|
||||
-- 契约 #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)';
|
||||
@ -0,0 +1,62 @@
|
||||
package com.wanxiang.huijing.game.module.aigc.dal.dataobject.quota;
|
||||
|
||||
import com.wanxiang.huijing.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* new-api per-user 额度池条目 DO(对应表 newapi_quota_pool,WU2 §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。
|
||||
*
|
||||
* 继承 {@link TenantBaseDO}:自带 creator/create_time/updater/update_time/deleted + tenant_id 审计/租户列。
|
||||
* 池是系统级资源,运行时 claim/查询经 {@code TenantUtils.executeIgnore} 跨租户存取(tenant_id 值仅占位);
|
||||
* ops 脚本 raw INSERT 只给业务列,审计/租户列走 DB 默认落值。
|
||||
*
|
||||
* 账本口径唯一 = new-api 网关(权威余额=token remain_quota、权威消耗=user used_quota);本 DO 的
|
||||
* {@link #grantQuota} 只是审计快照,game-cloud 侧不记余额。
|
||||
*
|
||||
* 幂等三键(仿 {@code GrantDO} 的 uk_biz_no):uk_newapi_user(脚本去重)/ uk_claimed_by(一玩家至多一条 CLAIMED)/
|
||||
* uk_biz_no(claim 幂等键 claim_<gamePlayerId>)——并发/重投由 status='FREE' 单条 CAS + 两 NULL 唯一键三重收敛。
|
||||
*
|
||||
* @author 绘境AI
|
||||
*/
|
||||
@TableName("newapi_quota_pool")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class NewapiQuotaPoolDO extends TenantBaseDO {
|
||||
|
||||
/** 池条目主键 */
|
||||
private Long id;
|
||||
/** 预建的 new-api users.id(脚本灌数去重键 uk_newapi_user) */
|
||||
private Long newapiUserId;
|
||||
/** 预建的 new-api tokens.id */
|
||||
private Long newapiTokenId;
|
||||
/** new-api tokens.key(48 位 sk-…;⚠ 敏感,随 job 下发须脱敏,永不整条落日志) */
|
||||
private String newapiTokenKey;
|
||||
/** 该条目预置的 ¥100 折算 quota(审计快照;权威余额以网关 token.remain_quota 为准) */
|
||||
private Long grantQuota;
|
||||
/** 折算时网关 quota_per_unit(默认 500000,审计追溯用) */
|
||||
private Long quotaPerUnitSnapshot;
|
||||
/** 折算时 usd_exchange_rate(默认 7.3,审计追溯用) */
|
||||
private BigDecimal usdRateSnapshot;
|
||||
/** 状态:FREE/CLAIMED/INVALID({@link com.wanxiang.huijing.game.module.aigc.enums.NewapiQuotaStatusEnum});claim CAS 抢占锚 */
|
||||
private String status;
|
||||
/** claim 后 ↔ game_player.id;FREE 时 NULL(uk_claimed_by 允许多 NULL) */
|
||||
private Long claimedByGamePlayerId;
|
||||
/** claim 时间(CLAIMED 时回填) */
|
||||
private LocalDateTime claimedAt;
|
||||
/** claim 幂等键 claim_<gamePlayerId>;FREE 时 NULL */
|
||||
private String bizNo;
|
||||
/** 预留:claim/隔离重试计数 */
|
||||
private Integer retryCount;
|
||||
/** 备注(隔离原因等) */
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package com.wanxiang.huijing.game.module.aigc.dal.mysql.quota;
|
||||
|
||||
import com.wanxiang.huijing.game.module.aigc.dal.dataobject.quota.NewapiQuotaPoolDO;
|
||||
import com.wanxiang.huijing.game.module.aigc.enums.NewapiQuotaStatusEnum;
|
||||
import com.wanxiang.huijing.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.wanxiang.huijing.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* new-api 额度池 Mapper(WU2 §3.5)
|
||||
*
|
||||
* <p><b>跨租户存取铁律</b>:池是系统级资源、注册消费/派发线均无租户上下文——调用方({@code NewapiQuotaServiceImpl})
|
||||
* 必须用 {@code TenantUtils.executeIgnore(...)} 包裹本 Mapper 的每次调用,否则多租户插件会按空租户上下文过滤致查不到条目。
|
||||
*
|
||||
* <p><b>claim 幂等靠 CAS + 唯一键</b>:{@link #claimOneFree} 是单条 {@code FREE→CLAIMED} 行级 CAS;并发/重投由
|
||||
* {@code status='FREE'} 条件 + uk_claimed_by + uk_biz_no 三重收敛,任何路径不给同一玩家占第二条、不让两玩家抢同一条。
|
||||
*
|
||||
* @author 绘境AI
|
||||
*/
|
||||
@Mapper
|
||||
public interface NewapiQuotaPoolMapper extends BaseMapperX<NewapiQuotaPoolDO> {
|
||||
|
||||
/**
|
||||
* 按已绑玩家取其 CLAIMED 条目(懒 claim 前查 / 派发取 token;uk_claimed_by 保证至多一条)。
|
||||
*
|
||||
* @param gamePlayerId game_player.id
|
||||
* @return CLAIMED 条目;未绑返回 null
|
||||
*/
|
||||
default NewapiQuotaPoolDO selectClaimedByPlayer(Long gamePlayerId) {
|
||||
return selectOne(new LambdaQueryWrapperX<NewapiQuotaPoolDO>()
|
||||
.eq(NewapiQuotaPoolDO::getClaimedByGamePlayerId, gamePlayerId)
|
||||
.eq(NewapiQuotaPoolDO::getStatus, NewapiQuotaStatusEnum.CLAIMED.getStatus()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 池水位:FREE 条目计数(低于阈值触发补池告警,§3.4)。
|
||||
*
|
||||
* @return 当前 FREE 条目数
|
||||
*/
|
||||
default Long countFree() {
|
||||
return selectCount(new LambdaQueryWrapperX<NewapiQuotaPoolDO>()
|
||||
.eq(NewapiQuotaPoolDO::getStatus, NewapiQuotaStatusEnum.FREE.getStatus()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 原子 CAS:抢一个 FREE 条目翻转 CLAIMED 并绑玩家(§3.4)。
|
||||
*
|
||||
* <p>双层派生表 {@code (SELECT id FROM (SELECT id ... LIMIT 1) t)} 是 MySQL「不能 UPDATE 又在 FROM 子查询引用同表」
|
||||
* 的标准物化绕法;{@code AND status='FREE'} 再做一次行级 CAS 兜底并发。返回:1=抢到、0=池空(子查询 NULL 无命中)。
|
||||
* 显式带 {@code deleted=0}(raw @Update 不经多租户/逻辑删自动改写,调用方 executeIgnore 已免租户过滤)。
|
||||
*
|
||||
* @param gamePlayerId 绑定的 game_player.id
|
||||
* @param bizNo 幂等键 claim_<gamePlayerId>
|
||||
* @param claimedAt claim 时间
|
||||
* @return 影响行数(1=抢到;0=池空无 FREE 条目)
|
||||
*/
|
||||
@Update("UPDATE newapi_quota_pool "
|
||||
+ "SET status='CLAIMED', claimed_by_game_player_id=#{gamePlayerId}, claimed_at=#{claimedAt}, biz_no=#{bizNo} "
|
||||
+ "WHERE id = (SELECT id FROM (SELECT id FROM newapi_quota_pool WHERE status='FREE' AND deleted=0 ORDER BY id LIMIT 1) t) "
|
||||
+ "AND status='FREE' AND deleted=0")
|
||||
int claimOneFree(@Param("gamePlayerId") Long gamePlayerId,
|
||||
@Param("bizNo") String bizNo,
|
||||
@Param("claimedAt") LocalDateTime claimedAt);
|
||||
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.wanxiang.huijing.game.module.aigc.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* new-api 额度池条目状态枚举(WU2 §3.4/§3.5 状态机)
|
||||
*
|
||||
* FREE → 离线 ops 脚本预建的可 claim 条目;CLAIMED → 已被注册/懒 claim CAS 抢占绑玩家;
|
||||
* INVALID → token 失效隔离(S4 再 claim 路,本单只落 FREE→CLAIMED,不产出 INVALID)。
|
||||
* 落库列 newapi_quota_pool.status(varchar(16)),CAS 抢占以 status='FREE' 为锚。
|
||||
*
|
||||
* @author 绘境AI
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum NewapiQuotaStatusEnum {
|
||||
|
||||
/** 可 claim(离线预建,claimed_* 空) */
|
||||
FREE("FREE"),
|
||||
/** 已绑玩家(claim CAS 抢占后翻转) */
|
||||
CLAIMED("CLAIMED"),
|
||||
/** token 失效隔离(S4,不再派发;本单不产出) */
|
||||
INVALID("INVALID");
|
||||
|
||||
/** 落库值(对齐 DDL status 列取值) */
|
||||
private final String status;
|
||||
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
-- =============================================================================
|
||||
-- 契约 #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)';
|
||||
Loading…
x
Reference in New Issue
Block a user