134 lines
10 KiB
Markdown
134 lines
10 KiB
Markdown
# 技术栈、异步任务与部署方案
|
||
|
||
> 状态:已确认。本文定义首期技术选型和环境边界;具体 Docker Compose、CI/CD、密钥和云资源参数在实施前补充为运行手册。
|
||
|
||
## 1. 已确认技术选型
|
||
|
||
| 层级 | 选型 | 当前版本 / 镜像 | 职责 |
|
||
|---|---|---|---|
|
||
| 前端 | React、TypeScript、Vite、Ant Design、React Router、Axios | React 19.2.8;TypeScript 7.0.2;Vite 8.2.2;Ant Design 6.6.2;Router 7.18.3;Axios 1.20.0 | 延续 `ozon-seller-kit/studio` 的前端技术路线,构建卖家工作台。 |
|
||
| 主后端 | NestJS、TypeScript | NestJS 12.0.1;TypeScript 7.0.2 | 认证、门店、商品/SKU、定价、平台适配、任务编排和 HTTP API。 |
|
||
| 关系数据库 | PostgreSQL | `postgres:18.6-alpine`(local) | 业务事实来源:用户、隐藏工作空间、门店、商品、报价、任务记录和审计。 |
|
||
| 缓存与队列 | Redis、BullMQ | `redis:7.4.11-alpine3.21`(local);BullMQ 6.3.4 | 待执行任务、延迟/重试、进度和限流;不作为业务事实来源。 |
|
||
| 对象存储(本地) | MinIO | `minio/minio:RELEASE.2025-09-07T16-13-09Z` | 本地开发存放图片和文件,使用 S3 兼容接口。 |
|
||
| 对象存储(生产) | 七牛云 Kodo | 生产及共享测试环境存放图片和文件。Kodo 的基础 S3 兼容能力用于上传、下载、删除和短时访问链接。 |
|
||
| 浏览器扩展 | WXT、React | WXT 0.21.4;`@wxt-dev/module-react` 1.2.2;React 19.2.8 | 在来源商品详情页运行采集器。 |
|
||
| 运行时与构建 | Node.js、pnpm、Turborepo、Prettier | Node 24.20.0;pnpm 11.25.0;Turbo 2.10.12;Prettier 3.9.6 | 固定本地/CI 运行时,管理 workspace、任务编排和格式校验。 |
|
||
| 运行与编排 | Docker、Docker Compose | Docker Compose local 基础依赖 | 本地一键启动依赖;首期服务器部署 API、Worker、Redis 和反向代理。 |
|
||
|
||
不将旧项目的 FastAPI 服务作为新项目运行时依赖;旧项目的 Ozon 资料、计价规则、采集经验和前端技术路线可作为参考或选择性复用。
|
||
|
||
代码仓库采用 pnpm workspace monorepo:Web、API、Worker 与浏览器扩展位于独立 `apps/*`,跨端 API 契约和数据库迁移基础设施位于 `packages/*`。目录和依赖边界见 [项目结构与运行边界](./project-structure.md)。
|
||
|
||
版本由根目录 `package.json`、`.nvmrc` 与 `infra/compose.yaml` 锁定;镜像不使用 `latest`。pnpm 11 启用供应链保护:仅允许 `esbuild` 执行安装构建脚本,`msgpackr-extract` 保持禁用。
|
||
|
||
## 2. 服务边界
|
||
|
||
```text
|
||
Browser
|
||
│ HTTPS
|
||
▼
|
||
Reverse proxy / CDN
|
||
├─ Web:Vite 构建的静态前端
|
||
└─ NestJS API
|
||
├─ PostgreSQL:业务数据、任务状态、审计与规则快照
|
||
├─ Redis:BullMQ 队列与短期缓存
|
||
├─ Kodo / MinIO:原图、处理图、AI 图和导入文件
|
||
└─ BullMQ Worker:水印、AI、平台同步、上架与重试
|
||
```
|
||
|
||
API 进程只处理短请求、鉴权、事务和任务投递。耗时或会失败重试的工作必须由独立 Worker 执行,不能在 HTTP 请求内直接完成。
|
||
|
||
## 3. Redis 与 BullMQ 的使用规则
|
||
|
||
Redis 是高速的临时基础设施;BullMQ 使用 Redis 保存队列中的任务及其调度/重试信息。两者都不是商品、门店或任务最终结果的唯一存储位置。
|
||
|
||
| 任务 | API 的动作 | Worker 的动作 | PostgreSQL 应保存的内容 |
|
||
|---|---|---|---|
|
||
| 水印/图片处理 | 创建任务并投递队列 | 读取原图、处理、上传派生图 | 任务状态、输入图片、输出图片、错误、重试次数 |
|
||
| AI 生图/智能规划 | 创建任务并投递队列 | 调用模型、轮询或处理回调、保存结果 | 模型/提示词版本、输入、结果、费用/用量、人工确认状态 |
|
||
| Ozon 同步 | 创建同步任务 | 限速调用 API,分页拉取并更新数据 | 同步游标、开始/完成时间、错误和结果摘要 |
|
||
| SKU 发布 | 创建发布任务 | 按店铺限流发布、查询结果、失败重试 | 发布状态、平台任务 ID、请求/响应摘要和错误 |
|
||
|
||
实现要求:
|
||
|
||
1. 所有长任务在同一 PostgreSQL 事务中创建业务任务/`operation` 和 `outbox_events`;事务提交后由独立 Dispatcher 投递 BullMQ,避免“数据库已提交但任务未投递”。详见 [`transactional-outbox-and-idempotency.md`](./transactional-outbox-and-idempotency.md)。
|
||
2. 任务必须幂等:相同 SKU 的一次发布任务重试,不得重复创建平台商品。
|
||
3. 重试必须有次数上限、指数退避和可见错误;Ozon 等第三方 API 需按店铺/API 限额控制并发。
|
||
4. Redis 可丢失或重建,Worker 应能根据 PostgreSQL 中的未完成任务恢复投递;业务结果不只存在于 Redis。
|
||
|
||
## 4. 对象存储策略
|
||
|
||
对象存储保存二进制文件;PostgreSQL 只保存对象键、文件哈希、MIME 类型、尺寸、归属关系和处理状态,不保存大图片的二进制内容。
|
||
|
||
### 4.1 概念
|
||
|
||
- **Bucket(存储桶)**:一个独立文件仓库,例如 `atlas-prod-assets`。
|
||
- **Object Key(对象键)**:桶内文件的唯一键,例如 `workspaces/{workspaceId}/products/{productId}/original/{assetId}.jpg`。
|
||
- **S3 兼容**:以 Bucket、Object Key、上传/下载/删除和预签名 URL 这一类通用 API 操作对象存储。MinIO 与七牛 Kodo 均可用于此模式;应用只依赖首期所需的基础能力。
|
||
|
||
### 4.2 文件分层与访问控制
|
||
|
||
建议对象键按业务归属分层:
|
||
|
||
```text
|
||
workspaces/{workspaceId}/
|
||
watermarks/{assetId}/
|
||
products/{productId}/original/{assetId}
|
||
products/{productId}/processed/{assetId}
|
||
products/{productId}/ai-generated/{assetId}
|
||
imports/{taskId}/{filename}
|
||
```
|
||
|
||
规则:
|
||
|
||
1. Bucket 默认私有;用户原图、模板图、导入文件和 AI 结果不长期公开。
|
||
2. 前端上传使用服务端签发的短时上传凭证或预签名 URL;浏览器不保存永久 Kodo 密钥。
|
||
3. 前端预览/下载使用短时访问 URL,或由 API 受控转发。
|
||
4. Ozon 发布由 Worker 用受控服务端凭据读取文件;不因平台发布而把私有原图改为公共读。
|
||
5. 对象删除应先检查数据库引用;商品、水印软删除或保留期结束后,由后台清理任务物理删除。
|
||
|
||
### 4.3 本地、测试与生产
|
||
|
||
| 环境 | 对象存储 | 说明 |
|
||
|---|---|---|
|
||
| local | Docker 中的 MinIO | 每位开发者独立数据,可随时用种子数据重建。 |
|
||
| staging | 七牛 Kodo 独立 Bucket | 家/公司联调和验收使用,严禁与生产 Bucket 混用。 |
|
||
| production | 七牛 Kodo 独立 Bucket | 保存真实用户文件,凭据只在生产运行环境中配置。 |
|
||
|
||
首期不在普通单台云服务器自建生产 MinIO:自行承担磁盘冗余、备份、故障恢复、TLS、升级和监控,不能因“部署了 MinIO”而获得托管对象存储的可靠性。
|
||
|
||
## 5. 环境与数据库策略
|
||
|
||
| 环境 | PostgreSQL | 目的 |
|
||
|---|---|---|
|
||
| local | 本机 Docker PostgreSQL | 日常开发、迁移编写和自动化测试;每位开发者独立。 |
|
||
| staging | 云端独立 PostgreSQL | 家/公司共同联调、演示和测试店铺验证。 |
|
||
| production | 云托管 PostgreSQL | 真实业务数据;仅生产服务通过私网或受控网络访问。 |
|
||
|
||
不能把生产数据库作为开发数据库,也不建议所有日常开发直接共用同一云端数据库。数据库结构通过迁移文件保持一致;演示数据通过版本化 seed 脚本保持一致。迁移顺序必须是 local → staging → production,并在生产前备份和验证回滚方案。
|
||
|
||
数据库权限分为迁移角色与应用角色:迁移角色拥有表并只在部署迁移时使用;API/Worker 的应用登录角色只获业务表所需的 DML 权限,不拥有表且没有 `BYPASSRLS`。RLS 策略使用每个事务设置的 `app.workspace_id`;业务表启用并强制 RLS。具体初始化和权限清单见 [`database-security.md`](./database-security.md)。
|
||
|
||
## 6. AI 能力边界
|
||
|
||
首期 AI 智能规划、文案和生图均通过 Provider Adapter 调用云模型 API。NestJS 负责权限、上下文组装、结构化结果校验、任务状态和人工确认;模型不得直接改价、发布或修改门店数据。
|
||
|
||
若未来出现 GPU 推理、自托管扩散模型、大规模 OCR/CV、训练或微调,再增加独立 Python AI Worker。Python Worker 通过队列或内部 API 接收任务,主业务后端仍保持 NestJS,避免过早维护双语言的主业务系统。
|
||
|
||
## 7. Docker 与首期部署
|
||
|
||
当前仓库的 `infra/compose.yaml` 只编排本地基础依赖:`postgres`、`redis`、`minio`;`web`、`api`、`worker` 与 `extension` 通过 `pnpm dev` 在宿主机并行 watch。Web 默认监听 `8100`,API 默认监听 `8200`,Web 的 `/api` 代理目标为 `http://localhost:8200`;Worker 不监听 HTTP 端口。
|
||
|
||
后续若将本地应用进程也容器化,Compose 至少应覆盖:`web`、`api`、`worker`、`postgres`、`redis`、`minio`。前端开发也可单独使用 Vite 热更新,并将 `/api` 代理至本地 API。
|
||
|
||
首期云端 Docker Compose 编排:`api`、`worker`、`redis`、`reverse-proxy`;PostgreSQL 使用云托管实例,图片使用七牛 Kodo。每个环境使用独立 `.env`/密钥管理配置,密钥不提交 Git、不进入前端构建产物和日志。
|
||
|
||
在规模、可用性或多机部署出现明确瓶颈前,不引入 Kubernetes。
|
||
|
||
## 8. Ozon Seller 浏览器会话边界
|
||
|
||
一期浏览器插件可以在用户已登录的 `seller.ozon.ru` 标签页内,以同源请求调用已列白名单的四个网页内部接口,保存净化后的观察结果。该模式使用浏览器自动附带的会话 Cookie,但不提取完整 Cookie、不上传、不在 Atlas 保存,也不能交给云端 Worker 执行。
|
||
|
||
未来若要支持加密保存浏览器 Cookie,必须作为独立的二级实验能力:按门店验证会话归属,使用信封加密和可撤销的专用密钥记录,任务队列仅传密钥记录 ID,并逐接口限制用途。此类 Cookie 会话不替代官方 Seller API 的发布、库存或状态同步凭据。
|