feat: 开发采集、采集箱和商品编辑功能

This commit is contained in:
Joey
2026-08-15 22:17:26 +08:00
parent c61d1a3154
commit 36357843d0
130 changed files with 18005 additions and 12 deletions
+182
View File
@@ -0,0 +1,182 @@
# V2 总体架构
> 状态:方案设计(待确认)
> 上游:[V2 总览](./README.md) · V1 [`architecture.md`](../architecture.md)
> 前置阅读:建议先读 [`capability-inventory.md`](./capability-inventory.md) 了解现状资产。
---
## 1. 组件与职责
```
┌───────────────┐ Bearer Token ┌──────────────────────────────────────────────┐
│ Chrome 插件 │ ────────────────▶ │ 服务端 server/FastAPI
│ extension-v2 │ POST /api/materials│ │
Ozon/1688 采集)│ │ ├─ api/ 采集/商品/类目/店铺/发布/图片/汇率 │
└───────────────┘ │ ├─ services/ Ozon / DeepSeek / 套图 / 七牛 │
▲ │ ├─ models/ SQLAlchemy ORM + Alembic │
│ 远程配置 / 埋点 │ └─ jobs/ 异步:图下载转存 / 发布轮询 │
┌───────┴───────┐ │ │
│ 采集配置文件 │ └──────┬───────────────┬───────────────┬────────┘
│(可热更) │ │ │ │
└───────────────┘ ┌──────────▼──┐ ┌───────▼────────┐ ┌─────▼─────────┐
│ PostgreSQL │ │ 七牛对象存储 │ │ Ozon Seller API│
│ 商品/店铺/任务│ │ 源图/生成图/水印 │ │ Client-Id+Api-Key│
└─────────────┘ └────────────────┘ └───────────────┘
│ REST /api/*
┌─────────────┴──────────────┐
│ studio/React + Vite + antd)│
│ 采集箱 / 商品编辑 / 发布 / 店铺 / 导出 │
└────────────────────────────┘
```
四个部分与 V1 一致(插件 / studio / server / 采集配置),但 **studio 的职责显著扩大**(从单页图生图 → 完整工作台),**server 从无状态代理 → 有状态业务中枢**。
---
## 2. 核心边界(延续 V1,补充 V2)
1. **密钥只放服务端**DeepSeek / DASHSCOPE / 七牛 / Ozon 店铺 Client-Id+Api-Key 全部只在 server 侧;插件和 studio 只持有一个长期 Bearer Token。
2. **插件仍做纯采集**:不调 LLM、不做图片处理、不碰 Ozon API;只是把「写本地文件夹」换成「上传落库」。
3. **服务端是唯一出网口(对 Ozon/云厂商)**:插件 background 与服务端通信,studio 与服务端通信;谁都不直连 Ozon。
4. **商品数据单点真源 = `products` 表**`_` 前缀的本地扩展字段(`_raw`/`_pricing`/`_images`)仍保留在 JSONB 里,提交 Ozon 前按 V1 契约剥离。
5. **图片一律七牛公网 URL**:数据库里存七牛 URL,不存本地路径、不存源站 URL(源站 URL 仅存 `product_assets.source_url` 做溯源)。
---
## 3. 技术栈
| 部分 | 技术栈 | 说明 |
|---|---|---|
| server | FastAPI + SQLAlchemy 2.0async+ Alembic + httpx | 沿用现状 FastAPIORM 用 SQLAlchemy 2.0 async |
| DB | PostgreSQL 16(腾讯云 CDB | JSONB 存 attributes/raw/pricing |
| 任务 | 轻量:先 DB 轮询 + asyncio 后台任务;量大再上 Redis/Celery | 图下载转存、发布轮询都是 IO 密集 |
| 对象存储 | 七牛云 Kodo | 源图转存 + 生成图 + 水印结果 |
| 缓存 | 类目/属性字典 → PostgreSQL 表 + 内存 LRU;可选 Redis | 见 `ozon-publish.md` §3 |
| studio | React 19 + Vite 7 + antd 6 + react-router 7 | 沿用现状;加 react-query 或 zustand 管状态 |
| extension | WXT + React + TS | 沿用;改造 export → upload |
| 鉴权 | JWT(短期)+ Bearer TokenMVP 单用户,预留 `users` 表 | 见 §6 |
**与 V1 的差异**:唯一新增重依赖是 **SQLAlchemy + Alembic****七牛 SDKqiniu**。任务队列一期不引入 Redis/Celery,用「DB 状态机 + 后台协程」即可(单人自用规模)。
---
## 4. 目录结构(目标)
```
ozon-seller-kit/
├── server/
│ ├── main.py # 应用入口,挂载路由 + studio 静态
│ ├── api/ # 按域拆:collection / products / categories /
│ │ │ # shops / publish / export / image / ai / fx / auth
│ ├── services/ # ozon_client / deepseek / image_suite / qiniu / pricing
│ ├── models/ # SQLAlchemy 模型(见 database.md
│ ├── schemas/ # Pydantic(接口契约真源)
│ ├── jobs/ # 后台协程:下载转存 / 发布轮询
│ ├── migrations/ # Alembic
│ └── config/ # settings.py + models.yaml(沿用)
├── studio/ # 工作台(多页)
│ └── src/
│ ├── pages/
│ │ ├── collection/ # 采集箱列表
│ │ ├── product/ # 商品编辑(核心)
│ │ │ └── components/ # PricingPanel / CopyPanel / ImagePanel /
│ │ │ # CategoryPicker / AttributeMapper / PublishPanel
│ │ ├── publish/ # 发布任务 / 状态
│ │ ├── shops/ # 店铺管理(Client-Id / Api-Key
│ │ ├── export/ # CSV 导出
│ │ └── ai-image/ # 保留:智能修图(wanx2.1-imageedit,改名)
│ ├── services/ # 与 /api/* 对齐的客户端
│ ├── stores/ # zustand:商品编辑态 / 采集箱筛选
│ └── pricing/ # 从 v1 抄来的计价纯函数(不改原文件)
├── extension-v2/ # 采集插件(改造:上传落库)
│ └── src/
│ ├── messaging/ # 消息层(plan.md §9
│ ├── api/ # 后端客户端(仅 background
│ └── collector/ profiles/ # 沿用采集引擎
├── web/ # v1 工具台,冻结
├── docs/
│ ├── v2/ # ★ 本文档集
│ └── ...V1 文档)
└── .env / .env.example
```
---
## 5. 状态机:商品生命周期
V1 是 `collected → edited → published`。V2 因为「落库 + 异步发布」,扩展为:
```
collected ──(进入编辑)──> editing ──(填写完整)──> ready ──(点发布)──> publishing
┌───────────────────────────────────────┤
▼ ▼
imported(成功) failed(失败,可改后重发)
│ ▲
└────── published ──(可归档)──> archived ─┘
collected 插件刚上传,只有素材与原文
editing 用户正在编辑(计价/文案/图片/类目)
ready 必填项齐全,可发布
publishing 已提交 ImportProductsV3,拿到 task_id,等待轮询
published 轮询 imported 成功,回填 product_id
failed 轮询返回 errors / 校验失败;可回到 editing 修复后重发
archived 手动归档(软删)
```
- 每步都落库,刷新/换设备不丢。
- `publishing` 由发布任务表(`publish_tasks`)驱动,服务端轮询 `/v1/product/import/info` 更新状态。
- 状态定义详见 [`database.md`](./database.md) §2.2。
---
## 6. 鉴权与多租户
**MVP(单人自用)**`.env` 里配一个 `APP_TOKEN`,插件 options 页和 studio 登录页填同一个值,请求头 `Authorization: Bearer <APP_TOKEN>`。服务端校验后签发短期 JWT,后续请求用 JWT。
**预留升级路径(不影响 MVP**`users` 表 + `shops.user_id` 已留好外键,未来要做多用户 SaaS 只需补注册/登录 + 按 `user_id` 过滤查询,schema 不用改。
| 层 | MVP | 升级 |
|---|---|---|
| 身份 | 单个 `APP_TOKEN` | `users` 表 + 密码哈希 |
| 会话 | 短期 JWT`Authorization: Bearer` | 同左,加刷新令牌 |
| 店铺归属 | 全部归当前用户 | 按 `user_id` 隔离 |
| 密钥保护 | 店铺 Api-Key 服务端 AES-GCM 加密落库 | 同左 |
---
## 7. 部署拓扑(腾讯云)
```
┌────────────── nginx (443) ──────────────┐
│ /api/* → uvicorn (127.0.0.1:8800) │
浏览器/插件 ─────▶ │ / → studio 静态资源(构建产物)│
│ /ozonSeller.html → web/v1,可选保留) │
└─────────────────────────────────────────┘
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
PostgreSQLCDB 七牛 Kodo(对象存储) 外部 APIOzon/DeepSeek/DashScope
```
- **单进程部署**FastAPI 同源托管 studio 构建产物(与 V1 托管 web/ 同思路),`/api` 走 nginx 反代到 uvicorn。
- **环境变量**`.env` 在服务器上维护(不入 git),新增 `APP_TOKEN` / `DATABASE_URL` / `QINIU_*` / `APP_BASE_URL`
- **CORS**:同源托管时 `CORS_ORIGINS` 留空;开发期 studio 跑 8900 时用 Vite 代理 `/api`,无需 CORS。
- 详见 [`migration.md`](./migration.md) §5。
---
## 8. 与 V1 的差异小结
| 维度 | V1 | V2 |
|---|---|---|
| 契约真源 | 磁盘「商品文件夹」 | `products` 表 + 七牛 |
| 插件出口 | File System Access 写盘 | `POST /api/materials` 落库 |
| studio | 单页图生图 | 多页工作台 |
| server | 无状态代理(ai/image | 有状态业务中枢(DB/七牛/Ozon/任务) |
| 发布 | 预留 `/api/ozon/*` 占位 | 完整发布链路 + 任务轮询 |
| 图片 | 图生图(wanx2.1)+ 前端水印 | 智能修图 + 电商套图 + 七牛托管 |
| 数据导出 | v1 登记表 CSV(前端) | 服务端统一 CSV 导出 |
| 部署 | 本机 127.0.0.1 | 腾讯云公网 |