From d908036621d116b79c67d2495b2e28d605e82c0b Mon Sep 17 00:00:00 2001 From: toom1996 <23cm.cn@gmail.com> Date: Tue, 22 Sep 2026 11:12:23 +0800 Subject: [PATCH] update --- .../2026-09-21-01-street-main-detail.sql | 21 + .../2026-09-21-02-duplicate-review.sql | 49 + ...026-09-21-03-ingest-source-idempotency.sql | 27 + .../plans/2026-09-21-street-main-detail.md | 1446 +++++++++++++++++ .../2026-09-20-ingest-idempotency-design.md | 9 +- .../2026-09-21-duplicate-review-design.md | 6 +- 6 files changed, 1554 insertions(+), 4 deletions(-) create mode 100644 db/migrations/2026-09-21-01-street-main-detail.sql create mode 100644 db/migrations/2026-09-21-02-duplicate-review.sql create mode 100644 db/migrations/2026-09-21-03-ingest-source-idempotency.sql create mode 100644 docs/superpowers/plans/2026-09-21-street-main-detail.md diff --git a/db/migrations/2026-09-21-01-street-main-detail.sql b/db/migrations/2026-09-21-01-street-main-detail.sql new file mode 100644 index 0000000..1c47581 --- /dev/null +++ b/db/migrations/2026-09-21-01-street-main-detail.sql @@ -0,0 +1,21 @@ +-- 2026-09-21-01 街拍主副图:草稿表 / 正式表的图片表各加两列。 +-- +-- 对应规格:docs/superpowers/specs/2026-09-21-street-main-detail-design.md §3.1 +-- is_detail 0=主图 1=副图 +-- parent_image_id 副图指向所属主图的「行 id」;主图为 0 +-- (存行 id 而非序号:序号会因重排 / 插入 / 删除而失效) +-- +-- 幂等:全部 ADD COLUMN IF NOT EXISTS,可重复执行。 +-- 存量行为 0/0,即「全部按主图渲染」,无需数据迁移。 +-- +-- 应用后请重新导出结构,否则目标库拿不到新列: +-- ./bin/dbtool dump -clean -out db/backups/db_dump.sql +-- +-- 说明:规格未给 parent_image_id 建索引。图片表当前规模为千行级(street_snap_draft_images +-- 1052 行),按 (draft_id) 过滤走顺序扫描即可;若日后量级变大需要,再按读侧实际查询补索引。 + +ALTER TABLE street_snap_draft_images ADD COLUMN IF NOT EXISTS is_detail smallint NOT NULL DEFAULT 0; +ALTER TABLE street_snap_draft_images ADD COLUMN IF NOT EXISTS parent_image_id integer NOT NULL DEFAULT 0; + +ALTER TABLE street_snap_images ADD COLUMN IF NOT EXISTS is_detail smallint NOT NULL DEFAULT 0; +ALTER TABLE street_snap_images ADD COLUMN IF NOT EXISTS parent_image_id integer NOT NULL DEFAULT 0; diff --git a/db/migrations/2026-09-21-02-duplicate-review.sql b/db/migrations/2026-09-21-02-duplicate-review.sql new file mode 100644 index 0000000..3c3b4ba --- /dev/null +++ b/db/migrations/2026-09-21-02-duplicate-review.sql @@ -0,0 +1,49 @@ +-- 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 <> ''; diff --git a/db/migrations/2026-09-21-03-ingest-source-idempotency.sql b/db/migrations/2026-09-21-03-ingest-source-idempotency.sql new file mode 100644 index 0000000..2076a25 --- /dev/null +++ b/db/migrations/2026-09-21-03-ingest-source-idempotency.sql @@ -0,0 +1,27 @@ +-- 2026-09-21-03 来源幂等:两张草稿表新增 source / source_url,并建部分唯一索引。 +-- +-- 对应规格:docs/superpowers/specs/2026-09-20-ingest-idempotency-design.md §3.1–3.2 +-- +-- 幂等:ADD COLUMN / CREATE INDEX 全带 IF NOT EXISTS,可重复执行。 +-- +-- 应用后请重新导出结构: +-- ./bin/dbtool dump -clean -out db/backups/db_dump.sql +-- +-- 注意:同规格 §3.6(month 列与「实体键并入 month」)**已作废**—— +-- 由 docs/superpowers/specs/2026-09-21-duplicate-review-design.md §3.7 取代 +-- (街拍实体键改为 (source, source_url),不再按月区分)。故本脚本**不建 month 列**。 + +-- 用 not null default '' 而不是可空:NULL 在唯一索引里不参与比较, +-- 会造成「同键可重复插入」的漏洞。 +ALTER TABLE brand_runway_drafts ADD COLUMN IF NOT EXISTS source varchar(32) NOT NULL DEFAULT ''; +ALTER TABLE brand_runway_drafts ADD COLUMN IF NOT EXISTS source_url varchar(512) NOT NULL DEFAULT ''; + +ALTER TABLE street_snap_drafts ADD COLUMN IF NOT EXISTS source varchar(32) NOT NULL DEFAULT ''; +ALTER TABLE street_snap_drafts ADD COLUMN IF NOT EXISTS source_url varchar(512) NOT NULL DEFAULT ''; + +-- 两个部分唯一索引(全量唯一索引会因存量大量 ('','') 冲突而建索引失败)。 +-- 向后兼容:老爬虫不上送 source_url 时该列为空串,自动被索引豁免 —— 行为与改动前一致。 +CREATE UNIQUE INDEX IF NOT EXISTS uq_br_draft_source + ON brand_runway_drafts (source, source_url) WHERE source_url <> ''; +CREATE UNIQUE INDEX IF NOT EXISTS uq_ss_draft_source + ON street_snap_drafts (source, source_url) WHERE source_url <> ''; diff --git a/docs/superpowers/plans/2026-09-21-street-main-detail.md b/docs/superpowers/plans/2026-09-21-street-main-detail.md new file mode 100644 index 0000000..fff010e --- /dev/null +++ b/docs/superpowers/plans/2026-09-21-street-main-detail.md @@ -0,0 +1,1446 @@ +# 街拍主副图 实现计划 + +> **面向 AI 代理的工作者:** 必需子技能:使用 subagent-driven-development(推荐)或 executing-plans 逐任务实现此计划。步骤使用复选框(`- [ ]`)语法来跟踪进度。 + +**目标:** 给街拍图集加「主图 / 副图」分组——审核页人工指定,详情页按组折叠,公开 API 保守扩展。 + +**架构:** 纯人工分组,不引入算法。数据层在两张街拍图片表上加 `is_detail` + `parent_image_id`(**列已由迁移脚本加好,本计划不改 DB**);读侧把扁平图片列表「按主副关系重排」成组视图,父引用失效时容错按主图渲染。后台沿用现有「零 JS 同步表单 POST + 302」风格,当前主图由 URL 查询参数 `?main=` 承载。 + +**技术栈:** Go 1.2x + Gin + GORM + PostgreSQL;后台为服务端渲染(内联 `html/template` 字符串常量,无前端框架)。 + +**规格:** `docs/superpowers/specs/2026-09-21-street-main-detail-design.md` + +## 全局约束 + +- **零 JS**:后台不得引入 `