# 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 定时任务检查到期（每小时一次）

---

**老大确认后，我就把这些任务同步到推进器里。**
