# 数据契约 (Data Contract) v0.1 本契约是 Go(API) 与 Python(ingestion) 两端共享的"事实约定",避免两端对字段含义理解不一致。 > 写入责任:**仅 Python (ingestion) 通过 ETL 写入数据库**;Go (API) **只读**。所有写入必须经过单位归一化与字段级溯源。 ## 1. 边界原则 - 系统只采集与提供**客观商品信息**;不包含任何购买/交易语义的字段或端点。 - 价格仅收录**官方建议零售价 (MSRP)** 的静态快照,必须带 `currency`/`region`/`source`/`effective_date`。 ## 2. 固定枚举 | 字段 | 取值 | |------|------| | `product.status` | `active` / `merged` / `deprecated` | | `food_detail.nutrition_basis` | `per_100g` / `per_100ml` / `per_serving` | | `unit.dimension` | `mass` / `volume` / `energy` / `count` / `ratio` / `length` / `duration` | | `source.license` | `ODbL` / `CC0` / `proprietary` / ... | | `product_image.kind` | `front` / `ingredients` / `nutrition` / `other` | ## 3. 单位规则 - 数值字段同时保存**原始值 + 单位**与**归一化值 + 基准单位**(canonical)。 - 质量 → `g`,体积 → `ml`,能量 → `kJ`(同时保留 `kcal`)。 - 归一化逻辑由 `ingestion/opengoods/units.py` 提供(纯函数,含测试),换算因子是唯一事实来源。 - 营养成分统一折算到品类模板规定的基准(`per_100g` / `per_100ml`)。 ## 4. 标识与可空性 - `product.gtin`:8/12/13/14 位数字,可空(无条码商品),非空时全局唯一。 - `product.quality_score` ∈ [0, 1]。 - 货币用 ISO 4217(`CNY` 等),国家/地区用简短代码(`CN` 等)。 ## 5. 溯源 (Provenance) - 每条数据通过 `product_source` 记录来源、URL、贡献字段、抓取时间与原始快照。 - 对外 API 在 `sources` 中透明返回来源与其许可。 ## 6. 版本 - 本契约随 schema 演进版本化;任何 schema 变更需同步更新:迁移(SQL) + 本契约 + `docs/openapi.yaml`。