Files
atlas-seller-kit/docs/project/HANDOFF.md
T

117 lines
14 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.
# Atlas Seller Kit 交接说明
> 更新:2026-09-02。此文是新 AI 对话、架构讨论与开发工作的首读入口。
## 1. 项目定位
这是一个全新的云端产品,不是 `ozon-seller-kit` 的本地版重构。目标用户可拥有多个门店,每个门店只能绑定一个平台;平台自身可支持多个市场、国家、语言和币种。因此语言、币种、类目和发布规则不能写死为 Ozon 或中文/俄文。
当前已完成 pnpm monorepo 初始化:包含 Web、NestJS API、BullMQ Worker、WXT 浏览器扩展、共享 API 契约、数据库包、本地基础设施 Compose 与依赖锁文件。API 仅实现健康检查;Web 已具备完整前端框架(布局、路由、主题)和登录/注册页面,业务页面均为占位;Worker 与扩展为可运行骨架。尚未实现业务模块、迁移执行器、数据库 schema、鉴权或实际部署。不要从旧项目复制 SQLite 模型、无鉴权 API、旧 `/trial/:id` 或商品编辑页组件。可选择性复用已经验证过的纯计价公式、采集扩展思路和 AI 任务经验,但必须先适配多租户和云端边界。
当前运行时基线:Node 24.20.0、pnpm 11.25.0、PostgreSQL 18.6、Redis 7.4.11、MinIO `RELEASE.2025-09-07T16-13-09Z`;Web 默认端口为 `8100`,API 默认端口为 `8200`,扩展 dev server 默认端口为 `8110`(仅本地开发用),Worker 无 HTTP 端口。完整目录、依赖边界与版本表见 [`architecture/project-structure.md`](../architecture/project-structure.md) 和 [`architecture/technology-and-deployment.md`](../architecture/technology-and-deployment.md)。
### 1.1 开发进度(2026-09-02)
今日完成三项工作,全部通过 typecheck、生产构建,并经浏览器或启动实测:
**Web 前端框架(`apps/web`)**
- 参照 `ozon-seller-kit/studio` 搭建:紫色主题(`colorPrimary #8b5cf6`、圆角 8)、`index.css` CSS 变量、可折叠侧边栏 + 吸顶页头 + 移动端 Drawer 的 `MainLayout`、`@` 路径别名、`StrictMode` 入口。
- 主题显式 `fontSize: 14`;输入类控件默认高度 32→34(`controlHeight`)、小尺寸 24→26(`controlHeightSM`);body 字号同步 14px。
- 依赖使用最新稳定版:React 19.2.8、antd 6.6.2,新增 `@ant-design/icons` 6.3.4;沿用仓库精确版本号约定。
- 左侧菜单按 [`requirements/account-store-watermark.md`](../requirements/account-store-watermark.md) 的导航约定:在线商品(默认首页)、采集箱、店铺管理、水印管理、定价工具,均为占位页;另有菜单外的商品 AI 编辑页 `/products/:id`。
- 基础设施:`services/api.ts`(axios 封装 + 统一错误提取)、`config/env.ts`(`VITE_` 变量)、统一占位组件 `components/PagePlaceholder`。
- Web tsconfig 覆盖 base 的 `module: Node16` 为 `ESNext + bundler`(base 面向 NestJS;Node16 会要求相对导入带扩展名);TypeScript 7 已移除 `baseUrl`,`paths` 直接相对 tsconfig 解析为 `"@/*": ["./src/*"]`。
**注册与登录页面(契约:[`api/auth.md`](../api/auth.md))**
- `/login`、`/register` 两页共用 `AuthLayout`(品牌视觉与主布局一致)。注册字段:显示名称(选填 ≤80)、邮箱、密码、确认密码;登录失败统一 401 文案,注册重复邮箱 409 落到邮箱字段提示。
- 会话基础:access token 仅内存持有(`services/authToken.ts`),不进入任何持久化存储;`api.ts` 拦截器自动附加 Bearer 头,401 时用 refresh cookie 换新 token 并重放一次(并发去重),刷新失败整页跳转 `/login`。
- 实测发现并修复:antd v6 中空值会同时触发 `required` 与 `type: 'email'` 两条错误,已改为非空才校验格式的 `emailFormatRule`(`utils/validators.ts`)。
- 浏览器实测通过:表单校验、页面互链、API 未启动时的错误提示路径。密码复杂度按契约不在前端硬编码,仅提示以服务端校验为准。
- 留待 API 认证模块就绪后:接入真实 `/api/auth/*` 调用、主布局路由守卫、刷新页面后的会话恢复;auth 类型届时迁移至 `@atlas/contracts`。
**Worker 与扩展骨架修复**
- Worker:`ioredis` 是 BullMQ 的可选 peer 依赖,pnpm 严格隔离下必须由应用显式声明,已新增 `ioredis 6.0.0`;`main.ts` 改为显式构造 IORedis 实例并设置 `maxRetriesPerRequest: null`(原生 ESM 运行必需,也是后续 BullMQ Worker 的硬性要求)。`tsx` dev 与 `node dist/main.js` 两种运行方式均验证可连接本地 Redis。
- 扩展:WXT dev server 从默认的 3000–3010 漂移改为固定 `8110`(`EXTENSION_PORT` 可覆盖,`strictPort` 开启);`.output/` 构建产物已加入 `.gitignore` 并移出 git 跟踪。端口约定同步更新至交接、部署与项目结构三份文档及 `.env.example`。
## 2. 已确认产品决策
| 主题 | 决策 |
|---|---|
| 商品模型 | 每个商品是一个 SPU,且始终至少有一条 SKU;单规格商品使用默认 SKU,多规格商品使用多条 SKU。 |
| 平台可售单元 | 一个 SKU 对应一个独立平台 offer;Ozon 首个平台中对应 `/v3/product/import.items[]` 的一项和独立 `offer_id`。 |
| 通用属性 | 标题、品牌、型号、主题标签、简介、条形码、采买地址、货源备注及未来商品级属性;类目和平台属性属于独立的平台发布配置。首期不做富内容。 |
| SKU 属性 | SKU 名称、图片、货号、采购价、售价、划线价、包装重量和尺寸、商品重量和尺寸、商品颜色、颜色名称等。首期不支持视频。 |
| 型号/货号 | 型号(`model`)是父商品通用字段;`offer_id` 是当前平台下的每个 SKU 字段。采集时两者可为空;首次上架前必须由用户填写,系统不从标题、规格或来源 SKU 自动生成。被成功导入的 `offer_id` 作为历史事实锁定。 |
| 规格 | 实物规格与包装物流规格严格分离;尺寸图只读取实物规格,计价/物流/发布只读取包装规格。 |
| 继承 | 可继承字段的 `null` 表示该字段没有覆盖父商品默认值,不表示 SKU 不存在、名称为空或商品为单规格。 |
| 尺寸图 | 必须逐 SKU 生成,任务保存 SKU ID 和实物规格快照。 |
| 定价 | SKU 上点“定价”打开弹窗,以有效包装数据计算;用户确认后回填 SKU 销售价和划线价。 |
| 编辑体验 | 新商品 AI 编辑页取代旧商品编辑页;旧试算页不再追加多 SKU 功能。 |
| 采集插件 | 采集 Ozon、1688、淘宝、天猫详情页;未登录只显示登录入口,已登录显示“编辑上架 / 采集商品 / 进入 ERP”。采集箱为工作空间共用,采集记录不关联目标平台或门店;用户进入 ERP 编辑时,按页头当前平台(首期默认 Ozon)取得该平台发布配置并预选默认店铺。A/B 平台的上架状态独立。详情见 [`requirements/collector-browser-extension.md`](../requirements/collector-browser-extension.md)。 |
| 采集 SKU | 只有来源给出稳定 SKU/组合证据时创建多个 SKU;不能把规格轴做笛卡尔积。没有专属 SKU 图时,真实 SKU 继承父商品默认图而不复制资产。 |
| 媒体 | 采集主图/详情图是商品候选池;来源明确给出 SKU、或可靠的规格轴值(如颜色)与图片关系时才自动绑定。其余素材由编辑页人工选择。 |
| 发布与在线商品 | 商品采集、编辑、定价、AI 媒体和首次导入至 Ozon 后台是核心闭环。正式发布使用官方 Seller API,按一 SKU 一 import item/offer 执行并轮询结果;首期不传库存或仓库,用户在 Ozon 后台设置库存。已导入 SKU 不可再次上架,未上架 SKU 仍可首次上架;SPU 在当前平台汇总为未上架/已部分上架/已上架。在线商品由异步 Ozon API 同步,按 Ozon 商品 SKU 展示,亦包含非 Atlas 发布商品。 |
## 3. Ozon 已核对结论
仓内旧项目的 `docs/ozon-seller-api/04-product-import.md` 记录:Ozon `/v3/product/import` 每个 item 都有独立 `offer_id`、价格、包装尺寸/重量和图片,尺寸/重量不能为零;单次最多 100 项。`03-category-attributes.md` 记录类目属性的 `is_aspect=true` 表示变体属性。
因此 Ozon 适配器应以“一 SKU 一 import item/offer”为最小稳定单位。现有资料没有可强制把多个 item 合并为一个 Ozon 前台变体组的 API 契约,不能依赖自动归并;这是未来 Ozon 联调阶段要在真实店铺或沙盒验证的能力。
## 4. 云端架构底线
1. 使用 PostgreSQL;所有业务行必须受 `workspace_id` 或可安全追溯至工作空间的外键约束。
2. 首期注册后静默创建一个个人工作空间,并只建立一个 `owner` 成员;不展示工作空间、成员、角色或店铺级权限管理。后续有团队协作需求时再扩展。
3. 门店只能绑定一个平台,不能跨平台使用;市场/国家、默认语言、支持语言和支持币种属于平台能力配置,不属于门店。门店保留已确认的默认计价币种与加密凭据;上述信息均不得写进商品核心表。
4. 本地素材使用 MinIO;共享测试和生产素材使用七牛 Kodo,不使用应用服务器本地目录作为持久存储。
5. AI、生图、导出、采集转存和发布使用 Redis + BullMQ 队列/Worker,任务可重试、可恢复且携带工作空间与 SKU 上下文。关键可重试写操作使用持久化幂等记录;异步任务与业务事实在同一 PostgreSQL 事务写入 Transactional Outbox,再由 Dispatcher 投递队列。Redis/BullMQ 不作为业务事实唯一来源。
6. 用户界面语言、采集源语言、商品编辑语言和发布目标语言相互独立;文案及属性值需要支持多语言版本。
7. 一期实现插件中显式开启的 Ozon Seller 网页本地观察:在用户浏览器的已登录 Seller 标签页调用四个已记录内部接口,并仅上传净化结果;不得提取完整、保存或上传 Cookie,不得阻塞标准采集、不得替代官方 Seller API 发布或把未验证经营数据视为本店事实。加密保存 Cookie 仅作为未来二级实验能力预留。
建议的核心层级:
```text
User → Workspace → Membership / Role
→ Store → Platform connection / default currency
→ Product (SPU) → ProductVariant (SKU)
→ attributes / media / pricing snapshots / tasks
```
## 5. 已冻结的第一阶段 API 契约
第一阶段 HTTP API 的接口范围已讨论完成,当前状态为**设计冻结、业务接口尚未实现**。仓库已有 NestJS API 启动骨架及 `GET /health`,它不构成任何已实现的业务契约。后续编码以 [`docs/api/`](../api/README.md) 为唯一 HTTP 契约来源;旧 [`product/api.md`](../product/api.md) 仅作历史背景,不能作为实现依据。
- 覆盖账户认证、平台/门店、水印与素材、定价、浏览器采集/采集箱、商品编辑/首次发布、在线商品读取与同步。
- 所有接口遵循统一鉴权、工作空间隔离、页头平台上下文、金额字符串、错误格式、`Idempotency-Key`、`If-Match` 和异步 `operation` 约定。
- 关键异步动作必须在同一事务写入业务记录、`operations`(如需用户可见进度)和 `outbox_events`;Dispatcher 至少一次投递 BullMQ,Worker 必须幂等。
- DDL 已通过临时隔离 PostgreSQL 实例执行验证;API 契约已完成文档评审。这不表示 NestJS 模块、迁移执行器或 Worker 已实现。
仍需在对应模块开始编码前完成的 P1/P2 决策和数据模型补丁,集中记录在 [`reviews/implementation-readiness-open-items.md`](../reviews/implementation-readiness-open-items.md)。
## 6. 下一步建议
项目初始化已完成;下一步进入实现准备,而不是继续扩大 API 范围:
1. 以 `001_foundation.sql`、`002_product-domain.sql` 建立可重复执行的迁移执行器,并按数据库角色/RLS 约束验证本地环境。
2. 在 API 建立配置校验、认证、工作空间上下文和事务包装器;任何工作空间查询前固定 `SET LOCAL app.workspace_id`。
3. 建立 `operations`、幂等请求和 Outbox Dispatcher 的第一个集成测试闭环。
4. 在开始商品编辑/在线同步模块前,关闭评审文档中的 P1 事项:同商品归属约束、未映射属性持久化、乐观锁 Repository 规则、平台能力 Schema;并确认在线商品归档策略和 Client ID 编辑边界。
5. 优先实现账户、平台上下文、门店、素材上传的纵向最小闭环,再接入采集箱和商品编辑;浏览器扩展仅在采集 API 稳定后实现实际解析器。
6. Web 侧:认证 API 就绪后把登录/注册接入真实 `/api/auth/*`,补主布局路由守卫与刷新后的会话恢复,auth 类型迁移至 `@atlas/contracts`。
## 7. 文档导航
- [文档总索引](../README.md)
- [第一阶段 HTTP API 索引](../api/README.md)
- [API 统一约定](../api/conventions.md)
- [基础模块数据模型与 DDL](../architecture/foundation-data-model.md)
- [商品领域数据模型与 DDL](../architecture/product-domain-data-model.md)
- [幂等与 Transactional Outbox](../architecture/transactional-outbox-and-idempotency.md)
- [数据库角色与 RLS](../architecture/database-security.md)
- [实现前待决与待落地事项](../reviews/implementation-readiness-open-items.md)
- [浏览器采集插件需求与技术方案](../requirements/collector-browser-extension.md)
- [技术栈、异步任务与部署方案](../architecture/technology-and-deployment.md)