16 KiB
16 KiB
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 设计
{
"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 刷新流程
- 客户端检测
access_token即将过期(剩余 < 5 分钟) - 用
refresh_token调用/auth/refresh - 验证
refresh_token在 Redis 中存在且未过期 - 签发新的
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 实体新增字段
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 实体
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 | ✅ | ❌ | ❌ | ❌ |
| 邀请成员 | ✅ | ✅ | ❌ | ❌ |
| 移除成员 | ✅ | ✅ | ❌ | ❌ |
| 修改成员角色 | ✅ | ✅ | ❌ | ❌ |
| 转让所有权 | ✅ | ❌ | ❌ | ❌ |
| 创建项目 | ✅ | ✅ | ✅ | ❌ |
| 编辑项目 | ✅ | ✅ | 自己的 | ❌ |
| 删除项目 | ✅ | ✅ | 自己的 | ❌ |
| 上传素材 | ✅ | ✅ | ✅ | ❌ |
| 查看素材 | ✅ | ✅ | ✅ | ✅ |
| 删除素材 | ✅ | ✅ | 自己的 | ❌ |
| 查看订阅/账单 | ✅ | ✅ | ❌ | ❌ |
| 修改订阅 | ✅ | ❌ | ❌ | ❌ |
技术方案
权限检查中间件
@require_permission("project:create")
async def create_project(request, ...):
pass
权限装饰器实现
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
数据隔离过滤器
# 所有查询自动加上 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 实体
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 实体
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/月
-
支付功能
- 支付宝扫码支付
- 微信扫码支付
- 自动续费(可选)
-
账单管理
- 订阅历史
- 发票申请
- 退款申请
技术方案
支付流程
- 用户选择套餐 → 创建订单
- 调用支付宝/微信支付 API → 生成支付二维码
- 用户扫码支付 → 支付平台回调我们的 webhook
- 验证回调签名 → 更新订单状态 → 激活订阅
订阅状态机
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 实体
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 实体
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 实体
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 下载地址
📐 开发规则与约定
代码规范
-
遵循 Clean Architecture
- 认证逻辑在
packages/domain/auth/ - Use Cases 在
packages/application/auth/ - API 路由在
apps/api/app/api/routes/auth.py
- 认证逻辑在
-
安全第一
- 所有密码必须哈希存储
- JWT Secret 从环境变量读取,不硬编码
- 敏感 API(修改密码/删除账号)需要二次验证
- 所有输入必须验证和清洗
-
测试覆盖
- 每个 Use Case 至少 1 个单元测试
- 每个 API 端点至少 1 个集成测试
- 安全相关功能(认证/权限)测试覆盖率 > 80%
-
日志与监控
- 登录/登出/权限拒绝必须记录日志
- 敏感操作(修改密码/删除账号)记录审计日志
- 异常情况告警(大量登录失败/异常 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 定时任务检查到期(每小时一次)
老大确认后,我就把这些任务同步到推进器里。