topfans/backend/migrations/2026_07_21_001_exhibition_revenue_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

33 lines
1.4 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_001_exhibition_revenue_idempotent.sql
-- 批次1.1+1.3:展品收益结算幂等 + created_at 单位统一
-- 执行前请先备份:
-- pg_dump -h <host> -U postgres -t exhibition_revenue_records -t exhibitions <db> > backup_1_1.sql
BEGIN;
-- (1.3) created_at 秒→毫秒回填10 位秒 → 13 位毫秒)
UPDATE exhibition_revenue_records
SET created_at = created_at * 1000
WHERE created_at > 0 AND created_at < 100000000000;
-- (1.1) 历史去重:同一 (exhibition_id, cycle_start_time) 只保留 id 最小的一条
DELETE FROM exhibition_revenue_records a
USING exhibition_revenue_records b
WHERE a.exhibition_id = b.exhibition_id
AND a.cycle_start_time = b.cycle_start_time
AND a.id > b.id;
-- (1.1) 唯一约束(幂等基石)
ALTER TABLE exhibition_revenue_records
ADD CONSTRAINT uk_exhibition_revenue_cycle UNIQUE (exhibition_id, cycle_start_time);
-- (settled_at) 独立审计列,替代复用 is_processed
ALTER TABLE exhibitions ADD COLUMN IF NOT EXISTS settled_at bigint;
-- 回填:已被当作 settled 的历史行is_processed=true迁移到 settled_at
UPDATE exhibitions SET settled_at = COALESCE(updated_at, EXTRACT(EPOCH FROM now())*1000)
WHERE is_processed = true AND settled_at IS NULL;
-- 序列同步CLAUDE.md 强制)
SELECT setval('exhibition_revenue_records_id_seq', (SELECT COALESCE(MAX(id),1) FROM exhibition_revenue_records));
COMMIT;