docs: 归档天工·商品标签(OpenGoods)规划文档
新增 docs/planning/ 规划文档归档: - 00-final-plan: 最终规划(决策+架构+M0~M5任务清单) - 01-detailed-design-v2.0: 分类/单位/数据库/API/治理/采集/部署/众包 - 02-advanced-topics-v3.0: OpenAPI/全表DDL/数据契约/OFF映射/中国合规/测试/安全/图片/SLA/竞品 - history/: v0.1~v1.0 演进记录 更新 README 为项目介绍并链接规划文档。 Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
# 商品档案公益 API 系统 — 规划方案 (v0.1)
|
||||
|
||||
> 一个公益性质的网站/服务:**采集全网商品信息**,对外提供**商品参数查询 API**。
|
||||
> 核心原则:**只收集信息、只提供信息,不涉及任何购买、下单、比价导购等交易行为。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 项目定位与原则
|
||||
|
||||
| 维度 | 说明 |
|
||||
|------|------|
|
||||
| 定位 | 公益的"商品参数百科 / 商品档案库",类似商品界的 Wikipedia + 开放 API |
|
||||
| 提供什么 | 商品的客观参数(规格、型号、成分、能效、尺寸、条码等) |
|
||||
| **不提供什么** | 价格交易、加购物车、下单、跳转购买链接、联盟分佣、比价导购 |
|
||||
| 服务对象 | 第三方软件 / 开发者,通过 API 查询商品参数 |
|
||||
| 数据态度 | 客观、中立、可溯源(每条数据标注来源与采集时间) |
|
||||
|
||||
> ⚠️ 关于价格:建议**默认不收录价格**。价格属于交易属性,且实时性强、争议大。如果一定要做,只做"历史参考价"且明确标注来源时间,绝不提供购买入口。**这一点需要你确认。**
|
||||
|
||||
---
|
||||
|
||||
## 2. 系统总体架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────┐
|
||||
│ 数据来源 (Sources) │
|
||||
│ 官网/厂商 / 开放数据 / GS1 │
|
||||
│ 条码库 / 用户贡献 / 监管公开 │
|
||||
└──────────────┬──────────────┘
|
||||
│
|
||||
┌──────────────────────────▼──────────────────────────┐
|
||||
│ 采集层 Ingestion (Workers) │
|
||||
│ 爬虫调度 + 适配器 + 限速 + robots 合规 + 去重 │
|
||||
└──────────────────────────┬──────────────────────────┘
|
||||
│ 原始数据 (raw)
|
||||
┌──────────────────────────▼──────────────────────────┐
|
||||
│ 清洗/标准化 ETL (Normalize & Dedup) │
|
||||
│ 字段映射 / 单位归一 / 实体匹配 / 质量评分 │
|
||||
└──────────────────────────┬──────────────────────────┘
|
||||
│ 结构化商品档案
|
||||
┌──────────────────────────▼──────────────────────────┐
|
||||
│ 存储层 Storage │
|
||||
│ PostgreSQL(主) + 对象存储(图片) + 搜索引擎(检索) │
|
||||
└──────────────────────────┬──────────────────────────┘
|
||||
│
|
||||
┌──────────────────────────▼──────────────────────────┐
|
||||
│ 公开 API 服务 (FastAPI) │
|
||||
│ REST/JSON + 文档 + 限流 + 缓存 + API Key(可选) │
|
||||
└──────────────────────────┬──────────────────────────┘
|
||||
│
|
||||
┌──────────────▼──────────────┐
|
||||
│ 消费者:各种软件/开发者 │
|
||||
└─────────────────────────────┘
|
||||
```
|
||||
|
||||
分为四个相对独立的子系统:
|
||||
1. **采集子系统**(爬虫/适配器,离线运行)
|
||||
2. **数据处理子系统**(清洗、标准化、去重、质量评分)
|
||||
3. **存储子系统**(关系库 + 搜索 + 对象存储)
|
||||
4. **API 子系统**(对外只读公开 API + 文档站)
|
||||
|
||||
---
|
||||
|
||||
## 3. 核心数据模型(商品档案 Schema)
|
||||
|
||||
商品的本质是"一个实体 + 一组可扩展的参数"。建议采用 **核心字段 + 灵活属性(KV)** 的混合模型,以适配不同品类(手机、食品、家电、化妆品……参数差异极大)。
|
||||
|
||||
### 3.1 核心实体
|
||||
|
||||
```jsonc
|
||||
// Product 商品档案
|
||||
{
|
||||
"id": "uuid", // 内部唯一ID
|
||||
"gtin": "6901234567892", // 全球贸易项目代码(条码), 可空
|
||||
"name": "示例牌 1.5L 纯净水",
|
||||
"brand": "示例牌", // -> Brand 实体
|
||||
"manufacturer": "示例食品有限公司",
|
||||
"category": "饮料/包装水", // -> Category 树
|
||||
"model": "型号/SKU标识",
|
||||
"description": "客观描述, 非营销文案",
|
||||
"images": ["对象存储URL", ...],
|
||||
"attributes": [ // 灵活参数(见下)
|
||||
{"key": "容量", "value": "1.5", "unit": "L"},
|
||||
{"key": "保质期", "value": "12", "unit": "月"}
|
||||
],
|
||||
"identifiers": { // 其他标识
|
||||
"ean": "...", "upc": "...", "asin": "...", "mpn": "..."
|
||||
},
|
||||
"sources": [ // 数据溯源(每个字段可标来源)
|
||||
{"source_id": "...", "url": "...", "fetched_at": "2026-06-08T...", "field": "容量"}
|
||||
],
|
||||
"quality_score": 0.87, // 数据质量/可信度评分
|
||||
"status": "active|merged|deprecated",
|
||||
"created_at": "...", "updated_at": "..."
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 灵活属性 (EAV / JSONB)
|
||||
- 不同品类参数差异巨大,核心表存通用字段,品类专属参数存 `attributes`(PostgreSQL `JSONB`,可建 GIN 索引)。
|
||||
- 配合**品类参数模板**(Category Schema)约束某品类应有哪些参数,保证质量。
|
||||
|
||||
### 3.3 辅助实体
|
||||
- `Brand`(品牌)、`Manufacturer`(厂商)、`Category`(品类树)、`Source`(数据来源登记)、`AttributeDefinition`(参数字典:标准名/别名/单位)。
|
||||
- 实体去重/合并需要 `merge` 机制(同一商品多来源 → 合并为一条,保留溯源)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 数据采集策略(最关键、也最需合规)
|
||||
|
||||
### 4.1 来源优先级(从"最合规"到"需谨慎")
|
||||
1. **官方开放数据 / 标准库**:GS1 条码库、各国监管公开数据(能效标识、食品备案、药品/化妆品备案等)。✅ 最佳
|
||||
2. **厂商官网 / 官方规格表**:参数最权威。需遵守 robots.txt。
|
||||
3. **厂商/平台开放 API**:若有官方 API 走 API。
|
||||
4. **用户/社区贡献**:众包补全与纠错(带审核)。
|
||||
5. **第三方网页抓取**:⚠️ 合规风险最高,需严格遵守 robots、限速、只取客观参数、标注来源。
|
||||
|
||||
### 4.2 采集器设计
|
||||
- **适配器模式**:每个来源一个 adapter(解析规则独立、可热插拔)。
|
||||
- **调度**:任务队列(Celery / RQ / arq)+ 定时(cron)+ 增量更新。
|
||||
- **合规护栏**:尊重 `robots.txt`、礼貌限速、`User-Agent` 标识身份、错峰、缓存避免重复抓取。
|
||||
- **去重与匹配**:以 GTIN/条码为主键,无条码时用 (品牌+型号+关键参数) 做模糊匹配。
|
||||
|
||||
### 4.3 数据质量
|
||||
- 每个字段记录来源 + 时间;多来源冲突时按来源可信度加权。
|
||||
- 质量评分 `quality_score`:字段完整度 + 来源权威度 + 一致性。
|
||||
|
||||
---
|
||||
|
||||
## 5. 公开 API 设计(只读、RESTful)
|
||||
|
||||
基础原则:**只读、无副作用、无购买入口、稳定版本化、有文档**。
|
||||
|
||||
```
|
||||
GET /api/v1/products/{id} # 按内部ID查询商品档案
|
||||
GET /api/v1/products/barcode/{gtin} # 按条码(GTIN/EAN/UPC)查询 ★最常用
|
||||
GET /api/v1/products/search # 搜索: ?q=&brand=&category=&page=&size=
|
||||
GET /api/v1/products/{id}/attributes # 仅取参数
|
||||
GET /api/v1/brands / categories # 品牌/品类树
|
||||
GET /api/v1/sources/{id} # 数据来源说明(透明溯源)
|
||||
GET /healthz / /api/v1/openapi.json # 健康检查 / 机读文档
|
||||
```
|
||||
|
||||
设计要点:
|
||||
- **版本化** `/api/v1/`,破坏性变更升 `v2`。
|
||||
- **分页 + 字段筛选**(`fields=` 减少传输)。
|
||||
- **限流**:匿名按 IP 限流;可选 API Key 提升配额(免费,仅用于防滥用与统计)。
|
||||
- **缓存**:CDN + 服务端缓存(商品参数变化慢,缓存命中率高)。
|
||||
- **响应统一**:JSON,含 `data` / `meta`(分页) / `sources`(溯源)。
|
||||
- **开放协议**:数据采用开放许可(如 CC BY / ODbL),鼓励署名引用。
|
||||
- **自动文档**:FastAPI 自带 Swagger UI / ReDoc。
|
||||
|
||||
---
|
||||
|
||||
## 6. 技术选型建议
|
||||
|
||||
| 层 | 选型 | 理由 |
|
||||
|----|------|------|
|
||||
| API 框架 | **Python + FastAPI** | 与仓库定位一致、异步性能好、自带 OpenAPI 文档 |
|
||||
| 主数据库 | **PostgreSQL** (JSONB) | 关系 + 灵活属性兼得,GIN 索引支持检索 |
|
||||
| 搜索 | **OpenSearch / Elasticsearch / 或 PG 全文** | 商品名/参数全文与分面检索 |
|
||||
| 缓存 | **Redis** | 热点缓存 + 限流计数 + 任务队列后端 |
|
||||
| 采集任务 | **arq / Celery / RQ** | 异步调度爬虫与 ETL |
|
||||
| 爬虫 | **httpx + selectolax/BeautifulSoup**,动态页用 **Playwright** | 轻量为主,必要时浏览器渲染 |
|
||||
| 对象存储 | **S3 兼容 (MinIO / 云)** | 存商品图片 |
|
||||
| 部署 | **Docker + Compose**(初期) → K8s(规模化) | 渐进式 |
|
||||
| 文档站 | FastAPI 文档 + 静态站(MkDocs) | 开发者文档 |
|
||||
|
||||
> 如果你更偏好 Node.js / Go 也可以,我按你的偏好调整。仓库描述像是 FastAPI,所以我默认 Python。
|
||||
|
||||
---
|
||||
|
||||
## 7. 合规与法律(公益项目尤其重要)
|
||||
|
||||
- **爬取合规**:遵守 robots.txt、服务条款、合理限速;只采集**客观商品参数**,不抓取受版权保护的营销文案/评测原文(可链接来源)。
|
||||
- **数据来源透明**:每条数据可溯源,标注来源与时间,尊重原始来源。
|
||||
- **隐私**:只处理商品信息,不涉及个人数据(无 PII)。
|
||||
- **商标/品牌**:品牌名仅用于客观标识商品,不做背书或贬损。
|
||||
- **明确边界**:网站显著声明"仅提供信息、不提供购买、不构成消费建议"。
|
||||
- **数据开放许可**:选择 CC BY 4.0 或 ODbL,明确他人使用条款。
|
||||
- **下架机制**:提供来源方/权利方的纠错与下架联系渠道。
|
||||
|
||||
> 建议这块后续找法务/合规确认,我可以先把"合规护栏"写进采集器与站点声明。
|
||||
|
||||
---
|
||||
|
||||
## 8. 建议的实施路线图(分阶段,先跑起来再扩展)
|
||||
|
||||
**阶段 0 — 地基(先做)**
|
||||
- 仓库工程化:FastAPI 项目骨架、PostgreSQL、Docker Compose、CI、代码规范。
|
||||
- 定义核心数据模型 + 迁移。
|
||||
|
||||
**阶段 1 — MVP API**
|
||||
- 实现只读 API:按条码/ID 查询 + 搜索 + 自动文档。
|
||||
- 导入一批种子数据(用开放数据/手工录入几百条),让 API 真正可用。
|
||||
|
||||
**阶段 2 — 采集管线**
|
||||
- 1~2 个合规来源的 adapter + 调度 + 清洗/去重/入库。
|
||||
- 质量评分与溯源。
|
||||
|
||||
**阶段 3 — 规模化与开放**
|
||||
- 搜索引擎、缓存/CDN、限流、API Key、众包贡献与审核后台。
|
||||
- 开放数据许可与开发者文档站上线。
|
||||
|
||||
---
|
||||
|
||||
## 9. 需要你拍板的关键问题
|
||||
|
||||
1. **是否收录价格?**(建议默认不收录,只做客观参数)
|
||||
2. **首批聚焦哪些品类?**(如:食品/快消、3C 数码、家电…… 建议先聚焦 1~2 个品类把模型打磨好)
|
||||
3. **技术栈确认 Python + FastAPI 吗?**(还是有其他偏好)
|
||||
4. **数据来源**:你手上有没有已知的合规数据源 / 官方 API / 已有数据集?
|
||||
5. **首要交付**:先搭"可查询的 MVP API + 一批种子数据",还是先做"采集管线"?(建议先 MVP API)
|
||||
|
||||
---
|
||||
|
||||
> 这是 v0.1 规划草案,确认大方向后我会细化成可执行的工程任务,并开始搭建仓库骨架 + MVP。
|
||||
@@ -0,0 +1,203 @@
|
||||
# 商品档案公益 API 系统 — 规划方案 (v0.2)
|
||||
|
||||
> 公益网站/服务:**采集全网商品信息**,对外提供**商品参数查询 API**。
|
||||
> 原则:**只收集 + 只提供信息,不涉及任何购买/下单/比价导购**。
|
||||
> 本版根据你的反馈定稿四件事:① 收录**官方标准零售价(MSRP)** ② 首批聚焦**食品快消** ③ **Go(系统) + Python(采集)** 多语言架构 ④ 附**开放数据源清单**。
|
||||
|
||||
---
|
||||
|
||||
## 0. 你已确认的决策
|
||||
|
||||
| # | 决策 | 说明 |
|
||||
|---|------|------|
|
||||
| 1 | **价格 = 官方标准零售价 (MSRP)** | 厂商指导价/官方建议零售价,属**静态属性**,带来源+时间+币种标注;**不收录实时电商售价、不提供购买入口** |
|
||||
| 2 | **首批品类 = 食品快消 (Food & FMCG)** | 先把食品的数据模型打磨好(成分、营养、过敏原、规格、保质期…) |
|
||||
| 3 | **技术栈 = Go + Python** | Go 写对外 API/核心服务;Python 写采集/ETL/爬虫;通过 PostgreSQL + 消息队列解耦 |
|
||||
| 4 | **数据源 = 暂无,后期提供** | 本版先给出可立即接入的开放数据源清单 |
|
||||
|
||||
---
|
||||
|
||||
## 1. Go + Python 多语言架构(核心)
|
||||
|
||||
这是一个很经典且合理的组合。两端**不直接互相调用**,而是通过**共享数据库 + 消息队列**解耦,各自独立部署、独立扩展。
|
||||
|
||||
```
|
||||
┌────────────────────── Python 侧 (采集/数据) ──────────────────────┐
|
||||
│ │
|
||||
数据源 ─▶│ 采集 Workers (爬虫/适配器) ─▶ ETL 清洗/标准化/去重 ─▶ 入库 │
|
||||
│ httpx / Playwright / scrapy pandas / 规则引擎 │
|
||||
└───────────────────────────┬────────────────────────────────────────┘
|
||||
│ 写入
|
||||
┌───────▼────────┐ ┌──────────────┐
|
||||
│ PostgreSQL │◀──────▶│ 对象存储 S3 │ (商品图)
|
||||
│ (商品档案主库) │ └──────────────┘
|
||||
└───────▲────────┘
|
||||
│ 只读
|
||||
┌───────────────────────────┴────────────────────────────────────────┐
|
||||
│ Go 侧 (对外服务) │
|
||||
│ 公开 API (REST/JSON) + Redis 缓存/限流 + 搜索网关 + OpenAPI │
|
||||
│ Gin/Echo/Chi/标准库 │
|
||||
└───────────────────────────┬────────────────────────────────────────┘
|
||||
│
|
||||
各种软件 / 开发者消费
|
||||
```
|
||||
|
||||
### 1.1 职责划分
|
||||
|
||||
| 子系统 | 语言 | 职责 |
|
||||
|--------|------|------|
|
||||
| **公开 API 服务** | **Go** | 对外只读 API、限流、缓存、鉴权(可选 API Key)、检索网关、高并发承载 |
|
||||
| **采集 Workers** | **Python** | 每个数据源一个 adapter,抓取/调用 API、遵守 robots、限速、产出原始数据 |
|
||||
| **ETL / 数据处理** | **Python** | 清洗、字段映射、单位归一、实体去重与合并、质量评分 |
|
||||
| **调度 / 队列** | Python(worker) + Redis/消息队列 | 定时任务、增量更新、任务分发 |
|
||||
| **存储** | PostgreSQL + Redis + S3 | 主库 / 缓存+限流 / 图片 |
|
||||
| **检索** | 初期 PG 全文 → 后期 OpenSearch | 商品名/参数搜索与分面 |
|
||||
|
||||
### 1.2 为什么这样分?
|
||||
- **Go 做 API**:编译型、单二进制部署、并发模型适合高 QPS 的只读公益 API,运维简单。
|
||||
- **Python 做采集**:爬虫/解析/数据处理生态最强(scrapy、playwright、pandas),迭代快。
|
||||
- **解耦点 = 数据库**:Go 端**只读**主库(或读副本),Python 端负责写入。两端通过稳定的表结构约定协作,互不阻塞;将来任一端换语言/重写都不影响另一端。
|
||||
- **契约**:用数据库 schema + 一份内部「数据契约文档」固定字段含义,避免两端理解不一致。
|
||||
|
||||
---
|
||||
|
||||
## 2. 食品快消数据模型(细化)
|
||||
|
||||
食品参数差异大,沿用 **核心字段 + JSONB 灵活属性 + 营养结构化子表**。字段设计大量参考 Open Food Facts(成熟的食品开放库)。
|
||||
|
||||
### 2.1 商品主表 `product`
|
||||
```jsonc
|
||||
{
|
||||
"id": "uuid",
|
||||
"gtin": "6901234567892", // 条码(主键标识), EAN-13/UPC/EAN-8
|
||||
"name": "示例牌 巧克力榛子酱 400g",
|
||||
"brand": "示例牌", // -> brand
|
||||
"manufacturer": "示例食品有限公司", // 生产商
|
||||
"category": "食品/酱料/巧克力酱", // -> category 树 (可对齐 GS1 GPC / OFF categories)
|
||||
"net_content": {"value": 400, "unit": "g"}, // 净含量
|
||||
"country_of_origin": "中国",
|
||||
"shelf_life": {"value": 12, "unit": "月"}, // 保质期
|
||||
"storage": "常温避光保存",
|
||||
"images": ["S3_URL", ...],
|
||||
"msrp": { ... }, // 官方标准零售价, 见 2.3
|
||||
"food": { ... }, // 食品专属结构化字段, 见 2.2
|
||||
"attributes": [ {"key":"","value":"","unit":""} ], // 其余灵活参数(JSONB)
|
||||
"identifiers": {"ean":"", "upc":"", "off_id":""},
|
||||
"sources": [ {"source":"", "url":"", "fetched_at":"", "fields":["msrp"]} ],
|
||||
"quality_score": 0.0,
|
||||
"status": "active|merged|deprecated",
|
||||
"created_at": "", "updated_at": ""
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 食品专属字段 `food`(结构化)
|
||||
```jsonc
|
||||
{
|
||||
"ingredients_text": "白砂糖, 棕榈油, 榛子(13%), ...", // 配料表原文
|
||||
"ingredients": [ {"name":"白砂糖","rank":1}, ... ], // 解析后(可选)
|
||||
"allergens": ["坚果", "大豆", "乳"], // 过敏原
|
||||
"additives": ["E322 卵磷脂"], // 添加剂
|
||||
"nutriments": { // 营养成分(每100g/100ml)
|
||||
"energy_kj": 2252, "energy_kcal": 539,
|
||||
"fat_g": 30.9, "saturated_fat_g": 10.6,
|
||||
"carbohydrates_g": 57.5, "sugars_g": 56.3,
|
||||
"protein_g": 6.3, "salt_g": 0.107
|
||||
},
|
||||
"nutrition_basis": "per_100g", // per_100g | per_100ml | per_serving
|
||||
"serving_size": "15g",
|
||||
"is_vegetarian": null, "is_vegan": null, // 可空
|
||||
"nutri_score": "C", // 若引用 OFF
|
||||
"labels": ["无添加", "清真"] // 认证/标签
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 官方标准零售价 `msrp`(重点)
|
||||
```jsonc
|
||||
{
|
||||
"amount": 29.90,
|
||||
"currency": "CNY",
|
||||
"type": "msrp", // 仅 msrp/官方指导价; 不存实时电商成交价
|
||||
"region": "CN", // 适用地区(价格随地区不同)
|
||||
"source": "厂商官网/官方价目表",
|
||||
"source_url": "https://...",
|
||||
"effective_date": "2026-01-01", // 价格生效/采集时间
|
||||
"note": "官方建议零售价, 实际售价以零售商为准; 本站不提供购买"
|
||||
}
|
||||
```
|
||||
> 设计要点:价格是**带时间戳的历史快照**而非实时报价;明确 `type=msrp`、标注地区与来源;响应里附免责说明。**坚决不出现购买/跳转链接。**
|
||||
|
||||
### 2.4 辅助实体
|
||||
`brand` / `manufacturer` / `category`(品类树) / `source`(数据来源登记) / `attribute_definition`(参数字典: 标准名·别名·单位) / `merge_log`(实体合并记录, 保留溯源)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 可立即接入的开放数据源清单(食品快消)
|
||||
|
||||
按"合规性 / 可用性"排序。这些可作为**种子数据 + 采集 adapter 的首批对象**。
|
||||
|
||||
| 数据源 | 内容 | 许可 | 接入方式 | 备注 |
|
||||
|--------|------|------|----------|------|
|
||||
| **Open Food Facts** ⭐ | 全球食品(成分/营养/过敏原/Nutri-Score/图片) | **ODbL**(数据)+DbCL+CC-BY-SA(图) | REST API + **每夜全量 dump**(CSV/MongoDB, ~9GB) | 食品首选;可贡献回写;限速 15 req/min/IP(读) |
|
||||
| **USDA FoodData Central** ⭐ | 美国食品营养成分(含 Branded 品牌库) | **CC0(公共领域)** | REST API(需免费 key) + JSON/CSV 下载 | 营养数据权威;商业可用 |
|
||||
| **GS1 / Verified by GS1**(中国商品信息服务平台) | 条码→品牌/规格/厂商(官方登记) | 受限(需企业/接口授权) | 网页查询 + API(≤1000 GTIN/次) | **条码→商品**最权威来源;2亿+条;中国数据首选 |
|
||||
| **brocade.io** | 开放 GTIN/条码产品库 | 开源/开放 | 免费 REST(免鉴权读) | 数据量有限,可作补充 |
|
||||
| **3023data 等条码接口** | 中国物品编码+UPC+ISBN | 商业(0.005~0.02元/次) | REST API | **付费**,作兜底补全,非首选 |
|
||||
| 各国**监管公开数据** | 食品备案/标签/能效等 | 多为公开 | 各平台 | 后续按需逐个评估合规 |
|
||||
|
||||
**参考用开源项目(架构/数据模型借鉴,非数据源)**:
|
||||
- Open Food Facts Server (Product Opener) — 食品库的完整实现,可学其字段与流程
|
||||
- UnoPIM / PCMT / brocade.io — 开源 PIM / 商品主数据系统,借鉴建模与去重
|
||||
|
||||
> 建议:**先用 Open Food Facts 全量 dump 作种子数据**(直接有海量真实食品),再用 GS1/USDA 做补全与校验。这样 MVP 阶段就有真实可查的数据。
|
||||
|
||||
---
|
||||
|
||||
## 4. 公开 API 契约(Go 实现,只读)
|
||||
|
||||
```
|
||||
GET /api/v1/products/barcode/{gtin} # ★最常用: 条码查档案
|
||||
GET /api/v1/products/{id} # 内部ID查
|
||||
GET /api/v1/products/search # ?q=&brand=&category=&allergen_free=&page=&size=&fields=
|
||||
GET /api/v1/products/{id}/nutriments # 仅营养
|
||||
GET /api/v1/products/{id}/msrp # 仅官方零售价(含来源/时间/免责)
|
||||
GET /api/v1/brands | /categories # 品牌 / 品类树
|
||||
GET /api/v1/sources/{id} # 数据来源透明说明
|
||||
GET /healthz | /api/v1/openapi.json # 健康检查 / 机读文档
|
||||
```
|
||||
约定:版本化 `/v1/`;统一响应 `{data, meta(分页), sources(溯源)}`;分页 + `fields=` 裁剪;匿名按 IP 限流,可选免费 API Key 提配额;CDN+Redis 缓存(参数变化慢,命中率高);数据采用开放许可(CC BY / ODbL,注意 OFF 的 ODbL 传染性);**无任何购买/交易端点**。
|
||||
|
||||
---
|
||||
|
||||
## 5. 合规与边界(公益项目重点)
|
||||
|
||||
- **数据源许可要分清**:OFF 是 **ODbL**(衍生数据库需同样开放+署名),USDA 是 **CC0**(最宽松)。混用时要按最严格许可对外标注,避免许可冲突。
|
||||
- 爬取守 robots.txt / 服务条款,礼貌限速,标明 User-Agent 身份。
|
||||
- 只采**客观参数**;营销文案/评测原文不照搬(链接来源即可)。
|
||||
- 无个人数据(PII),只处理商品信息。
|
||||
- 站点显著声明:**仅提供信息、不提供购买、不构成消费建议**;价格为官方指导价历史快照。
|
||||
- 提供权利方**纠错/下架**联系渠道。
|
||||
|
||||
---
|
||||
|
||||
## 6. 里程碑(仍不写代码,仅规划,供确认)
|
||||
|
||||
| 阶段 | 目标 | 关键产出 |
|
||||
|------|------|----------|
|
||||
| **M0 工程地基** | 仓库骨架 | Go API 骨架 + Python 采集骨架 + PostgreSQL + Docker Compose + CI + 数据契约文档 |
|
||||
| **M1 数据模型** | 食品 schema | 主表/食品字段/MSRP/辅助实体 的迁移与字典 |
|
||||
| **M2 种子数据** | 有真实数据 | 导入 Open Food Facts dump(食品子集) + USDA 营养补全 |
|
||||
| **M3 MVP API (Go)** | 可查询 | 条码/ID/搜索/营养/MSRP + OpenAPI 文档 + 限流缓存 |
|
||||
| **M4 采集管线 (Python)** | 自动更新 | 1~2 个 adapter(OFF API / GS1) + ETL + 去重 + 质量评分 + 调度 |
|
||||
| **M5 开放与规模化** | 上线 | 搜索引擎 + CDN + API Key + 众包纠错后台 + 开发者文档站 + 开放数据许可 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 待你确认/补充
|
||||
|
||||
1. **价格范围**:确认只收「官方指导价 (MSRP)」、不碰实时电商价?(建议是)
|
||||
2. **OFF 的 ODbL 许可**:可接受(意味着我们对外的数据库也要用 ODbL 并署名 OFF)?还是更想用 CC0 来源(USDA)为主以保持宽松?
|
||||
3. **种子数据**:同意先导入 Open Food Facts 食品 dump 作为启动数据吗?
|
||||
4. **Go Web 框架偏好**:Gin / Echo / Chi / 标准库 net/http,有偏好吗?(无偏好我默认 Chi 或标准库,轻量)
|
||||
5. **地域范围**:首批面向中国市场商品,还是中外都收?(影响优先用 GS1-China 还是 OFF 全球库)
|
||||
|
||||
> 你确认后,我把它定为 v1.0 规划,并据此拆成可执行的工程任务清单(仍按你的节奏,需要我动手写代码时再开始)。
|
||||
@@ -0,0 +1,107 @@
|
||||
# 商品档案公益 API 系统 — 规划方案 (v1.0 定稿)
|
||||
|
||||
> 公益网站/服务:采集全网商品信息,提供商品参数查询 API。**只收集 + 只提供信息,不涉及任何购买行为。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 已锁定的决策
|
||||
|
||||
| # | 决策 | 结论 |
|
||||
|---|------|------|
|
||||
| 1 | 品类 | 首批 **食品快消** |
|
||||
| 2 | 价格 | 只收 **官方标准零售价 (MSRP)**,静态字段,带来源/时间/地区/币种 + 免责说明;**不收实时电商价、不提供购买入口** |
|
||||
| 3 | 技术栈 | **Go**(对外API/核心服务) + **Python**(采集/ETL/爬虫),经 PostgreSQL + Redis/队列解耦 |
|
||||
| 4 | 种子数据 | ✅ **先导入 Open Food Facts 食品 dump**,最快拥有真实数据 |
|
||||
| 5 | 数据许可 | 因采用 OFF → 对外数据库用 **ODbL** 并署名来源;CC0 来源(USDA)可自由混入 |
|
||||
|
||||
### 1.1 我先用的默认值(如不同意请指出,否则按此执行)
|
||||
- **Go Web 框架**:`chi` + 标准库 `net/http`(轻量、稳定、易维护)。
|
||||
- **地域范围**:先用 OFF **全球食品库**起步,后续接 **GS1-China** 补强中国市场数据。
|
||||
- **数据库迁移工具**:Go 侧用 `golang-migrate`(纯 SQL 迁移,两端共享同一套 schema)。
|
||||
- **部署**:初期 Docker Compose 一键起全套(Postgres/Redis/Go API/Python worker)。
|
||||
|
||||
---
|
||||
|
||||
## 2. 目标架构(定稿)
|
||||
|
||||
```
|
||||
数据源(OFF dump / OFF API / USDA / GS1)
|
||||
│
|
||||
▼ Python: 采集 adapters → ETL(清洗/归一/去重/质量评分)
|
||||
│
|
||||
┌────▼─────────┐ 图片 ┌──────────┐
|
||||
│ PostgreSQL │◀───────▶│ S3/MinIO │
|
||||
│ (商品档案主库)│ └──────────┘
|
||||
└────▲─────────┘
|
||||
│ 只读 (+Redis缓存/限流)
|
||||
▼ Go: 公开 REST API + OpenAPI 文档
|
||||
各种软件 / 开发者
|
||||
```
|
||||
|
||||
- **解耦契约**:两端通过共享 PostgreSQL schema + 一份《数据契约文档》协作,互不直接调用。
|
||||
- **Go 端只读主库**(或读副本);**Python 端负责写入**。
|
||||
|
||||
---
|
||||
|
||||
## 3. 仓库结构(计划,写代码时落地)
|
||||
|
||||
```
|
||||
goods/
|
||||
├── README.md
|
||||
├── docker-compose.yml # postgres + redis + minio + api + worker
|
||||
├── docs/
|
||||
│ ├── data-contract.md # 两端共享的字段契约
|
||||
│ └── openapi.yaml # API 契约
|
||||
├── migrations/ # 共享 SQL 迁移 (golang-migrate)
|
||||
├── api/ # Go: 对外只读 API
|
||||
│ ├── cmd/server/main.go
|
||||
│ ├── internal/{handler,store,model,middleware}/
|
||||
│ └── go.mod
|
||||
└── ingestion/ # Python: 采集 + ETL
|
||||
├── pyproject.toml
|
||||
├── adapters/{openfoodfacts,usda,gs1}.py
|
||||
├── etl/{normalize,dedup,quality}.py
|
||||
└── jobs/{seed_off_dump,scheduler}.py
|
||||
```
|
||||
|
||||
## 4. 数据模型 & API 契约
|
||||
(沿用 v0.2:`product` 主表 + `food` 食品字段 + `msrp` 价格 + 辅助实体;API 以 `GET /products/barcode/{gtin}` 为核心,全只读、无交易端点。详见 v0.2 附件。)
|
||||
|
||||
---
|
||||
|
||||
## 5. 可执行任务拆分(按里程碑,写代码时逐项落地)
|
||||
|
||||
**M0 — 工程地基**
|
||||
- [ ] 初始化 Go module (`api/`) + Python 项目 (`ingestion/`)
|
||||
- [ ] `docker-compose.yml`:Postgres + Redis + MinIO
|
||||
- [ ] CI(Go: build/vet/test;Python: ruff/pytest)
|
||||
- [ ] `docs/data-contract.md` 初版
|
||||
|
||||
**M1 — 数据模型**
|
||||
- [ ] `migrations/`:product / food / msrp / brand / manufacturer / category / source / attribute_definition / merge_log
|
||||
- [ ] JSONB + GIN 索引;gtin 唯一索引
|
||||
|
||||
**M2 — 种子数据 (Python)**
|
||||
- [ ] 下载 OFF 食品 dump(CSV)
|
||||
- [ ] `seed_off_dump`:字段映射 → 入库(含营养/成分/过敏原/图片URL)
|
||||
- [ ] USDA(CC0) 营养补全(可选)
|
||||
|
||||
**M3 — MVP API (Go)**
|
||||
- [ ] 路由 + handler:barcode / id / search / nutriments / msrp / brands / categories / sources
|
||||
- [ ] 统一响应、分页、`fields=` 裁剪、错误处理
|
||||
- [ ] Redis 缓存 + IP 限流;`/healthz` + OpenAPI 文档
|
||||
|
||||
**M4 — 采集管线 (Python)**
|
||||
- [ ] adapter:OFF API(增量更新)+ GS1(条码补全)
|
||||
- [ ] ETL:清洗/单位归一/去重合并/质量评分/溯源
|
||||
- [ ] 调度(定时增量更新)
|
||||
|
||||
**M5 — 开放与规模化**
|
||||
- [ ] 搜索引擎(PG 全文 → OpenSearch)、CDN 缓存
|
||||
- [ ] 免费 API Key(防滥用+统计)、众包纠错后台
|
||||
- [ ] 开发者文档站 + 开放数据许可声明 + 站点"不提供购买"声明
|
||||
|
||||
---
|
||||
|
||||
## 6. 下一步
|
||||
规划已定稿。**你说先不写代码,所以我暂停在这里**。等你说"开始",我就从 **M0 工程地基** 动手,搭好骨架后开 PR 给你看。也可以先只做某个里程碑(比如先 M0+M1 把骨架和数据模型立起来)。
|
||||
Reference in New Issue
Block a user