Files
2026-09-02 17:52:05 +08:00

81 lines
6.7 KiB
Markdown
Raw Permalink 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.
# V2.2 数据库与领域模型
> 状态:设计,尚未创建迁移。数据库单位统一为 `mm` 与 `g`。
## 1. 模型边界
```text
products(父商品 / SPU) 1 ─── N product_variants(可售 SKU / Ozon offer)
│ │
├── product_attributes ├── product_variant_media ── product_assets
├── product_assets(候选池) ├── product_attributes(scope=variant)
└── product_pricing_defaults └── variant_pricing_snapshots
```
保留现有 `products` 主键和采集来源字段,以便采集箱和历史链接继续有效;其单 SKU 价格、尺寸、`offer_id` 字段只作为迁移兼容层,V2.2 写路径不再以它们为事实来源。每个父商品至少有一条 `product_variants` 记录:单规格商品拥有默认 SKU,多规格商品拥有多个 SKU;两者不采用不同的数据结构。
## 2. 父商品 `products`
新增/规范的核心字段:
| 字段 | 说明 |
|---|---|
| `model_code` | 通用型号,所有 SKU 共用;可由 AI 建议,用户可编辑。 |
| `title_zh`、`name`、`description` | 中文标题、俄文标题、俄文简介。 |
| `rich_content` | 已验证的 JSON 富内容。 |
| `barcode` | 当前按业务决策作为通用字段。发布阶段若 Ozon/业务要求 SKU 级条码,再增加显式覆盖字段,不从图片或名称推断。 |
| `purchase_url`、`supply_note` | 采买地址和货源备注。 |
| `description_category_id`、`type_id` | Ozon 类目和商品类型。 |
| `pricing_defaults` | 默认利润率、贴单费、物流等级、划线价倍数、汇率等可继承计价参数。 |
| `package_*_default` | 默认包装物流规格;只作为 SKU 的可继承默认值。 |
| `physical_*_default` | 默认实物规格;只作为 SKU 的可继承默认值。 |
历史 `raw` 继续存原始采集文本/参数,绝不可将口径不明的原始“尺寸/重量”自动写入新规格字段。
## 3. SKU `product_variants`
| 字段组 | 字段 | 说明 |
|---|---|---|
| 身份 | `id`、`product_id`、`source_variant_key`、`variant_name`、`specs`、`sort_order`、`enabled` | `source_variant_key` 与来源平台联合唯一;显示名称可以变化或重复。 |
| 销售 | `offer_id`、`purchase_price`、`selling_price`、`old_price`、`currency_code` | `offer_id` 对启用 SKU 必须唯一;售价和划线价仅由定价确认或人工编辑写入。 |
| 包装物流 | `package_length_mm`、`package_width_mm`、`package_height_mm`、`shipping_weight_g`、`package_measurements_meta` | 用于试算、物流校验和 Ozon import。`null` 表示继承,不表示零。 |
| 实物 | `physical_length_mm`、`physical_width_mm`、`physical_height_mm`、`net_weight_g`、`physical_measurements_meta` | 用于尺寸图、规格展示、文案,绝不用于物流计算。 |
| 发布 | `ozon_product_id`、`ozon_sku`、`publish_state`、`published_at` | 为一 SKU 一 offer 的后续同步预留。 |
| 审计 | `created_at`、`updated_at`、`deleted_at` | SKU 采用软删除,防止丢失历史报价与外部映射。 |
两组 `*_measurements_meta` 至少存每个字段/字段组的 `status`(`confirmed`、`ambiguous`、`missing`)、来源、原始文本、确认时间。有效值按“SKU 覆盖 → 父商品默认值”逐字段合并;两组规格独立合并。这里的 `null` 仅表示某个可继承字段未覆盖父商品默认值;绝不表示 SKU 记录不存在,也不以此判断商品是否为单规格。
## 4. 动态属性 `product_attributes`
类目不同且将来可能持续增加属性,不能靠不断扩展 `products` 列。使用结构化属性表:
| 字段 | 说明 |
|---|---|
| `id`、`product_id`、`product_variant_id` | 通用属性只填 `product_id`;SKU 属性还填所属 `product_variant_id`。 |
| `scope` | `common` 或 `variant`;数据库约束与两个外键一致。 |
| `attribute_key`、`attribute_name` | 本地稳定键和最近一次展示名称。 |
| `ozon_attribute_id`、`complex_id` | 已映射时记录 Ozon 属性身份。 |
| `values` | JSON 数组,保存文本与可选 `dictionary_value_id`,能表达单值、多值、数值与布尔。 |
| `source`、`status` | `collected`/`ai`/`manual` 与 `confirmed`/`ambiguous`/`missing`。 |
动态属性 schema 来自 Ozon:先由父商品的 `description_category_id + type_id` 调用 `/v1/description-category/attribute`,再按返回的 `id`、`type`、`is_required`、`is_collection`、`max_value_count`、`dictionary_id` 和 `is_aspect` 渲染与校验。`dictionary_id > 0` 时,值通过属性值字典/搜索接口确认 `dictionary_value_id` 后保存。
通用属性包括品牌、型号、主题标签及默认的类目共有属性。变体属性包括颜色、颜色名称以及 Ozon schema 标记 `is_aspect=true` 的所有属性;`is_aspect` 是默认归属,不是硬编码限制。用户或采集规则可把某个非 `is_aspect` 属性(例如按容量销售的商品的容量)标记为 `variant` scope,并为每个 SKU 保存不同值。`specs` 仅是来源规格的原始/展示快照,不能替代已确认的属性值。
## 5. 素材与媒体选择
`product_assets` 保存一次资产事实:`product_id`、可空 `product_variant_id`、`media_type`(image/video)、`source_group`(collected_main/collected_sku/collected_detail/generated/upload)、原始/当前 URL、尺寸、生成任务/规格快照及来源信息。若采集平台无法稳定给出 SKU 归属,`product_variant_id` 必须为 `null`。
新增 `product_variant_media` 表保存每个 SKU 的已选媒体,而不是复制资产:`product_variant_id`、`asset_id`、`role`(image/video/video_cover)、`sort_order`、`selected_at`。同一商品级素材可安全地被多个 SKU 选用;同一 SKU 的排序独立。发布时仅取该 SKU 已选图片,并执行 Ozon 的图片数量、HTTPS 可访问性等校验。
## 6. 定价快照
`variant_pricing_snapshots` 记录不可变的确认结果:SKU、输入参数、合并后的包装物流规格、公式版本、结果、告警、汇率、`calculated_at`、确认人/来源。SKU 表可缓存最新快照 ID 以加速展示;导出或上架时服务端必须以有效包装规格重新校验,不能信任浏览器传回的价格结果。
## 7. 迁移原则
1. 每个历史 `products` 记录创建一个默认 SKU,复制原 `offer_id`、价格和 `pricing`。
2. 历史 `weight/depth/width/height` 迁入默认 SKU 的包装物流规格,因为旧字段只服务于试算;实物规格标记 `missing`。
3. 历史素材先保留为商品级候选素材;不根据 `variant_name` 倒推 SKU 绑定。
4. 新读路径优先 `product_variants`;在迁移完成前,旧字段只读兼容,禁止双向覆盖。