Files
atlas-seller-kit/docs/reviews/implementation-readiness-open-items.md
T

129 lines
8.0 KiB
Markdown
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.
# 实现前待决与待落地事项
> 本文记录 API 契约和数据库 DDL 评审后尚未闭环的事项。它不是新的产品需求;除明确标为“已决策”的条目外,实施对应模块前必须先确认或补齐。最后复核:2026-09-02。
## 使用规则
- **已决策,待落地**:产品或技术方向已确认,但 DDL、接口契约或实现规则尚未同步,编码前补齐即可。
- **待确认**:会改变用户可见行为或数据语义,不能由开发自行猜测。
- **实现约束**:已经确认,后续代码、测试和文档必须遵守。
## P0:开始实现前必须闭环
### 1. 幂等请求与 Transactional Outbox
**状态:已决策,DDL 与基础架构文档已落地;待 NestJS 实现和集成测试。**
所有可重试的关键写操作需要幂等保护;所有会触发异步工作的业务写入需要 Transactional Outbox。基础迁移已新增以下两张工作空间隔离表,并已纳入 RLS、清理策略和 Worker 设计:
- `idempotency_requests`:按用户、工作空间、规范化请求路径和 `Idempotency-Key` 保存请求摘要、处理状态、HTTP 响应摘要、关联资源及过期时间。至少保留 24 小时;建议 48 小时。相同键而请求摘要不同返回 `409 IDEMPOTENCY_KEY_REUSED`。
- `outbox_events`:在**同一数据库事务**中随业务数据和 `operations` 记录写入待投递事件;独立 Dispatcher 读取、投递 BullMQ 并重试。事件投递必须按“至少一次”设计,消费者必须可重入;不得将 API Key、Cookie、预签名 URL 等秘密写入事件载荷。
首批必须接入的场景:店铺创建/凭据验证、上传完成后的媒体处理、采集素材转存、首次上架发布、在线商品同步、AI 生成任务。普通草稿保存可在首期只使用乐观锁。完整设计和验收项见 [`../architecture/transactional-outbox-and-idempotency.md`](../architecture/transactional-outbox-and-idempotency.md)。
### 2. `offer_id`(Ozon 货号)策略
**状态:2026-09-22 修订决策;AI 填报尚未实现。**
- 采集进入采集箱时,型号(`model`)和 `offer_id` 都允许为空。
- `model` 是商品通用字段;`offer_id` 是当前平台下、每个 SKU 的字段。用户可手动填写,也可在进入编辑页后点击“AI 填报”,由规则与 AI 生成并直接填入表单。
- 采集入箱本身不填写货号;AI 生成以 Atlas 稳定商品标识、已确认类目和实际 SKU 规格为依据,可使用来源信息提炼语义片段,但不得直接复用来源 SKU 作为目标平台货号。
- 首次上架前,`model` 必填;每个被选中 SKU 的 `offer_id` 必填,且在目标门店内唯一。生成值和手填值接受相同的保存及发布校验。
- 导入成功后,该次平台 SKU 发布记录使用的 `offer_id` 作为历史事实,不允许通过“重新上架”改变;后续编辑在线商品属于另一套平台商品更新能力。
详细的主动生成、表单回填及冲突处理见 [`../product/ai-autofill-plan.md`](../product/ai-autofill-plan.md)。
## P1:实现对应模块前修正
### 1. SKU 与平台发布配置的同商品归属
**状态:M3.0 已落地数据库约束(2026-09-09);发布任务、在线镜像等后续表必须复用该归属链。**
`product_variant_platform_listings` 同时引用平台发布配置(profile)和通用 SKU(variant),但必须强制:`variant.product_id = profile.product_id`。同一条归属链也适用于属性、报价、发布任务项和在线镜像映射。
实施时优先选用可维护的复合外键/冗余 `product_id` 加一致性约束;如 PostgreSQL 外键表达能力不足,再使用约束触发器。不得只依赖服务层校验。
### 2. 类目切换后未映射属性的持久化
**状态:M3.0 已落地持久化表(2026-09-09);类目切换写入与恢复操作随编辑草稿保存实现。**
切换目标平台类目后,旧类目中无法映射的属性值必须作为 Atlas 草稿保留,供用户查看、复用或手动处理,不能只出现在一次 API response 的 warning 中。
可选落地方式:
- 新增 `product_unmapped_attributes`,保存原类目/属性标识、名称快照、原值、原因、保留时间;或
- 在 `product_platform_profiles` 增加有明确 JSON Schema 的 `unmapped_attributes_draft`。
选择后需要同步商品编辑 API 的读取、保存和类目切换响应。
### 3. 乐观锁的统一实施
**状态:M3.1 已使用产品/profile 双 `revision` 条件更新、事务回滚和集成测试落地;后续编辑资源不得绕过该规则。**
`revision` 不依赖数据库触发器自动递增。所有可编辑资源的更新必须由统一 Repository/数据访问层执行:
```sql
UPDATE ...
SET ..., revision = revision + 1
WHERE id = :id AND revision = :expected_revision;
```
受影响行数为 `0` 时,服务层读取当前版本摘要并返回 `409 VERSION_CONFLICT`。必须为并发更新和重复提交编写集成测试;禁止由各业务开发者手写、遗漏该规则。
### 4. 来源平台、发布目标平台与页头上下文
**状态:已决策,待平台能力模型落地。**
`platforms` 需要显式表达以下能力,不能由名称或零散 JSON 约定猜测:
- `can_be_source`:可作为采集来源,例如 1688、淘宝、天猫、Ozon;
- `can_be_target`:可作为商品发布目标,例如首期 Ozon;
- `can_be_header_context`:可出现在 ERP 页头平台切换器。
页头只展示已启用、且 `can_be_header_context = true` 的目标平台;来源信息仍可保存其平台标识。实现时可以使用三个布尔列,或统一的 `capabilities` JSONB,但后者必须在架构文档中给出固定 JSON Schema、默认值和校验规则。
### 5. 在线商品同步中的“未见”与归档
**状态:已确认(2026-09-26)。** 维护者选择以下规则,在线商品全量同步按此执行。
规则如下:
1. 一次**成功的全量同步**中未见某在线 SKU:仅首次写入 `missing_since`;不归档。
2. 之后连续第二次成功全量同步仍未见,或 `missing_since` 已超过 7 天:写入 `archived_at`,列表默认隐藏但可筛选查看。
3. 同步失败、部分同步或被取消:绝不修改 `missing_since`、`archived_at`。
4. 该 SKU 随后的成功同步再次出现:清空 `missing_since` 与 `archived_at`,恢复正常展示。
## P2:契约一致性优化
### 1. 删除的同步与异步响应
**状态:已决策,待统一约定更新。**
- 同步软删除成功返回 `204 No Content`。
- 涉及大量素材/衍生文件清理、需要异步任务的删除或清空操作允许返回 `202 Accepted` 与 `operation`。
应将此例外写入 `docs/api/conventions.md`,并在每个异步删除接口明确说明。
### 2. 平台市场、语言和币种能力的 JSON Schema
**状态:待技术设计确认。**
目前平台 API 返回的 `default_market_code`、`default_locale` 等字段可暂存于 `platforms.capabilities`,但必须定义统一 Schema,至少覆盖:默认市场、可用市场、默认语言、可用语言、可用币种,以及上述来源/目标/页头能力。
如平台能力会被频繁查询、筛选或由后台维护,后续可拆分为平台市场/语言/币种关联表;首期不得让各模块自行解释任意 JSON 字段。
### 3. 修改门店 Client ID 的边界
**状态:待产品确认。**
当前 API 契约禁止编辑 `Client ID`,这比最初“编辑店铺”需求更严格。二选一:
- 保持禁止:Client ID 变化视为新增授权,用户新建门店后停用/删除旧门店;
- 允许替换:要求同时提交新的 `Client ID` 与 API Key,服务端原子加密替换、清除验证状态并重新验证,验证失败不得使旧密钥与新 Client ID 形成混合状态。
无论选哪种,都不得只允许单独改 `Client ID`。
## 关闭记录
事项关闭时,在对应小节补充“确认日期、最终决策、影响的 SQL/API/测试文件”。不要直接删除历史结论,以保留设计决策轨迹。