-- 2026-09-21-02 重复检测与审核展示:新建 image_duplicates 表 + 街拍正式表按文章做键。 -- -- 对应规格:docs/superpowers/specs/2026-09-21-duplicate-review-design.md §3.1 / §3.7 -- -- 幂等:CREATE TABLE / CREATE INDEX 全带 IF NOT EXISTS,ADD COLUMN 带 IF NOT EXISTS, -- 可重复执行。 -- -- 应用后请重新导出结构: -- ./bin/dbtool dump -clean -out db/backups/db_dump.sql -- --------------------------------------------------------------------------- -- ① 重复图对表(读时预计算并落库,替代不可反查的 is_duplicate / dup_of 两列) -- --------------------------------------------------------------------------- -- kind / owner_kind 等字符串列控制长度而不做 CHECK 约束:与项目既有表风格一致 -- (brand_runway_drafts.status 等也是裸 varchar),避免新增约束带来的迁移负担。 CREATE TABLE IF NOT EXISTS image_duplicates ( id BIGSERIAL PRIMARY KEY, kind varchar(16) NOT NULL, -- runway | street -- 本方(「这张图」) image_id integer NOT NULL, -- 图片行 id owner_kind varchar(8) NOT NULL, -- draft | official owner_id integer NOT NULL, -- 草稿 id 或正式表主键 -- 对手(「和它重复的那张」) peer_image_id integer NOT NULL, peer_owner_kind varchar(8) NOT NULL, peer_owner_id integer NOT NULL, created_at integer NOT NULL DEFAULT 0 ); -- 唯一索引:保证重复配对计算幂等(写入侧用 ON CONFLICT ... DO NOTHING) CREATE UNIQUE INDEX IF NOT EXISTS uq_image_dups_pair ON image_duplicates (kind, owner_kind, image_id, peer_owner_kind, peer_image_id); -- 辅助索引:读侧按草稿 / 专辑批量取数(审核详情页) CREATE INDEX IF NOT EXISTS idx_image_dups_owner ON image_duplicates (kind, owner_kind, owner_id); -- --------------------------------------------------------------------------- -- ② 街拍正式表:新增 source / source_url,供「一篇文章一张专辑」的实体键使用 -- --------------------------------------------------------------------------- -- 用 not null default '' 而不是可空:NULL 在唯一索引里不参与比较, -- 会造成「同键可重复插入」的漏洞。 ALTER TABLE street_snaps ADD COLUMN IF NOT EXISTS source varchar(32) NOT NULL DEFAULT ''; ALTER TABLE street_snaps ADD COLUMN IF NOT EXISTS source_url varchar(512) NOT NULL DEFAULT ''; -- 必须是**部分**索引:存量行 source_url 为空串,全量唯一索引会因大量 ('','') 冲突 -- 而建索引失败。 CREATE UNIQUE INDEX IF NOT EXISTS uq_ss_source ON street_snaps (source, source_url) WHERE source_url <> '';