-- 资产钱包自动续费:新增全局单行配置表 tb_asset_auto_renewal_config。 -- 背景:运营需要「资产钱包余额充足时在最终到期前自动续购当前有效主套餐」的总开关、适用范围与 -- 到期前天数的统一配置。既有仓库没有任何单行配置表(000225 的 H5 弹窗配置是多行加优先级), -- 因此本迁移新建一张被 CHECK 约束到单行(id 恒为 1)的全局配置表,并预置一行默认关闭。 -- -- 设计选择: -- 1. 主键恒为 1:本能力只有一份全局生效配置,不按店铺、企业或个人客户分范围。单行约束由 -- CHECK (id = 1) 与预置行共同保证,应用层保存走同一行的行锁串行化,不新增第二行。 -- 2. enabled 默认 0 且严格 0/1:既有「启停新增语义使用 0=禁用、1=启用」的口径(ENG-STATE-001)。 -- 默认关闭,保证迁移上线后不会立即产生续购订单。 -- 3. scope 只允许 all/specified;两种范围的集合互斥关系由 CHECK 兜住: -- specified 时 package_ids 必须非空,all 时必须为空数组。半配置(指定范围但集合为空)会被 -- 解释为「谁都不符合范围」而静默不续购,属于必须由 Schema 兜住的风险。 -- 4. days_before_expiry 限制 1..90:与规格的「正整数,上限 90」一致,0 天窗口会让提前续购失去意义。 -- 5. config_version 是配置版本而非乐观锁:保存事务内自增,供尝试记录冻结快照追溯; -- 并发保护用单行事务锁(SELECT ... FOR UPDATE),不用 version 条件更新(ENG-CONC-001 面向余额与状态机)。 -- 6. creator/updater 记录维护账号 ID,系统写入为 0;本表没有软删列,配置行不删除。 -- 7. 不使用数据库外键,package_ids 中的套餐由应用层显式校验。 CREATE TABLE tb_asset_auto_renewal_config ( id BIGINT PRIMARY KEY, enabled SMALLINT NOT NULL DEFAULT 0, scope VARCHAR(16) NOT NULL DEFAULT 'all', package_ids JSONB NOT NULL DEFAULT '[]'::jsonb, days_before_expiry INTEGER NOT NULL DEFAULT 15, config_version BIGINT NOT NULL DEFAULT 1, creator BIGINT NOT NULL DEFAULT 0, updater BIGINT NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), CONSTRAINT ck_asset_auto_renewal_config_singleton CHECK (id = 1), CONSTRAINT ck_asset_auto_renewal_config_enabled CHECK (enabled IN (0, 1)), CONSTRAINT ck_asset_auto_renewal_config_scope CHECK (scope IN ('all', 'specified')), CONSTRAINT ck_asset_auto_renewal_config_package_ids CHECK (jsonb_typeof(package_ids) = 'array'), CONSTRAINT ck_asset_auto_renewal_config_scope_packages CHECK ( (scope = 'specified' AND jsonb_array_length(package_ids) >= 1) OR (scope = 'all' AND jsonb_array_length(package_ids) = 0) ), CONSTRAINT ck_asset_auto_renewal_config_window CHECK (days_before_expiry BETWEEN 1 AND 90), CONSTRAINT ck_asset_auto_renewal_config_version CHECK (config_version >= 1) ); COMMENT ON TABLE tb_asset_auto_renewal_config IS '资产钱包自动续费全局配置,主键恒为 1 的单行表,只影响后续扫描'; COMMENT ON COLUMN tb_asset_auto_renewal_config.id IS '主键,恒为 1(CHECK 约束保证单行)'; COMMENT ON COLUMN tb_asset_auto_renewal_config.enabled IS '总开关 0-关闭 1-开启;关闭后不再创建新的尝试与订单,既有尝试记录与通知保留'; COMMENT ON COLUMN tb_asset_auto_renewal_config.scope IS '适用范围 all-全部主套餐 specified-指定主套餐'; COMMENT ON COLUMN tb_asset_auto_renewal_config.package_ids IS '指定主套餐商品ID集合(jsonb 数组);scope=specified 时非空,scope=all 时为空数组'; COMMENT ON COLUMN tb_asset_auto_renewal_config.days_before_expiry IS '统一到期前天数(正整数,1-90),触发窗口为最终到期剩余天数闭区间 0 至该值'; COMMENT ON COLUMN tb_asset_auto_renewal_config.config_version IS '配置版本,每次保存事务内自增;尝试记录只保留触发时版本快照,不重算'; COMMENT ON COLUMN tb_asset_auto_renewal_config.creator IS '创建人账号ID,系统写入为 0'; COMMENT ON COLUMN tb_asset_auto_renewal_config.updater IS '最近更新人账号ID,系统写入为 0'; COMMENT ON COLUMN tb_asset_auto_renewal_config.created_at IS '创建时间'; COMMENT ON COLUMN tb_asset_auto_renewal_config.updated_at IS '最近更新时间'; -- 预置唯一一行且默认关闭:读取侧按主键 1 读取,缺失即视为部署异常。 INSERT INTO tb_asset_auto_renewal_config (id, enabled, scope, package_ids, days_before_expiry, config_version) VALUES (1, 0, 'all', '[]'::jsonb, 15, 1);