docs: 广告位设计评审修订——createdAt 进投影/载荷、inbox disabled=删行、albumId 恒空串、head 校验补 contentType

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-28 18:14:00 +08:00
parent 573a559e4a
commit 0220a9cc05
@@ -64,6 +64,7 @@ model ads_ov {
sortOrder Int sortOrder Int
albumIds Json? albumIds Json?
entityVersion Int entityVersion Int
createdAt DateTime @db.DateTime(6) // 排序 tie-break(§5.2:sortOrder 并列时按它稳定排序)
updatedAt DateTime @db.DateTime(6) updatedAt DateTime @db.DateTime(6)
} }
``` ```
@@ -80,7 +81,8 @@ model ads_ov {
staging 键 `photo-live/{env}/ads/staging/{cuid}.{ext}`(presignPut 现签)。 staging 键 `photo-live/{env}/ads/staging/{cuid}.{ext}`(presignPut 现签)。
2. 客户端 PUT 直传 OSS(裸 fetch,Content-Type 与申明一致)。 2. 客户端 PUT 直传 OSS(裸 fetch,Content-Type 与申明一致)。
3. `POST /v1/admin/ads` / `PATCH /v1/admin/ads/{id}` 携带 `imageStagingKey`: 3. `POST /v1/admin/ads` / `PATCH /v1/admin/ads/{id}` 携带 `imageStagingKey`:
服务端同事务内 `head()` 核验(存在 + bytes 一致)→ `copyIfAbsent()` 到终键 服务端同事务内 `head()` 核验(存在 + bytes + contentType 与申明一致,banner
complete 同口径)→ `copyIfAbsent()` 到终键
`ads/{adId}.{ext}`(禁止覆盖语义天然防重复)→ 落库 + 写 outbox。 `ads/{adId}.{ext}`(禁止覆盖语义天然防重复)→ 落库 + 写 outbox。
编辑换图:新终键生效,旧终键对象不回收(OSS 生命周期兜底,与 banner 流同款)。 编辑换图:新终键生效,旧终键对象不回收(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.* | | 契约 events.ts | type 联合加 `'ad.updated' \| 'ad.deleted'`;`AdUpdatedPayload`(全量快照:adId/imageObjectKey/linkUrl/enabled/sortOrder/albumIds/entityVersion/createdAt);`isTombstoneOutboxType` 加 ad.deleted | category.* |
| outbox 写入 | albumId 列 NOT NULL,**全局广告无相册 → 写空串 `''`**(约定登记;不动账本表结构) | — | | outbox 写入 | albumId 列 NOT NULL——**ad.* 事件 albumId 恒写空串 `''`(定向广告亦然,绑定关系在载荷 albumIds)**(约定登记;不动账本表结构) | — |
| sender | `syncEntityTypeOfOutboxType`:ad.* → `'ad'`;entityId 从载荷 `adId` 推导 | slot-state 分支 | | sender | `syncEntityTypeOfOutboxType`:ad.* → `'ad'`;entityId 从载荷 `adId` 推导 | slot-state 分支 |
| 线格式 | internal-sync entityType 联合加 `'ad'` | 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 分支 | | 对账 | cn sync.service 对账清单加 `'ad'` 当前态清扫(albumId='';ads 全表量小) | category 分支 |
## 5. API 契约(openapi.yaml 新增,`pnpm gen` 再生类型) ## 5. API 契约(openapi.yaml 新增,`pnpm gen` 再生类型)