Files
ozon-seller-kit/docs/v2/architecture.md
T

183 lines
11 KiB
Markdown
Raw 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 总体架构
> 状态:方案设计(待确认)
> 上游:[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 | 腾讯云公网 |