first commit
This commit is contained in:
@@ -0,0 +1,364 @@
|
||||
# 智绘微刻后端技术栈建议方案
|
||||
|
||||
> 本文档面向「智绘微刻」小程序团队,提供从 0 到 1 搭建后端服务的完整技术选型建议。
|
||||
> 撰写日期:2026-07-27
|
||||
> 适用场景:初期 MVP 上线(日活 < 1万),兼顾未来扩展。
|
||||
|
||||
---
|
||||
|
||||
## 一、总体架构概览
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 微信小程序端 │
|
||||
│ Taro 3.6 + React + Local Storage(当前无后端缓存阶段) │
|
||||
└──────────────────────────┬──────────────────────────────────┘
|
||||
│ HTTPS / JSON
|
||||
┌──────────────────────────▼──────────────────────────────────┐
|
||||
│ Nginx(反向代理 + 静态文件) │
|
||||
│ ┌─────────────┬─────────────┐ │
|
||||
│ │ SSL 证书 │ 负载均衡 │ │
|
||||
│ └─────────────┴─────────────┘ │
|
||||
└──────────────────────────┬──────────────────────────────────┘
|
||||
│
|
||||
┌──────────────────────────▼──────────────────────────────────┐
|
||||
│ FastAPI (Python 3.11+) │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ 用户/订单 │ │ 词云生成 │ │ 设计清单 │ │
|
||||
│ │ REST API │ │ 异步任务 │ │ REST API │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
└──────────────────────────┬──────────────────────────────────┘
|
||||
│ │ │
|
||||
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
|
||||
│ PostgreSQL │ │ Redis │ │ MinIO │
|
||||
│ (主数据库) │ │ 缓存/队列 │ │ 对象存储 │
|
||||
└─────────────┘ └─────────────┘ └─────────────┘
|
||||
│
|
||||
┌──────▼──────┐
|
||||
│ Celery │
|
||||
│ 异步任务队列 │
|
||||
│ (词云渲染) │
|
||||
└─────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、技术选型与理由
|
||||
|
||||
### 1. API 框架:FastAPI (Python)
|
||||
|
||||
| 维度 | 选型 | 理由 |
|
||||
|------|------|------|
|
||||
| 框架 | **FastAPI** | 自动生成 OpenAPI/Swagger 文档;异步原生支持(`async/await`);类型提示驱动开发,与前端 TS 思维一致 |
|
||||
| 替代方案 | Django / Flask / Go-Gin | Django 太重、Flask 需手写异步、Go 学习成本高;团队若熟悉 Python,FastAPI 是最佳平衡点 |
|
||||
| Python 版本 | **3.11+** | 性能优化显著(CPython 3.11 比 3.10 快 10~25%),且支持 `TaskGroup` 等现代并发原语 |
|
||||
|
||||
**核心职责**:
|
||||
- 用户登录(微信 OAuth2 → JWT Token)
|
||||
- 商品/品类/价格/工期配置读取
|
||||
- 设计清单 CRUD
|
||||
- 订单创建/支付回调/状态流转
|
||||
- 词云生成任务投递(异步)
|
||||
- 文件上传预签名 URL(MinIO)
|
||||
|
||||
---
|
||||
|
||||
### 2. 数据库:PostgreSQL 15+
|
||||
|
||||
| 维度 | 选型 | 理由 |
|
||||
|------|------|------|
|
||||
| 主数据库 | **PostgreSQL 15+** | 开源、稳定、JSONB 支持灵活存储设计稿元数据;PostGIS 扩展未来可做配送区域 |
|
||||
| ORM | **SQLAlchemy 2.0** + Alembic | 成熟、类型安全、迁移脚本自动化 |
|
||||
| 连接池 | asyncpg | FastAPI 原生异步兼容 |
|
||||
|
||||
**核心表结构设计(MVP 版)**:
|
||||
|
||||
```sql
|
||||
-- 用户表(微信授权)
|
||||
CREATE TABLE users (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
openid TEXT UNIQUE NOT NULL,
|
||||
unionid TEXT,
|
||||
nickname TEXT,
|
||||
avatar_url TEXT,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 商品品类表(与前端 productConfig 同步)
|
||||
CREATE TABLE products (
|
||||
id TEXT PRIMARY KEY, -- notebook-small, coaster, penbox ...
|
||||
name TEXT NOT NULL,
|
||||
desc TEXT,
|
||||
price INT NOT NULL, -- 单位:分,避免浮点
|
||||
lead_time TEXT,
|
||||
description TEXT,
|
||||
images TEXT[], -- 图片 URL 数组
|
||||
mask JSONB NOT NULL, -- {shape, width, height, borderRadius}
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 设计清单表
|
||||
CREATE TABLE designs (
|
||||
id TEXT PRIMARY KEY, -- DSG + 时间戳
|
||||
user_id UUID REFERENCES users(id),
|
||||
product_id TEXT REFERENCES products(id),
|
||||
count INT NOT NULL DEFAULT 1,
|
||||
status TEXT NOT NULL CHECK (status IN ('undesigned','designing','ordered')),
|
||||
design_data JSONB, -- {imageSrc, imagePos, category}
|
||||
order_id TEXT,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 订单表
|
||||
CREATE TABLE orders (
|
||||
id TEXT PRIMARY KEY, -- ORD + 时间戳
|
||||
user_id UUID REFERENCES users(id),
|
||||
design_id TEXT REFERENCES designs(id),
|
||||
product_id TEXT REFERENCES products(id),
|
||||
product_name TEXT NOT NULL,
|
||||
count INT NOT NULL,
|
||||
unit_price INT NOT NULL, -- 单位:分
|
||||
total_price INT NOT NULL,
|
||||
status TEXT NOT NULL CHECK (status IN ('pending','paid','shipping','done','cancelled')),
|
||||
sku TEXT,
|
||||
paid_at TIMESTAMPTZ,
|
||||
shipped_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 词云生成任务表(追踪异步任务状态)
|
||||
CREATE TABLE wordcloud_jobs (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID REFERENCES users(id),
|
||||
base_image_key TEXT NOT NULL, -- MinIO 对象 key
|
||||
names TEXT[] NOT NULL,
|
||||
status TEXT NOT NULL CHECK (status IN ('queued','processing','completed','failed')),
|
||||
result_key TEXT,
|
||||
error_msg TEXT,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
completed_at TIMESTAMPTZ
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. 缓存与消息队列:Redis 7+
|
||||
|
||||
| 用途 | 说明 |
|
||||
|------|------|
|
||||
| **JWT 黑名单 / Session 缓存** | 用户登出时令牌失效 |
|
||||
| **_rate limiting_** | 防止词云接口被刷(每用户 5 次/分钟) |
|
||||
| **Celery Broker** | Redis List 作为 Celery 任务队列 |
|
||||
| **热点数据缓存** | 商品配置表、首页轮播数据(TTL 10 分钟) |
|
||||
|
||||
---
|
||||
|
||||
### 4. 异步任务:Celery + Redis
|
||||
|
||||
| 场景 | 处理方式 |
|
||||
|------|----------|
|
||||
| **词云图片生成** | 用户上传底图 → 投递 Celery Task → C++ 布局引擎 / Python 词云库生成 → 结果上传 MinIO → WebSocket/轮询通知前端 |
|
||||
| **订单支付回调处理** | 微信 notify_url → FastAPI 接收 → Celery Task 异步更新订单状态、发送通知 |
|
||||
| **批量邮件/短信** | 发货通知、营销短信异步发送 |
|
||||
|
||||
**为什么不用 RabbitMQ?**
|
||||
Redis 作为 Broker 在初期足够(架构简单、少维护一个组件)。当每日任务量 > 10万 时,再迁移到 RabbitMQ 或 AWS SQS。
|
||||
|
||||
---
|
||||
|
||||
### 5. 对象存储:MinIO
|
||||
|
||||
| 用途 | 说明 |
|
||||
|------|------|
|
||||
| **用户上传底图** | 微信小程序 → 直传 MinIO(预签名 URL)→ 返回 key 给后端 |
|
||||
| **词云生成结果图** | Celery Worker 生成后上传 → 前端通过 CDN 域名访问 |
|
||||
| **商品实物照片** | 运营后台上传 → 前端展示 |
|
||||
|
||||
**为什么不存数据库?**
|
||||
图片二进制存数据库会导致表体积膨胀、备份慢、查询性能下降。MinIO(S3 兼容)是对象存储的最优解。
|
||||
|
||||
**云服务器部署建议**:
|
||||
- 若使用阿里云:可无缝切换到 **阿里云 OSS**(代码只需改 endpoint + access key)。
|
||||
- 若自建服务器:MinIO 单机版 Docker 运行,占用 < 200MB 内存。
|
||||
|
||||
---
|
||||
|
||||
### 6. 部署与运维:Docker Compose(初期)
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml 示例(MVP 单服务器)
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
api:
|
||||
build: ./backend
|
||||
ports:
|
||||
- "8000:8000"
|
||||
environment:
|
||||
- DATABASE_URL=postgresql+asyncpg://user:pass@db:5432/smart_engraving
|
||||
- REDIS_URL=redis://redis:6379/0
|
||||
- MINIO_ENDPOINT=minio:9000
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
- minio
|
||||
|
||||
celery_worker:
|
||||
build: ./backend
|
||||
command: celery -A tasks worker --loglevel=info --concurrency=2
|
||||
environment:
|
||||
- DATABASE_URL=postgresql+asyncpg://user:pass@db:5432/smart_engraving
|
||||
- REDIS_URL=redis://redis:6379/0
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
- minio
|
||||
|
||||
db:
|
||||
image: postgres:15-alpine
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_DB: smart_engraving
|
||||
POSTGRES_USER: user
|
||||
POSTGRES_PASSWORD: pass
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
volumes:
|
||||
- redisdata:/data
|
||||
|
||||
minio:
|
||||
image: minio/minio:latest
|
||||
command: server /data --console-address ":9001"
|
||||
ports:
|
||||
- "9000:9000"
|
||||
- "9001:9001"
|
||||
volumes:
|
||||
- miniodata:/data
|
||||
environment:
|
||||
MINIO_ROOT_USER: minioadmin
|
||||
MINIO_ROOT_PASSWORD: minioadmin
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
redisdata:
|
||||
miniodata:
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、API 设计速查(供前端联调用)
|
||||
|
||||
### 认证
|
||||
```http
|
||||
POST /api/v1/auth/wechat
|
||||
Body: { code: "wx_auth_code" }
|
||||
Response: { access_token: "jwt", refresh_token: "jwt", user: {...} }
|
||||
```
|
||||
|
||||
### 商品
|
||||
```http
|
||||
GET /api/v1/products
|
||||
Response: [ { id, name, desc, price, leadTime, images[], mask } ]
|
||||
```
|
||||
|
||||
### 设计清单
|
||||
```http
|
||||
GET /api/v1/designs # 列表
|
||||
POST /api/v1/designs # 新建(加入清单)
|
||||
PATCH /api/v1/designs/{id} # 更新(保存设计稿)
|
||||
DELETE /api/v1/designs/{id} # 删除
|
||||
POST /api/v1/designs/{id}/order # 确认下单(design → order)
|
||||
```
|
||||
|
||||
### 词云
|
||||
```http
|
||||
POST /api/v1/wordcloud/jobs
|
||||
Body: { baseImageKey, names: [] }
|
||||
Response: { jobId, status: "queued" }
|
||||
|
||||
GET /api/v1/wordcloud/jobs/{jobId}
|
||||
Response: { status, resultUrl, progress }
|
||||
```
|
||||
|
||||
### 订单
|
||||
```http
|
||||
GET /api/v1/orders
|
||||
POST /api/v1/orders # 创建预支付订单
|
||||
POST /api/v1/orders/{id}/pay # 调起微信支付(返回 prepay_id)
|
||||
POST /api/v1/orders/wechat_notify # 微信支付回调(服务端内部)
|
||||
```
|
||||
|
||||
### 上传
|
||||
```http
|
||||
GET /api/v1/upload/presign?filename=xxx.jpg&contentType=image/jpeg
|
||||
Response: { url, key, expires }
|
||||
# 前端使用 `url` 直传 MinIO / OSS
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、费用预估(阿里云 / 腾讯云,MVP 阶段)
|
||||
|
||||
| 资源 | 配置 | 月费用(人民币) |
|
||||
|------|------|-----------------|
|
||||
| 云服务器 ECS | 2核4G,共享型 | ~¥60-100 |
|
||||
| 云数据库 RDS PostgreSQL | 1核1G,基础版 | ~¥35-60 |
|
||||
| 云数据库 Redis | 256MB 主从 | ~¥20-40 |
|
||||
| 对象存储 OSS | 50GB 标准存储 | ~¥5-10 |
|
||||
| CDN 流量 | 100GB/月 | ~¥15-25 |
|
||||
| 域名 + SSL 证书 | 通配符一年 | ~¥200-400/年 |
|
||||
| **合计** | | **~¥150-260/月** |
|
||||
|
||||
> 若用户量极小(< 1000 日活),可将 PostgreSQL 和 Redis 都部署在同一台 ECS 上,初期费用可压到 **¥60-80/月**。
|
||||
|
||||
---
|
||||
|
||||
## 五、开发排期建议(后端 MVP,2 人团队)
|
||||
|
||||
| 阶段 | 周期 | 内容 |
|
||||
|------|------|------|
|
||||
| **Week 1** | 环境搭建 | Docker Compose 本地跑通;FastAPI 项目脚手架;PostgreSQL + Redis 联调 |
|
||||
| **Week 2** | 核心 API | 微信登录 JWT / 商品列表 / 设计清单 CRUD / 订单创建 |
|
||||
| **Week 3** | 词云 & 支付 | 词云异步任务接入(Celery);微信支付预支付+回调;MinIO 预签名上传 |
|
||||
| **Week 4** | 联调 & 部署 | 小程序前端联调;阿里云 ECS 生产部署;监控告警(日志 + 告警) |
|
||||
|
||||
---
|
||||
|
||||
## 六、风险与预案
|
||||
|
||||
| 风险 | 影响 | 预案 |
|
||||
|------|------|------|
|
||||
| 微信登录 code 换取 session_key 失败 | 用户无法登录 | 后端增加 Mock 登录接口(开发环境)|
|
||||
| 词云生成耗时长(>30s) | 用户体验差 | 前端轮询 + 后端加进度反馈;高并发时排队提示 |
|
||||
| 支付回调网络抖动 | 订单状态不一致 | 支付回调幂等设计(按微信 `out_trade_no` 去重)|
|
||||
| 图片存储流量激增 | CDN 费用上升 | 启用 OSS 图片压缩 + WebP 转换 |
|
||||
|
||||
---
|
||||
|
||||
## 七、推荐的开箱即用工具链
|
||||
|
||||
| 工具 | 用途 |
|
||||
|------|------|
|
||||
| **uv** | Python 包管理与虚拟环境(比 pip + venv 快 10 倍)|
|
||||
| **Pydantic v2** | 数据校验与序列化(FastAPI 内置)|
|
||||
| **sqlalchemy[asyncio]** | 异步 ORM |
|
||||
| **celery[redis]** | 异步任务队列 |
|
||||
| **boto3** | MinIO / OSS S3 兼容客户端 |
|
||||
| **loguru** | 结构化日志 |
|
||||
| **sentry-sdk** | 线上异常追踪(免费额度够用)|
|
||||
|
||||
---
|
||||
|
||||
## 八、总结
|
||||
|
||||
> **推荐技术栈:FastAPI + PostgreSQL + Redis + MinIO + Celery,Docker Compose 单服务器部署。**
|
||||
|
||||
- **FastAPI**:异步高性能、自动生成文档、团队上手快。
|
||||
- **PostgreSQL**:JSONB 灵活存储设计稿元数据,未来扩展无需换库。
|
||||
- **Redis**:一物三用(缓存 + 队列 + 限流)。
|
||||
- **MinIO**:自托管 S3 兼容对象存储,未来可一键切阿里云 OSS。
|
||||
- **Celery**:词云生成、支付回调、通知推送全部异步化,前端响应 < 100ms。
|
||||
|
||||
该方案在 **日活 1 万以内** 完全不需要 Kubernetes 或微服务拆分,单台 2 核 4G 服务器即可承载。
|
||||
@@ -0,0 +1,121 @@
|
||||
# 智绘微刻小程序 - 遮罩尺寸配置指南
|
||||
|
||||
## 📌 概述
|
||||
|
||||
本小程序的 DIY 工作台使用**遮罩层(Mask)**来模拟实际产品的雕刻区域。用户在画布上看到的半透明黑色区域之外的部分,即为该产品的实际外形轮廓;白色/透明区域则是激光雕刻的可用范围。
|
||||
|
||||
当你们确定了各品类的真实尺寸后,**只需修改一个配置文件**,所有页面的渲染就会自动更新。
|
||||
|
||||
---
|
||||
|
||||
## 🎯 修改位置
|
||||
|
||||
**文件路径:**
|
||||
```
|
||||
src/utils/productConfig.ts
|
||||
```
|
||||
|
||||
此文件导出一个 `PRODUCTS` 数组,每个品类对象中都有一个 `mask` 属性,就是遮罩的配置。
|
||||
|
||||
---
|
||||
|
||||
## 📐 尺寸单位说明
|
||||
|
||||
| 项目 | 说明 |
|
||||
|---|---|
|
||||
| 单位 | `px`(像素) |
|
||||
| 基准 | 基于 **750px 宽度** 的设计稿 |
|
||||
| 换算建议 | 实际尺寸(mm)÷ 实物最大宽度(mm)× 画布宽度(px) |
|
||||
|
||||
### 举例
|
||||
假设铜质杯垫实际直径为 **90mm**,画布区域在手机上显示为 **300px 宽**:
|
||||
```
|
||||
先量出杯垫实际直径对应的像素比例:
|
||||
90mm ÷ 90mm × 280 = 280px
|
||||
(如果直接按1:1在画布上展示,就填280)
|
||||
```
|
||||
|
||||
**更简单的方式**:等真实的样品拿到后,直接用手机截图量一下在 375px 逻辑像素下应该占多大,然后把数值填进去即可。
|
||||
|
||||
---
|
||||
|
||||
## 🔧 遮罩类型
|
||||
|
||||
### 1. 矩形遮罩(rect)
|
||||
适用于:笔记本、笔盒、书本灯等方形/圆角矩形产品
|
||||
|
||||
```typescript
|
||||
mask: {
|
||||
type: 'rect',
|
||||
width: 300, // 遮罩宽度(px)
|
||||
height: 420, // 遮罩高度(px)
|
||||
radius: 8 // 圆角半径(px),不需要圆角填 0
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 圆形遮罩(circle)
|
||||
适用于:杯垫、徽章等圆形产品
|
||||
|
||||
```typescript
|
||||
mask: {
|
||||
type: 'circle',
|
||||
width: 280, // 椭圆外接矩形宽度(px)
|
||||
height: 280 // 椭圆外接矩形高度(px)
|
||||
}
|
||||
```
|
||||
|
||||
> 如果 `width === height`,即为正圆;如果不相等,则为椭圆。
|
||||
|
||||
---
|
||||
|
||||
## 📋 当前品类与待填尺寸
|
||||
|
||||
| 品类ID | 品类名称 | 当前尺寸 | 状态 |
|
||||
|---|---|---|---|
|
||||
| `notebook-small` | 微雕笔记本(小) | 300 × 420 px | 占位待改 |
|
||||
| `notebook-large` | 微雕笔记本(大) | 340 × 480 px | 占位待改 |
|
||||
| `coaster` | 铜质杯垫 | 280 px 直径 | 占位待改 |
|
||||
| `penbox` | 竹制笔盒 | 320 × 160 px | 占位待改 |
|
||||
| `booklamp` | 书本型灯 | 320 × 240 px | 占位待改 |
|
||||
|
||||
---
|
||||
|
||||
## 💡 修改步骤
|
||||
|
||||
1. 测量实际样品的雕刻区域尺寸(建议用卡尺精确到 mm)
|
||||
2. 在手机上打开小程序 DIY 页面,截图量出画布的实际显示像素
|
||||
3. 按比例换算:`(实际尺寸 mm / 画布对应的实际物理宽度 mm) × 画布像素宽度`
|
||||
4. 打开 `src/utils/productConfig.ts`
|
||||
5. 修改对应产品 `mask` 对象的 `width`、`height`、`radius` 数值
|
||||
6. 保存文件,重新编译小程序即可看到效果
|
||||
|
||||
---
|
||||
|
||||
## 🎨 效果说明
|
||||
|
||||
遮罩在 UI 上的表现:
|
||||
- 遮罩区域:**透明/白色**,可看到用户上传的图片,表示这是雕刻范围
|
||||
- 遮罩外部:**半透明黑色蒙层**,提示用户图片在这个范围之外的部分不会被雕刻到产品上
|
||||
- 遮罩边框:**白色虚线框**,清晰标识边界
|
||||
|
||||
用户上传图片后,可以通过**拖拽**调整图片在遮罩内的位置,通过**缩放按钮**调整图片大小,确保想要雕刻的内容落在白色遮罩区域内。
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
1. **修改后需重新编译**:Taro 会热更新,但在微信开发者工具中建议点击「编译」确保生效
|
||||
2. **尺寸不宜过大**:遮罩面积建议不超过画布面积的 80%,否则用户难以感受到「边缘」
|
||||
3. **留足边距**:设计时建议遮罩四周至少留出 20px 的安全边距,避免用户把图片贴得太边
|
||||
4. **圆形产品**:如果杯垫等产品有固定内圈雕刻区域(而非整个圆面),可以将 `width/height` 设小一点,模拟内圈
|
||||
|
||||
---
|
||||
|
||||
## 🔗 相关文件
|
||||
|
||||
| 文件 | 作用 |
|
||||
|---|---|
|
||||
| `src/utils/productConfig.ts` | 品类与遮罩配置(修改这里) |
|
||||
| `src/types/index.ts` | 类型定义(一般不需要改) |
|
||||
| `src/pages/diy/index.tsx` | DIY 工作台页面(读取配置自动渲染) |
|
||||
| `src/pages/diy/index.scss` | 遮罩样式(一般不需要改) |
|
||||
Reference in New Issue
Block a user