feat: 开发采集插件
This commit is contained in:
@@ -0,0 +1,310 @@
|
||||
# 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.json,stage 置 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** | server:Ozon 发布 | M8 | 草稿进 Ozon 后台 | 4h |
|
||||
|
||||
**M4 结束时插件功能完整**,可以采集 1688/淘宝商品到本地文件夹,跨平台追加不重复。M9 结束时全链路跑通。
|
||||
|
||||
Reference in New Issue
Block a user