# 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.0(async)+ Alembic + httpx | 沿用现状 FastAPI;ORM 用 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 Token;MVP 单用户,预留 `users` 表 | 见 §6 | **与 V1 的差异**:唯一新增重依赖是 **SQLAlchemy + Alembic** 和 **七牛 SDK(qiniu)**。任务队列一期不引入 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 `。服务端校验后签发短期 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,可选保留) │ └─────────────────────────────────────────┘ │ ┌─────────────────────┼─────────────────────┐ ▼ ▼ ▼ PostgreSQL(CDB) 七牛 Kodo(对象存储) 外部 API(Ozon/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 | 腾讯云公网 |