Files

16 KiB
Raw Permalink Blame History

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 刷新流程

  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 实体新增字段

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 个 Workspace3 个项目,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 实体

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 下载地址

📐 开发规则与约定

代码规范

  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(邮箱验证)
  • 登录 APIJWT 签发)
  • 登出 API(撤销 Token
  • 刷新 Token API
  • 密码重置流程

Day 5-6Session 管理

  • 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:上线准备

  • 端到端测试
  • 性能测试(登录/权限检查)
  • 安全审计
  • 生产环境部署

🔒 安全检查清单

认证安全

  • 密码哈希使用 bcryptcost ≥ 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 定时任务检查到期(每小时一次)

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