topfans/backend/migrations/2026_07_21_003_exhibition_hours_idempotent.sql
zerosaturation 878bd46399 fix(backend): financial correctness — settlement/hours/mint idempotency (batch 1)
- settlement(1.1): exhibition_revenue_records 加 UNIQUE(exhibition_id,cycle_start_time)
  + CreateRevenueRecord ON CONFLICT DO NOTHING; MQ 用 settled_at 替代复用 is_processed;
  恢复扫描器过滤改 settled_at IS NULL; created_at 统一毫秒; 删死代码 cleanup_worker.go。
- hours(1.2): 新增 exhibition_hours_log/asset_exhibition_hours_log(source_id 唯一)幂等表;
  fan_profile/assetLevel 的 AddExhibitionHours 按 sourceID 幂等(事务包裹); 存量重算脚本。
- mint(1.4/1.5/1.6): crystal_transaction_records (source_id,change_type) 部分唯一索引
  + UpdateCrystalBalance/CreateMintOrder 幂等; 保底改 crypto/rand; 下线伪 tx_hash;
  doMint Redis Lua 原子限流。
- migrations 001/002/003; 各服务单测(自包含, 缺 DB t.Skip)。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-23 01:11:54 +08:00

46 lines
2.2 KiB
PL/PgSQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 2026_07_21_003_exhibition_hours_idempotent.sql
-- 批次1.2:累计时长幂等(用户级 + 资产级)
-- 执行前请先备份:
-- pg_dump -h <host> -U postgres -t exhibition_hours_log -t asset_exhibition_hours_log <db> > backup_1_2.sql
-- 触发场景fan_profile_repository.AddExhibitionHours/assetLevelService.AddExhibitionHours
-- 重复调用会造成 total_exhibition_hours / season_exhibition_hours 多次叠加
-- 设计:每条幂等键由 source_id 唯一约束保证INSERT ON CONFLICT DO NOTHING 即跳过
BEGIN;
-- (1) 用户级幂等 log
CREATE TABLE IF NOT EXISTS exhibition_hours_log (
id BIGINT PRIMARY KEY,
source_id VARCHAR(100) NOT NULL UNIQUE,
user_id BIGINT NOT NULL,
star_id BIGINT NOT NULL,
hours BIGINT NOT NULL,
created_at BIGINT NOT NULL
);
CREATE INDEX IF NOT EXISTS ix_exh_log_user_star
ON exhibition_hours_log (user_id, star_id);
CREATE INDEX IF NOT EXISTS ix_exh_log_created
ON exhibition_hours_log (created_at);
-- (2) 资产级幂等 log
CREATE TABLE IF NOT EXISTS asset_exhibition_hours_log (
id BIGINT PRIMARY KEY,
source_id VARCHAR(100) NOT NULL UNIQUE,
asset_id BIGINT NOT NULL,
hours INT NOT NULL,
created_at BIGINT NOT NULL
);
CREATE INDEX IF NOT EXISTS ix_asset_exh_log_asset
ON asset_exhibition_hours_log (asset_id);
-- (3) 序列同步CLAUDE.md 强制;新表无现存行,序列置 1
-- 内部去重 log 表无脚本硬编码其 id不适用 START 10000 约定;序列从 1 起步。
CREATE SEQUENCE IF NOT EXISTS exhibition_hours_log_id_seq OWNED BY exhibition_hours_log.id;
ALTER TABLE exhibition_hours_log ALTER COLUMN id SET DEFAULT nextval('exhibition_hours_log_id_seq');
SELECT setval('exhibition_hours_log_id_seq', GREATEST((SELECT COALESCE(MAX(id),0) FROM exhibition_hours_log), 1));
CREATE SEQUENCE IF NOT EXISTS asset_exhibition_hours_log_id_seq OWNED BY asset_exhibition_hours_log.id;
ALTER TABLE asset_exhibition_hours_log ALTER COLUMN id SET DEFAULT nextval('asset_exhibition_hours_log_id_seq');
SELECT setval('asset_exhibition_hours_log_id_seq', GREATEST((SELECT COALESCE(MAX(id),0) FROM asset_exhibition_hours_log), 1));
COMMIT;