Files
social-app/docs/plans/2026-02-27-invite-code-implementation-plan.md
T
qzl e4e995854d feat: 实现密码重置功能与用户搜索API,优化注册登录流程
- 新增忘记密码页面与重置密码确认流程(前端+后端)
- 修复注册验证码页登录跳转路由
- 新增用户搜索API(按邮箱查询)
- 简化infra脚本,统一为app.sh
- 补充密码重置与用户API测试覆盖
- 更新runtime文档与AGENTS配置
2026-02-27 15:22:42 +08:00

10 KiB
Raw Blame History

Invite Code Implementation Plan

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: 在现有 OTP 注册链路中引入邀请码能力,支持用户自动生成专属邀请码、注册时可选填邀请码并记录邀请关系与使用次数。

Architecture: 采用数据库中心实现:通过 Alembic 新增 invite_codes 表、扩展 profiles 字段,并在 auth.users 的现有 trigger 函数中完成邀请码校验与记账,保证注册与邀请关系写入尽量原子。应用层只负责透传 invite_code 到 Supabase raw_user_meta_data

Tech Stack: FastAPI, SQLAlchemy, Alembic, Supabase Auth, PostgreSQL PL/pgSQL, Pytest


Task 1: 更新注册请求 SchemaTDD

Files:

  • Modify: backend/src/v1/auth/schemas.py
  • Modify: backend/tests/integration/test_auth_routes.py

Step 1: Write the failing test

test_signup_start_returns_pending_response 基础上新增断言路径:请求体带 invite_code 时返回仍为 202,且未触发 422。

Step 2: Run test to verify it fails

Run: cd backend && uv run pytest tests/integration/test_auth_routes.py -k signup_start_returns_pending_response -v Expected: FAILinvite_code 为额外字段或校验不通过)

Step 3: Write minimal implementation

VerificationCreateRequest 增加可选字段:

invite_code: str | None = Field(default=None, min_length=8, max_length=8)

Step 4: Run test to verify it passes

Run: cd backend && uv run pytest tests/integration/test_auth_routes.py -k signup_start_returns_pending_response -v Expected: PASS

Step 5: Commit

git add backend/src/v1/auth/schemas.py backend/tests/integration/test_auth_routes.py
git commit -m "feat: accept invite code in signup request"

Task 2: 透传 invite_code 到 Supabase metadataTDD

Files:

  • Modify: backend/src/v1/auth/gateway.py
  • Modify: backend/tests/unit/v1/auth/test_auth_service.py

Step 1: Write the failing test

test_supabase_signup_passes_username_in_metadata 增加 invite_code 并断言:

assert captured_payload["data"] == {
    "username": "demo",
    "invite_code": "A1B2C3D4",
}

Step 2: Run test to verify it fails

Run: cd backend && uv run pytest tests/unit/v1/auth/test_auth_service.py -k metadata -v Expected: FAILmetadata 未包含 invite_code

Step 3: Write minimal implementation

create_verification 中构建 metadata

metadata = {"username": request.username}
if request.invite_code:
    metadata["invite_code"] = request.invite_code
payload = {
    "email": request.email,
    "password": request.password,
    "data": metadata,
}

Step 4: Run test to verify it passes

Run: cd backend && uv run pytest tests/unit/v1/auth/test_auth_service.py -k metadata -v Expected: PASS

Step 5: Commit

git add backend/src/v1/auth/gateway.py backend/tests/unit/v1/auth/test_auth_service.py
git commit -m "feat: pass invite code through signup metadata"

Task 3: 新增 invite_codes 表与 profiles.referred_by(迁移先行)

Files:

  • Create: backend/alembic/versions/20260227_0006_invite_codes_and_profile_referral.py
  • Modify: backend/src/models/profile.py
  • Create: backend/src/models/invite_code.py
  • Modify: backend/src/models/__init__.py

Step 1: Write the failing test

backend/tests/unit/database/test_profile_models.py 新增 referred_by 读写测试;新增 backend/tests/unit/database/test_invite_code_models.py 验证 InviteCode 基本创建与约束字段。

Step 2: Run test to verify it fails

Run: cd backend && uv run pytest tests/unit/database/test_profile_models.py tests/unit/database/test_invite_code_models.py -v Expected: FAIL(字段/模型不存在)

Step 3: Write minimal implementation

  • Alembic 创建 invite_codes

    • code 唯一索引
    • owner_id 外键到 profiles.id(可空)
    • statusused_countmax_uses check 约束
    • max_uses 默认 NULL(无限制)
    • expires_at 默认 NULL(无限制)
    • reward_config JSONB 默认 {}
    • 启用 RLS(按项目默认 deny-all
  • 注意:本期不开放 invite_codes 表直接读取,用户邀请码通过 profile 聚合接口返回(后续实现)

  • Alembic 给 profiles 增加 referred_by + 索引 + 外键

  • ORM 同步 Profile.referred_byInviteCode 模型

Step 4: Run test to verify it passes

Run: cd backend && uv run pytest tests/unit/database/test_profile_models.py tests/unit/database/test_invite_code_models.py -v Expected: PASS

Step 5: Commit

git add backend/alembic/versions/20260227_0006_invite_codes_and_profile_referral.py backend/src/models/profile.py backend/src/models/invite_code.py backend/src/models/__init__.py backend/tests/unit/database/test_profile_models.py backend/tests/unit/database/test_invite_code_models.py
git commit -m "feat: add invite code schema and profile referral fields"

Task 4: 扩展注册 trigger 生成邀请码并消费邀请(TDD)

Files:

  • Modify: backend/alembic/versions/20260227_0006_invite_codes_and_profile_referral.py
  • Modify: backend/tests/integration/test_auth_routes.py

Step 1: Write the failing test

新增集成测试(建议通过测试替身/fixture 验证行为):

  • 注册不带邀请码时,profile 创建后存在 owner 邀请码
  • 注册带有效邀请码时,referred_by 生效且 used_count + 1

Step 2: Run test to verify it fails

Run: cd backend && uv run pytest tests/integration/test_auth_routes.py -k invite -v Expected: FAIL(触发器逻辑尚未实现)

Step 3: Write minimal implementation

在迁移 SQL 中:

  • 新增 helper function:生成 8 位随机码(排除易混淆字符 0/O/1/I/L,冲突重试)
  • 重建 public.create_profile_for_new_user()
    1. 插入 profiles
    2. 创建该用户专属 invite_codesowner_id = NEW.id
    3. 读取 NEW.raw_user_meta_data ->> 'invite_code'
    4. 校验邀请码状态/过期/次数
    5. 若有效:更新 profiles.referred_by,并 used_count = used_count + 1

Step 4: Run test to verify it passes

Run: cd backend && uv run pytest tests/integration/test_auth_routes.py -k invite -v Expected: PASS

Step 5: Commit

git add backend/alembic/versions/20260227_0006_invite_codes_and_profile_referral.py backend/tests/integration/test_auth_routes.py
git commit -m "feat: extend signup trigger for invite code generation and usage"

Task 5: 覆盖邀请码边界场景(TDD)

Files:

  • Modify: backend/tests/integration/test_auth_routes.py
  • Optional Modify: backend/tests/e2e/test_auth_flow.py

Step 1: Write the failing test

新增场景测试:

  • 邀请码不存在
  • 邀请码 disabled
  • 邀请码 expires_at 已过期
  • 邀请码达到 max_uses

断言:注册仍成功(202/200 链路正常),仅邀请关系不建立。

Step 2: Run test to verify it fails

Run: cd backend && uv run pytest tests/integration/test_auth_routes.py -k "invite and (expired or disabled or max_uses or invalid)" -v Expected: FAIL

Step 3: Write minimal implementation

修正 trigger 判断顺序和条件,确保“邀请无效不影响注册”原则。

Step 4: Run test to verify it passes

Run: cd backend && uv run pytest tests/integration/test_auth_routes.py -k invite -v Expected: PASS

Step 5: Commit

git add backend/tests/integration/test_auth_routes.py backend/alembic/versions/20260227_0006_invite_codes_and_profile_referral.py
git commit -m "test: cover invite code edge cases in signup flow"

Task 6: 文档同步与运行手册更新

Files:

  • Modify: docs/runtime/runtime-route.md
  • Modify: docs/runtime/runtime-runbook.md

Step 1: Write the failing test

无自动化测试;改为文档一致性检查清单(手工):

  • 注册接口 request 字段包含 invite_code
  • 说明邀请码消费时机与“无效码不阻断注册”

Step 2: Run check to verify missing docs

Run: cd backend && uv run pytest tests/integration/test_auth_routes.py -k signup_start -v Expected: PASS(作为行为基线),文档尚未同步

Step 3: Write minimal implementation

  • 更新 POST /auth/verifications 请求字段
  • 新增邀请码行为说明
  • 在 runbook 变更日志添加本次改动记录

Step 4: Run check after docs update

Run: cd backend && uv run pytest tests/integration/test_auth_routes.py -k signup_start -v Expected: PASS(行为与文档一致)

Step 5: Commit

git add docs/runtime/runtime-route.md docs/runtime/runtime-runbook.md
git commit -m "docs: document invite code behavior in signup flow"

Task 7: 全量验证与风险审查(L2)

Files:

  • Verify only

Step 1: Run lint/type checks

Run:

  • cd backend && uv run ruff check src tests
  • cd backend && uv run basedpyright src

Expected: 全部通过

Step 2: Run test suites

Run:

  • cd backend && uv run pytest tests/unit -v
  • cd backend && uv run pytest tests/integration -v
  • cd backend && uv run pytest tests/e2e/test_auth_flow.py -v

Expected: 通过

Step 3: Run mandatory review gates for L2

  • refactor-cleaner agent:确认无死代码/重复代码
  • code-reviewer agent:检查 DB trigger、安全边界、可维护性

Expected: CRITICAL/HIGH 为 0

Step 4: Security-specific sanity checks

检查项:

  • 未硬编码密钥
  • SQL 逻辑无注入风险(trigger 中仅参数/列操作)
  • 邀请码校验失败不泄露内部细节

Step 5: Commit verification evidence (if needed in docs/PR notes)

git add <updated verification notes if any>
git commit -m "chore: record invite code verification results"

交付验收标准

  1. 新用户注册后必有 1 条专属邀请码。
  2. 注册时传入有效邀请码会建立 profiles.referred_by 并增加 used_count
  3. 无效邀请码不会阻断注册成功。
  4. 支持运营码(owner_id IS NULL)与后续奖励扩展(reward_config)。
  5. 文档已同步,测试与检查通过。

备注

  • 本需求触发 L2(数据库迁移 + trigger + 多文件大改),必须走双审查 gate。
  • 不在本期实现运营后台批量发码 API;仅完成数据层与注册链路支撑。