# 商品域数据模型与迁移 > 可执行 PostgreSQL DDL:[`sql/002_product-domain.sql`](./sql/002_product-domain.sql)。必须先执行 [`sql/001_foundation.sql`](./sql/001_foundation.sql)。 ## 1. 两个不能混用的商品域 ```text 工作空间 ├─ 采集箱商品(跨平台 Atlas 草稿) │ collection_items → products → product_variants │ └→ product_platform_profiles(每个平台一份) │ └→ product_variant_platform_listings(每个 SKU 首次导入状态) └─ 在线商品(平台 + 门店独有的同步镜像) platform_product_sync_runs → platform_listings → platform_listing_sync_snapshots ``` `products` / `product_variants` 只服务采集箱商品,保存来源、采购和跨平台可复用资料。`platform_listings` 则是目标平台、目标门店的实际商品镜像;它不能跨平台或跨门店复用,即使它关联了 Atlas SKU。`product_platform_profiles.market_code` 表示当前平台业务上下文,首期取平台默认 `RU`,不从门店派生。 类目/商品类型、属性定义和字典候选值是待迁移的**平台级**参考数据:同一平台所有门店共用,不跨 Ozon、Wildberries 等平台混用,也不在本阶段维护门店差异层。门店连接与商品/SKU 已填值仍按工作空间隔离。现有 `022_store_catalog_cache.sql` 的门店级缓存和 profile 外键继续有效,目标模型及迁移边界见 [`platform-product-reference-catalog.md`](./platform-product-reference-catalog.md)。 ## 2. 关键关系与状态 | 表 | 粒度 | 核心约束 | |---|---|---| | `collection_items` | 工作空间的一条采集箱记录 | 来源平台商品按 `workspace + source_platform + source_item_key` 幂等;手动商品无来源平台。`workspaces.collection_item_limit` 默认 1000,触发器在创建或恢复记录时以工作空间行锁保证不超限。 | | `products` / `product_variants` | 采集箱 SPU / SKU | SKU 删除是 Atlas 软删除,不下架任何平台商品。 | | `collection_asset_transfers` | 来源素材转存任务 | 来源 URL 先以持久化任务进入 Worker;成功后才创建 `media_assets` 与商品候选素材。失败可单独重试,不能把未下载素材伪装成资产。 | | `collection_seller_enrichment_observations` | Ozon Seller 本地观察结果 | 记录浏览器同源调用四个网页内部接口后的净化结果或不可用原因;不保存 Cookie、授权头或完整会话信息。 | | `product_platform_profiles` | 采集箱商品 × 目标平台 | 同一采集箱 SPU 在一个平台只有一份配置;A/B 平台的类目、属性、标题、价格和状态独立。 | | `product_variant_platform_listings` | 平台配置 × Atlas SKU | 保存 `offer_id`、首次导入状态、Ozon `product_id`、实际提交时的门店和价格。`imported` 后不可再次从采集箱提交。 | | `platform_listings` | 平台 × 门店 × Ozon 商品 SKU | 以店铺内 Ozon `product_id` / `offer_id` 唯一;保存 `visible`、库存、审核、错误和最新原始响应。 | 采集箱页面按**当前页头平台**汇总 `product_variant_platform_listings`:无成功导入 SKU 为“未上架”,部分成功为“已部分上架”,全部未删除 SKU 成功为“已上架”。这与 `platform_listings.visible` 完全分离:后者只代表 Ozon 当前是否可购买/可见。 ## 3. 媒体、AI、任务与审计 - `product_media_candidates` 是来源图、AI 图和手工上传图的候选池。 - `product_variant_listing_media` 是当前平台 SKU 最终选图与顺序;Ozon 首期最多 15 张由发布适配器校验,数据库不硬编码该上限,以支持未来平台差异。 - `media_derivatives` 记录“编辑图片 → 添加水印”生成的派生资产,固化水印模板版本;原图不被覆盖。 - `product_ai_tasks` 保存 AI 文案、类目、套图和尺寸图任务的输入快照、模型信息、输出和错误;`ai_category_suggestions` 保存可供用户确认的类目候选。 - `product_publish_jobs` / `product_publish_job_items` 是 BullMQ 之外的持久化发布事实;重试不能仅依赖 Redis/BullMQ 状态。 - `platform_product_sync_runs` / `platform_listing_sync_snapshots` 为 Ozon 在线商品全量同步保留运行记录和响应审计。 ## 4. 执行顺序 1. 在空库依次执行 `001_foundation.sql`、`002_product-domain.sql`。 2. 使用 NestJS migration runner 记录迁移版本;生产环境禁止手工在控制台执行。 3. 每个请求在成员授权后,在同一事务执行 `SET LOCAL app.workspace_id = ''`;API/Worker 使用专用非所有者、无 `BYPASSRLS` 的应用角色。两份迁移对业务表均 `FORCE ROW LEVEL SECURITY`,避免所有者静默绕过。 4. 商品发布、图片处理、AI、Ozon 同步均先落事务表,再投递 BullMQ;Worker 应能据表中的未完成任务恢复。