# 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 定时任务检查到期(每小时一次) --- **老大确认后,我就把这些任务同步到推进器里。**