From 0220a9cc05deea200e8d61f9b1b1426a2c14ff69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=85=E5=BF=B5?= Date: Mon, 28 Sep 2026 18:14:00 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=B9=BF=E5=91=8A=E4=BD=8D=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E8=AF=84=E5=AE=A1=E4=BF=AE=E8=AE=A2=E2=80=94=E2=80=94?= =?UTF-8?q?createdAt=20=E8=BF=9B=E6=8A=95=E5=BD=B1/=E8=BD=BD=E8=8D=B7?= =?UTF-8?q?=E3=80=81inbox=20disabled=3D=E5=88=A0=E8=A1=8C=E3=80=81albumId?= =?UTF-8?q?=20=E6=81=92=E7=A9=BA=E4=B8=B2=E3=80=81head=20=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E8=A1=A5=20contentType?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Code --- docs/plans/2026-09-28-广告位轮播-设计方案.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/plans/2026-09-28-广告位轮播-设计方案.md b/docs/plans/2026-09-28-广告位轮播-设计方案.md index 1100257..18ab470 100644 --- a/docs/plans/2026-09-28-广告位轮播-设计方案.md +++ b/docs/plans/2026-09-28-广告位轮播-设计方案.md @@ -64,6 +64,7 @@ model ads_ov { sortOrder Int albumIds Json? entityVersion Int + createdAt DateTime @db.DateTime(6) // 排序 tie-break(§5.2:sortOrder 并列时按它稳定排序) updatedAt DateTime @db.DateTime(6) } ``` @@ -80,7 +81,8 @@ model ads_ov { staging 键 `photo-live/{env}/ads/staging/{cuid}.{ext}`(presignPut 现签)。 2. 客户端 PUT 直传 OSS(裸 fetch,Content-Type 与申明一致)。 3. `POST /v1/admin/ads` / `PATCH /v1/admin/ads/{id}` 携带 `imageStagingKey`: - 服务端同事务内 `head()` 核验(存在 + bytes 一致)→ `copyIfAbsent()` 到终键 + 服务端同事务内 `head()` 核验(存在 + bytes + contentType 与申明一致,banner + complete 同口径)→ `copyIfAbsent()` 到终键 `ads/{adId}.{ext}`(禁止覆盖语义天然防重复)→ 落库 + 写 outbox。 编辑换图:新终键生效,旧终键对象不回收(OSS 生命周期兜底,与 banner 流同款)。 @@ -91,11 +93,11 @@ model ads_ov { | 环节 | 改动 | 模板 | | --- | --- | --- | -| 契约 events.ts | type 联合加 `'ad.updated' \| 'ad.deleted'`;`AdUpdatedPayload`(全量快照:adId/imageObjectKey/linkUrl/enabled/sortOrder/albumIds/entityVersion);`isTombstoneOutboxType` 加 ad.deleted | category.* | -| outbox 写入 | albumId 列 NOT NULL,**全局广告无相册 → 写空串 `''`**(约定登记;不动账本表结构) | — | +| 契约 events.ts | type 联合加 `'ad.updated' \| 'ad.deleted'`;`AdUpdatedPayload`(全量快照:adId/imageObjectKey/linkUrl/enabled/sortOrder/albumIds/entityVersion/createdAt);`isTombstoneOutboxType` 加 ad.deleted | category.* | +| outbox 写入 | albumId 列 NOT NULL——**ad.* 事件 albumId 恒写空串 `''`(定向广告亦然,绑定关系在载荷 albumIds)**(约定登记;不动账本表结构) | — | | sender | `syncEntityTypeOfOutboxType`:ad.* → `'ad'`;entityId 从载荷 `adId` 推导 | slot-state 分支 | | 线格式 | internal-sync entityType 联合加 `'ad'` | slot-state | -| ov inbox | sync-inbox.service 加 `'ad'` 分支:tombstone→删 ads_ov;否则 upsert(eventId 幂等 + entityVersion 单调由通用逻辑承担) | slot-state→embed_slots_ov | +| ov inbox | sync-inbox.service 加 `'ad'` 分支:`tombstone ∨ enabled=false → 删 ads_ov 行`(disabled=公开不可见=无投影行,§2.2);否则 upsert(eventId 幂等 + entityVersion 单调由通用逻辑承担) | slot-state→embed_slots_ov | | 对账 | cn sync.service 对账清单加 `'ad'` 当前态清扫(albumId='';ads 全表量小) | category 分支 | ## 5. API 契约(openapi.yaml 新增,`pnpm gen` 再生类型)