fix: connect API to tracker.db via SQLite repository
Deploy / Deploy Staging (push) Failing after 9s
Deploy / Deploy Production (push) Has been skipped
Tests / test (push) Failing after 14s
Tests / lint (push) Failing after 15s

This commit is contained in:
Xiaoxia AI
2026-06-17 13:21:38 +08:00
parent 3bf90f8614
commit 2cda8dec39
67 changed files with 5737 additions and 123 deletions
+542
View File
@@ -0,0 +1,542 @@
# Phase 4: SAAS 产品化 - 设计文档
> 版本:v1.0
> 创建时间:2026-06-17
> 负责人:小虾 🦐
> 目标完成日期:2026-07-15
---
## 📋 目标
将小虾 SaaS 从技术 Demo 升级为真正的多租户商业化产品:
- ✅ 用户可以注册/登录/管理账号
- ✅ 支持多租户隔离和权限控制
- ✅ 支持订阅套餐和在线支付
---
## 🎯 核心功能模块
### 1️⃣ 认证与账号体系
#### 功能列表
- **用户注册**
- 邮箱 + 密码注册
- 邮箱验证(发送验证链接)
- 用户名唯一性检查
- **用户登录**
- 邮箱/用户名 + 密码登录
- JWT Token 签发(access_token + refresh_token)
- 记住我(30 天有效期)
- **密码管理**
- 忘记密码(邮件重置链接)
- 修改密码
- 密码强度要求(最少 8 位,包含字母+数字)
- **Session 管理**
- 刷新 Token
- 登出(撤销 Token)
- 查看活跃 Session(设备/IP/时间)
- 强制登出所有设备
#### 技术方案
**密码存储**
- 使用 `bcrypt` 哈希密码(cost=12)
- 不存储明文密码
- 密码哈希存储在 `User.password_hash` 字段
**JWT Token 设计**
```json
{
"access_token": {
"payload": {
"user_id": "uuid",
"workspace_id": "uuid",
"role": "owner|admin|member|viewer",
"exp": 1800 // 30 分钟过期
}
},
"refresh_token": {
"payload": {
"user_id": "uuid",
"session_id": "uuid",
"exp": 2592000 // 30 天过期
},
"存储": "Redis (key: refresh_token:{session_id}, value: user_id)"
}
}
```
**Token 刷新流程**
1. 客户端检测 `access_token` 即将过期(剩余 < 5 分钟)
2. 用 `refresh_token` 调用 `/auth/refresh`
3. 验证 `refresh_token` 在 Redis 中存在且未过期
4. 签发新的 `access_token`(可选:同时轮转 `refresh_token`)
**邮件服务**
- SMTP 配置(支持 Gmail/阿里云企业邮箱等)
- 邮件模板(欢迎邮件/验证邮件/密码重置)
- 异步发送(Celery 任务)
#### API 设计
```
POST /api/v1/auth/register # 注册
POST /api/v1/auth/login # 登录
POST /api/v1/auth/logout # 登出
POST /api/v1/auth/refresh # 刷新 Token
POST /api/v1/auth/password/forgot # 忘记密码
POST /api/v1/auth/password/reset # 重置密码
POST /api/v1/auth/password/change # 修改密码
GET /api/v1/auth/verify-email # 邮箱验证
GET /api/v1/auth/sessions # 查看活跃 Session
DELETE /api/v1/auth/sessions/:id # 删除指定 Session
DELETE /api/v1/auth/sessions/all # 登出所有设备
```
#### 数据模型扩展
**User 实体新增字段**
```python
class User(BaseEntity):
# 原有字段
username: str
email: str
display_name: str
# 新增字段
password_hash: str # bcrypt 哈希
email_verified: bool = False # 邮箱是否验证
email_verification_token: str # 邮箱验证令牌
password_reset_token: str # 密码重置令牌
password_reset_expires_at: datetime # 重置令牌过期时间
last_login_at: datetime # 最后登录时间
last_login_ip: str # 最后登录 IP
```
**新增 Session 实体**
```python
class Session(BaseEntity):
user_id: str # 所属用户
refresh_token_hash: str # refresh_token 哈希
device_info: str # 设备信息(User-Agent)
ip_address: str # 登录 IP
expires_at: datetime # 过期时间
last_active_at: datetime # 最后活跃时间
```
---
### 2️⃣ 多租户权限体系
#### 功能列表
- **Workspace 成员管理**
- 邀请成员(发送邀请邮件)
- 移除成员
- 转让 Workspace 所有权
- **角色与权限**
- Owner(所有者):完全控制权
- Admin(管理员):管理成员、项目、资产
- Member(成员):创建/编辑自己的内容
- Viewer(查看者):只读权限
- **数据隔离**
- 所有资源(Project/Task/Asset)必须关联 Workspace
- API 自动过滤非当前 Workspace 的数据
- 防止跨 Workspace 访问
#### 权限矩阵
| 操作 | Owner | Admin | Member | Viewer |
|------|-------|-------|--------|--------|
| 查看 Workspace 信息 | ✅ | ✅ | ✅ | ✅ |
| 修改 Workspace 信息 | ✅ | ✅ | ❌ | ❌ |
| 删除 Workspace | ✅ | ❌ | ❌ | ❌ |
| 邀请成员 | ✅ | ✅ | ❌ | ❌ |
| 移除成员 | ✅ | ✅ | ❌ | ❌ |
| 修改成员角色 | ✅ | ✅ | ❌ | ❌ |
| 转让所有权 | ✅ | ❌ | ❌ | ❌ |
| 创建项目 | ✅ | ✅ | ✅ | ❌ |
| 编辑项目 | ✅ | ✅ | 自己的 | ❌ |
| 删除项目 | ✅ | ✅ | 自己的 | ❌ |
| 上传素材 | ✅ | ✅ | ✅ | ❌ |
| 查看素材 | ✅ | ✅ | ✅ | ✅ |
| 删除素材 | ✅ | ✅ | 自己的 | ❌ |
| 查看订阅/账单 | ✅ | ✅ | ❌ | ❌ |
| 修改订阅 | ✅ | ❌ | ❌ | ❌ |
#### 技术方案
**权限检查中间件**
```python
@require_permission("project:create")
async def create_project(request, ...):
pass
```
**权限装饰器实现**
```python
def require_permission(permission: str):
def decorator(func):
async def wrapper(request, *args, **kwargs):
user = request.state.user
workspace_id = request.state.workspace_id
# 检查用户在当前 Workspace 的角色
membership = get_workspace_membership(user.id, workspace_id)
if not membership.has_permission(permission):
raise HTTPException(403, "Permission denied")
return await func(request, *args, **kwargs)
return wrapper
return decorator
```
**数据隔离过滤器**
```python
# 所有查询自动加上 workspace_id 过滤
def list_projects(workspace_id: str) -> List[Project]:
return project_repo.find_by_workspace(workspace_id)
```
#### API 设计
```
# Workspace 成员管理
GET /api/v1/workspaces/:id/members # 成员列表
POST /api/v1/workspaces/:id/members/invite # 邀请成员
DELETE /api/v1/workspaces/:id/members/:user_id # 移除成员
PATCH /api/v1/workspaces/:id/members/:user_id # 修改角色
POST /api/v1/workspaces/:id/transfer # 转让所有权
# 邀请管理
GET /api/v1/invitations # 我的邀请
POST /api/v1/invitations/:id/accept # 接受邀请
POST /api/v1/invitations/:id/decline # 拒绝邀请
```
#### 数据模型扩展
**新增 WorkspaceMembership 实体**
```python
class WorkspaceMembership(BaseEntity):
workspace_id: str # 所属 Workspace
user_id: str # 成员用户
role: WorkspaceRole # 角色(owner/admin/member/viewer)
invited_by_user_id: str # 邀请人
joined_at: datetime # 加入时间
```
**新增 WorkspaceInvitation 实体**
```python
class WorkspaceInvitation(BaseEntity):
workspace_id: str # 邀请加入的 Workspace
email: str # 受邀邮箱
role: WorkspaceRole # 邀请角色
invited_by_user_id: str # 邀请人
token: str # 邀请令牌
expires_at: datetime # 过期时间
status: InvitationStatus # pending/accepted/declined/expired
```
---
### 3️⃣ 订阅与计费体系
#### 功能列表
- **订阅套餐**
- 免费版:1 个 Workspace,3 个项目,10GB 存储
- 专业版:5 个 Workspace,无限项目,100GB 存储,¥99/月
- 企业版:无限 Workspace,无限项目,1TB 存储,专属支持,¥999/月
- **支付功能**
- 支付宝扫码支付
- 微信扫码支付
- 自动续费(可选)
- **账单管理**
- 订阅历史
- 发票申请
- 退款申请
#### 技术方案
**支付流程**
1. 用户选择套餐 → 创建订单
2. 调用支付宝/微信支付 API → 生成支付二维码
3. 用户扫码支付 → 支付平台回调我们的 webhook
4. 验证回调签名 → 更新订单状态 → 激活订阅
**订阅状态机**
```
trial (试用) → active (有效) → expired (过期) → cancelled (取消)
↓
grace_period (宽限期,3 天)
```
**配额检查**
- 创建 Workspace 前检查套餐限制
- 上传文件前检查存储空间
- 超出配额时提示升级
#### API 设计
```
# 订阅管理
GET /api/v1/subscriptions/plans # 套餐列表
GET /api/v1/subscriptions/current # 当前订阅
POST /api/v1/subscriptions/subscribe # 订阅套餐
POST /api/v1/subscriptions/cancel # 取消订阅
POST /api/v1/subscriptions/renew # 续费
# 支付
POST /api/v1/payments/create # 创建支付订单
GET /api/v1/payments/:id # 查询订单状态
POST /api/v1/payments/webhook/alipay # 支付宝回调
POST /api/v1/payments/webhook/wechat # 微信回调
# 账单
GET /api/v1/invoices # 账单列表
GET /api/v1/invoices/:id # 账单详情
POST /api/v1/invoices/:id/download # 下载账单
```
#### 数据模型
**新增 Subscription 实体**
```python
class Subscription(BaseEntity):
workspace_id: str # 所属 Workspace
plan: SubscriptionPlan # 套餐(free/pro/enterprise)
status: SubscriptionStatus # 状态(trial/active/expired/cancelled)
started_at: datetime # 开始时间
expires_at: datetime # 到期时间
auto_renew: bool # 是否自动续费
```
**新增 Payment 实体**
```python
class Payment(BaseEntity):
workspace_id: str # 所属 Workspace
subscription_id: str # 关联订阅
amount: Decimal # 金额
currency: str = "CNY" # 货币
payment_method: PaymentMethod # alipay/wechat
status: PaymentStatus # pending/paid/failed/refunded
transaction_id: str # 支付平台交易号
paid_at: datetime # 支付时间
```
**新增 Invoice 实体**
```python
class Invoice(BaseEntity):
workspace_id: str # 所属 Workspace
payment_id: str # 关联支付
invoice_number: str # 发票号
amount: Decimal # 金额
tax_amount: Decimal # 税额
issued_at: datetime # 开票时间
pdf_url: str # PDF 下载地址
```
---
## 📐 开发规则与约定
### 代码规范
1. **遵循 Clean Architecture**
- 认证逻辑在 `packages/domain/auth/`
- Use Cases 在 `packages/application/auth/`
- API 路由在 `apps/api/app/api/routes/auth.py`
2. **安全第一**
- 所有密码必须哈希存储
- JWT Secret 从环境变量读取,不硬编码
- 敏感 API(修改密码/删除账号)需要二次验证
- 所有输入必须验证和清洗
3. **测试覆盖**
- 每个 Use Case 至少 1 个单元测试
- 每个 API 端点至少 1 个集成测试
- 安全相关功能(认证/权限)测试覆盖率 > 80%
4. **日志与监控**
- 登录/登出/权限拒绝必须记录日志
- 敏感操作(修改密码/删除账号)记录审计日志
- 异常情况告警(大量登录失败/异常 IP)
### Git 工作流
- 每个功能模块一个分支(如 `feature/auth-system`)
- 完成后合并到 `main`
- 提交信息格式:`feat(auth): add JWT login endpoint`
### 部署策略
- 认证功能先在测试环境验证
- 灰度发布(10% 流量 → 50% → 100%)
- 保留回滚能力(旧版本镜像保留 7 天)
---
## 📅 任务拆解与排期
### Milestone 1: 认证与账号体系(7 天,2026-06-17 ~ 2026-06-23)
**Day 1-2:基础设施搭建**
- [ ] JWT 工具类实现(sign/verify/refresh)
- [ ] bcrypt 密码哈希工具
- [ ] Redis Session 存储
- [ ] 邮件服务封装(SMTP + 模板)
- [ ] User 实体扩展(密码字段)
**Day 3-4:核心认证功能**
- [ ] 注册 API(邮箱验证)
- [ ] 登录 API(JWT 签发)
- [ ] 登出 API(撤销 Token)
- [ ] 刷新 Token API
- [ ] 密码重置流程
**Day 5-6:Session 管理**
- [ ] Session 实体与 Repository
- [ ] 活跃 Session 列表
- [ ] 强制登出所有设备
- [ ] 设备信息解析(User-Agent)
**Day 7:测试与文档**
- [ ] 集成测试(注册/登录/登出/刷新)
- [ ] 安全测试(密码强度/Token 伪造)
- [ ] API 文档更新
---
### Milestone 2: 多租户权限体系(7 天,2026-06-24 ~ 2026-06-30)
**Day 1-2:权限基础**
- [ ] WorkspaceMembership 实体与 Repository
- [ ] WorkspaceRole 枚举与权限定义
- [ ] 权限检查中间件
- [ ] 数据隔离过滤器
**Day 3-4:成员管理**
- [ ] 邀请成员 API
- [ ] 接受/拒绝邀请
- [ ] 移除成员
- [ ] 修改成员角色
- [ ] 转让所有权
**Day 5-6:权限验证**
- [ ] 所有现有 API 加上权限检查
- [ ] 跨 Workspace 访问防护测试
- [ ] 权限矩阵验证
**Day 7:测试与文档**
- [ ] 权限测试(各角色权限边界)
- [ ] 数据隔离测试
- [ ] API 文档更新
---
### Milestone 3: 订阅与计费(7 天,2026-07-01 ~ 2026-07-07)
**Day 1-2:订阅基础**
- [ ] Subscription 实体与 Repository
- [ ] SubscriptionPlan 枚举(free/pro/enterprise)
- [ ] 配额检查工具
- [ ] 套餐限制中间件
**Day 3-4:支付集成**
- [ ] 支付宝 SDK 集成
- [ ] 微信支付 SDK 集成
- [ ] 创建支付订单 API
- [ ] 支付回调处理(webhook)
**Day 5-6:账单管理**
- [ ] Invoice 实体与 Repository
- [ ] 生成账单 PDF
- [ ] 账单列表/下载 API
- [ ] 订阅历史记录
**Day 7:测试与文档**
- [ ] 支付流程端到端测试
- [ ] 配额检查测试
- [ ] API 文档更新
---
### Milestone 4: 前端集成与收尾(7 天,2026-07-08 ~ 2026-07-14)
**Day 1-2:认证 UI**
- [ ] 登录页面
- [ ] 注册页面
- [ ] 忘记密码页面
- [ ] 邮箱验证提示
**Day 3-4:权限 UI**
- [ ] 成员管理页面
- [ ] 邀请成员弹窗
- [ ] 角色选择器
- [ ] 权限说明文档
**Day 5-6:订阅 UI**
- [ ] 套餐选择页面
- [ ] 支付二维码页面
- [ ] 账单管理页面
- [ ] 配额使用展示
**Day 7:上线准备**
- [ ] 端到端测试
- [ ] 性能测试(登录/权限检查)
- [ ] 安全审计
- [ ] 生产环境部署
---
## 🔒 安全检查清单
### 认证安全
- [ ] 密码哈希使用 bcrypt,cost ≥ 12
- [ ] JWT Secret 强度足够(≥ 32 字节随机)
- [ ] Token 过期时间合理(access 30 分钟,refresh 30 天)
- [ ] 防止暴力破解(登录失败 5 次锁定 15 分钟)
- [ ] 防止用户枚举(注册/登录错误信息统一)
### 数据安全
- [ ] 所有查询强制 Workspace 过滤
- [ ] 跨 Workspace 访问返回 403,不是 404
- [ ] 敏感字段(密码哈希)不出现在 API 响应
- [ ] SQL 注入防护(使用 ORM,参数化查询)
- [ ] XSS 防护(输入清洗,输出转义)
### 支付安全
- [ ] 回调验证签名
- [ ] 订单金额不信任客户端
- [ ] 防止重放攻击(nonce + timestamp)
- [ ] 支付密钥不出现在日志
---
## 📊 成功指标
- [ ] 用户可以完整走通注册 → 登录 → 使用 → 续费流程
- [ ] 权限系统无漏洞(各角色权限边界清晰)
- [ ] 支付成功率 > 95%
- [ ] 认证 API 响应时间 < 200ms
- [ ] 权限检查开销 < 10ms
- [ ] 安全测试通过(无 SQL 注入/XSS/CSRF)
---
## 📝 备注
- 邮件服务可以先用 SMTP(Gmail/阿里云邮箱),后期再考虑 SendGrid
- 支付回调需要公网可访问地址(备案通过后才能配置)
- 支付功能可以先用沙箱环境测试
- 订阅计费逻辑需要 cron 定时任务检查到期(每小时一次)
---
**老大确认后,我就把这些任务同步到推进器里。**