Files
2026-08-14 18:27:45 +08:00

345 lines
16 KiB
Markdown
Raw Permalink 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.
# Ozon Seller Kit 总体架构
> 状态:架构设计(待确认)
> 最后更新:2026-08-11
> 相关:[插件方案](./extension/plan.md) · [部署](./deployment.md) · [文案后端](./ai-copy-backend-plan.md)
---
## 1. 项目定位
围绕 Ozon 跨境上品的一套自用工具链,覆盖**采集 → 编辑 → 发布**全链路,货源来自 Ozon 竞品页(跟卖)与 1688/淘宝/拼多多(补素材)。
四个组成部分,各自独立可用、通过明确契约衔接:
| # | 部分 | 形态 | 状态 | 职责 |
| --- | ---------- | ------------------------- | ------- | ---------------------------- |
| ① | **工具台 v1** | 静态页(原生 JS + Tailwind CDN | ✅ 在用 | 计价、上品登记、水印、俄文文案。**冻结维护,不重构** |
| ② | **采集插件** | Chrome MV3 扩展 | 🔨 待开发 | Ozon/1688 商品页采集 → 落本地文件夹 |
| ③ | **发布工作台** | Web 应用 | 📋 待设计 | 导入本地文件夹 → 编辑/图片处理 → 提交发布 |
| ④ | **服务端** | FastAPI | 🔨 部分就绪 | AI 文案、图片处理、Ozon API 代理、凭证保管 |
**关键边界**:① 与 ③ 并存不互相替代。① 是已验证好用的轻量工具,③ 是面向"整商品发布"的新流程;③ 成熟后 ① 的计价器可能被吸收,但那是以后的事。
---
## 2. 目录结构
```
ozon-seller-kit/
├── server/ # ④ 服务端(FastAPI
│ ├── main.py
│ ├── api/ # ai / image / ozon / collection
│ ├── services/
│ ├── schemas/ # Pydantic = 数据契约真源
│ ├── config/
│ └── requirements.txt
├── web/ # ① 工具台 v1 —— 原地冻结,不改目录名
│ ├── ozonSeller.html
│ ├── js/ css/ imgs/
│ └── README.md # 标注「v1,仅修 bug」
├── extension/ # ② 采集插件(WXT + TS
│ ├── entrypoints/
│ ├── src/{profiles,collector,export,storage}/
│ └── package.json
├── studio/ # ③ 发布工作台
│ └── (技术栈待定,见 §8)
├── packages/
│ └── schema/ # 跨端共享契约(TS 类型 + JSON Schema
├── reference/
│ └── 1688-extension/ # 反编译参考资料,非本项目代码
├── docs/ # 全部文档集中于此
│ ├── architecture.md # ← 本文
│ ├── deployment.md
│ ├── ai-copy-backend-plan.md
│ ├── contracts/ # 数据契约说明
│ ├── extension/ # 插件方案
│ └── studio/ # 发布工作台方案
├── start.command
└── .env / .env.example
```
两处与现状不同,需要迁移(§9):后端从仓库根收进 `server/``seller-helper/` 拆解为 `reference/` + `docs/extension/`
### 2.1 为什么后端要收进 `server/`
现状后端散在仓库根(`main.py``api/``services/``schemas/``config/`)。四个部分并列后,根目录会同时出现 Python 包目录和三个前端项目目录,`api/` 这种名字看不出属于谁。收进 `server/` 后每个顶层目录一一对应一个部分。
代价:`start.command``docs/deployment.md` 里的启动路径要改,`.env` 加载路径 `parents[1]` 要跟着调。Python 内部 import 全是 `from api import ...` 这类顶层相对形式,只要工作目录切到 `server/` 就不受影响。
**这是唯一有破坏性的改动,建议在动** `studio/` **之前一次做完,不要拖到中途。** 如果你想零风险,也可以让后端留在根目录——架构其余部分不依赖这个决定。
### 2.2 为什么 `web/` 不改名
改名会动 `main.py` 的挂载路径、`start.command`、部署文档,收益只是"名字更清楚"。目录名保持 `web/`,在里面放一个 README 标注定位即可。
路由上两代共存:`studio/` 上线后占 `/studio``web/` 继续在 `/ozonSeller.html`。谁占根路径是路由配置问题,跟目录名无关。
---
## 3. 核心数据契约:商品文件夹
**这是整个架构最重要的一个决定。** 四个部分之间不直接调用彼此的代码,只认一个约定:磁盘上的「商品文件夹」。
```
儿童保温杯_316不锈钢/
├── product.json # 商品数据(唯一真源)
├── sources.json # 采集溯源:哪个平台、哪个 URL、什么时候
└── images/
├── main/ # main-001.jpg …
├── sku/ # sku-001-blue.jpg(文件名带规格名)
├── detail/ # detail-001.jpg …
└── video/
```
数据流因此变成:
```
插件 ──写──> 商品文件夹 ──读──> 发布工作台 ──调用──> 服务端 ──> Ozon API
1688 插件二次采集追加
```
三个好处:
1. **插件和工作台完全解耦**。插件不需要知道工作台存在,反之亦然。任一端重写不影响另一端。
2. **中间产物可见可改**。采集结果就是普通文件夹,能用 Finder 看、能手动补图、能备份、能在两台机器间拷。
3. **跨平台合并天然成立**。Ozon 采完,切到 1688 采同类商品,选同一个文件夹继续写入——就是往同一目录追加文件,不需要任何服务端参与。
### 3.1 product.json
结构对齐 Ozon `ProductAPI_ImportProductsV3`,但**不等于**它的请求体。区别在于采集阶段拿不到的字段留空,由工作台补齐:
| 字段 | 采集阶段 | 工作台补齐 |
| ------------------------- | ----------- | -------------------------- |
| `name` / `description` | ✅ 原文(可能是俄文) | 改写/翻译 |
| `images` | 本地相对路径 | 上传图床后换成公网 URL |
| `offer_id` | ❌ 空 | **必须填自己的货号**(跟卖场景下不能沿用竞品的) |
| `description_category_id` | ❌ 空 | 类目选择/推荐 |
| `attributes[].id` | ❌ 空 | 查类目属性字典映射 |
| 尺寸重量 | 参数表里有就带上 | 校验补全 |
| `price` / `old_price` | 采到竞品价,仅供参考 | 计价器算出 |
所以 product.json 有个 `_meta.stage` 字段标明它处在哪个阶段:`collected``edited``published`
契约细节见 `[docs/contracts/product-json.md](./contracts/product-json.md)`
### 3.2 契约真源与双语言实现
Pydantic`server/schemas/`)是真源,因为服务端最终要用它做校验。由此派生:
```
server/schemas/product.py (Pydantic)
├── 导出 JSON Schema ──> packages/schema/product.schema.json
│ │
│ └── 生成 TS 类型 ──> 插件 / 工作台
└── 服务端运行时校验
```
不上 codegen 流水线(单人项目不值得):插件端手写一份对应的 TS interface,配一个 fixture 文件双向跑一遍校验做契约测试。schema 变更时测试会红。
---
## 4. 各部分职责与边界
### ① 工具台 v1`web/`
**冻结。** 只修 bug,不加功能、不重构、不迁技术栈。它当前的价值是「已经好用」,任何改动都是风险。
新需求一律进 `studio/`。计价逻辑(`web/js/app.js`)后续会被 studio 复用——那时候是**读它、抄它的公式**,不是改它。
### ② 采集插件(`extension/`
只做四件事:识别页面、提取素材、分组、写文件夹。
不做:LLM 调用、图片处理、Ozon API、持有任何密钥。
一期只支持 Ozon(跟卖是第一优先级),1688 二期。详见 `[docs/extension/plan.md](./extension/plan.md)`
### ③ 发布工作台(`studio/`
导入本地文件夹 → 编辑 → 发布。三块能力:
- **表单编辑**product.json 各字段,类目选择,属性映射,计价(复用 v1 公式)
- **图片处理**:水印、白底、图内翻译、图生图 —— 重活走服务端
- **发布**:提交 Ozon 草稿,回填 `product_id`
### ④ 服务端(`server/`
唯一持有密钥的地方。当前有 `/api/ai/*`(文案);待补 `/api/image/*``/api/ozon/*`
**Ozon 发布有个硬约束值得提前知道**`ProductAPI_ImportProductsV3``images` 只接受**公网可访问的 URL**,Ozon 服务器会主动来拉。本地文件夹里的图必须先上传到图床/对象存储才能发布。这决定了服务端必须有图床能力,也决定了「本地文件夹」方案无法绕过服务端直接发布。
---
## 5. 端到端数据流
```
① 浏览 Ozon 竞品页
│ 点插件按钮 → 侧边栏打开 → 人工确认页面加载完 → 点采集
② 侧边栏表单化展示采集结果(可二次编辑),图片分组勾选
│ 选保存目录 → 导出
③ 本地商品文件夹(product.json + images/
│ (可选)切到 1688 采同类商品,选同一文件夹追加
④ 发布工作台:选择文件夹导入
│ 编辑字段 / 加水印 / 图生图 / 定类目 / 计价
⑤ 服务端:图片上传图床 → 属性字典校验 → 提交 Ozon 草稿
⑥ 回填 product_id 到 product.jsonstage 置 published
```
每一步的产物都落盘,中断了可以从任意一步接着来。
---
## 6. 技术栈
| 部分 | 技术栈 | 说明 |
| ----------- | ----------------------- | ------------------------------------ |
| ① web | 原生 JS + Tailwind CDN | 不动 |
| ② extension | WXT + React + TS strict | WXT 比 Plasmo 活跃 |
| ③ studio | 待定(见 §8 | |
| ④ server | FastAPI + Pydantic | 已有 |
| 共享 | pnpm workspace | 只为 `packages/schema` 共享,不上 turborepo |
pnpm workspace 的唯一目的是让插件和 studio 共用契约类型。`pnpm-workspace.yaml` 三行搞定,不引入构建编排复杂度。
---
## 7. 服务端演进
当前是无状态的:只有 AI 文案代理,没有数据库。按需要逐步加,不要一次上齐:
| 阶段 | 触发条件 | 要加什么 |
| --- | -------------- | -------------------------------------- |
| 现在 | — | 无状态,`/api/ai/*` |
| S1 | studio 要处理图片 | `/api/image/*`(水印/白底/翻译),仍无状态:收图返图 |
| S2 | 要发布到 Ozon | `/api/ozon/*` + 图床 + 类目字典缓存(SQLite 够用) |
| S3 | 图片处理变慢(图生图、视频) | 任务队列 + `/api/job/:id` 轮询 |
| S4 | 想要跨设备同步 | 商品库落库,本地文件夹降级为导入导出格式 |
**S1、S2 都不需要数据库**,类目字典用文件缓存即可。S4 是个大改动,只在真的有多设备需求时才做——本地文件夹方案的一个优点就是单机场景下完全不需要它。
---
## 8. 已定决策
### D1 · 后端迁入 `server/` ✅
代价是改 `start.command``settings.py``.env` 路径、`deployment.md`。Python 内部 import 不受影响(工作目录切到 `server/` 即可)。**这是唯一有破坏性的改动,在开工 studio 前一次做完。**
### D2 · studio 用 React + Vite + TS ✅
studio 的核心是"几十个字段的结构化表单 + 图片批处理",正是原生 JS 最吃力的场景。与插件同栈,图片处理组件和契约类型可两边复用。v1 的计价公式(`web/js/app.js`)抄过来即可,不改原文件。
### D3 · 保存用 File System Access API ✅
`chrome.downloads``filename` 只能是下载目录下的相对路径,不接受绝对路径或 `..`,因此无法满足"用户选择保存目录",也无法读回 `sources.json` 做去重。
File System Access 在 side panel(扩展页面上下文)可用,`showDirectoryPicker()` 拿到的 handle 存进 IndexedDB 后**跨会话免重复授权**,正好支撑"Ozon 采完切 1688 追加到同一文件夹"。`chrome.downloads` 保留为降级路径(用户拒绝授权时)。
细节见 `[docs/extension/plan-revision.md](./extension/plan-revision.md)` R1。
---
## 9. 迁移计划
一次性做完,中途不要停在半路:
```
① 后端收拢
main.py api/ services/ schemas/ config/ requirements.txt → server/
改 server/config/settings.py: parents[1] → parents[1](指向 server/.env 仍在仓库根则用 parents[2]
改 start.command: cd server 后再 uvicorn
改 docs/deployment.md 中所有路径
② 参考资料归位
seller-helper/1688-extension/ → reference/1688-extension/
③ 文档集中
seller-helper/docs/方案设计.md → docs/extension/legacy-v1.md
seller-helper/docs/方案设计-V2.md → docs/extension/legacy-v2.md
seller-helper/docs/插件开发方案.md → docs/extension/plan.md
seller-helper/extension-plan/IMPLEMENTATION_PLAN.md → 合并进 docs/extension/plan.md
④ 上一轮错放的代码归位
seller-helper/extension-plan/profiles-ozon.ts → extension/src/profiles/ozon.ts
seller-helper/extension-plan/download-implementation.ts → extension/src/export/download.ts
(建插件项目时再放,现在先留在 docs/extension/ 作为草案附件)
⑤ 删空目录
seller-helper/
⑥ web/ 加 README 标注 v1 冻结
```
`reference/1688-extension/` 要不要进 git:它是反编译产物,约 40 个 bundle。建议**加进** `.gitignore`,保留在本地即可——设计结论已经写进 `docs/extension/plan.md` §2,原始 bundle 只在需要再次查证时才用。
---
## 10. 里程碑(已调整优先级)
**插件先行:1688/淘宝 → Ozon**。理由见 `[docs/extension/1688-taobao-implementation.md](./extension/1688-taobao-implementation.md)`
| # | 内容 | 依赖 | 产出 | 工作量 |
| ------ | ---------------------------------- | --- | ------------------------------- | --- |
| **M0** | 目录迁移 + 文档集中 | — | ✅ 已完成,服务正常起 | — |
| **M1** | 插件:1688 采集引擎 | M0 | Console 里能跑 `scanCurrentPage()` | 4h |
| **M2** | 插件:淘宝 profile | M1 | 淘宝页面同样可用 | 1h |
| **M3** | 插件:Side Panel + File System Access | M2 | 生成完整商品文件夹到本地 | 4h |
| **M4** | 插件:sources.json 去重 | M3 | 二次采集追加不重复 | 1h |
| **M5** | 契约真源:product.json Pydantic | M0 | `server/schemas/product.py` | 2h |
| **M6** | 插件:Ozon profile 实测 | M4 | Ozon 选择器验证(需真实页面链接) | 2h |
| **M7** | studio:导入文件夹 + 表单编辑 | M5 | 能改能存 | 8h |
| **M8** | studio + server:图片处理 | M7 | 水印/白底可用 | 6h |
| **M9** | serverOzon 发布 | M8 | 草稿进 Ozon 后台 | 4h |
**M4 结束时插件功能完整**,可以采集 1688/淘宝商品到本地文件夹,跨平台追加不重复。M9 结束时全链路跑通。