7.1 KiB
7.1 KiB
邀请码机制设计
Date: 2026-02-27 Status: Approved Author: User + AI
背景
为用户注册增加邀请码机制,支持:
- 每个用户注册后自动获得专属邀请码
- 注册时可填写他人邀请码
- 记录邀请关系和使用统计
- 支持运营邀请码(批量、限额、过期、禁用)
- 预留奖励策略配置
数据模型
invite_codes 表
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | UUID | PK | 主键 |
| code | VARCHAR(8) | UNIQUE, NOT NULL | 邀请码 |
| owner_id | UUID | FK → profiles.id, nullable | 所属用户,NULL 为运营码 |
| max_uses | INT | nullable | 最大使用次数,NULL 无限制 |
| used_count | INT | DEFAULT 0 | 已用次数 |
| expires_at | TIMESTAMPTZ | nullable | 过期时间,NULL 永不过期 |
| status | VARCHAR(20) | NOT NULL | active / disabled |
| reward_config | JSONB | DEFAULT '{}' | 奖励策略配置 |
| created_at | TIMESTAMPTZ | NOT NULL | 创建时间 |
| updated_at | TIMESTAMPTZ | NOT NULL | 更新时间 |
| deleted_at | TIMESTAMPTZ | nullable | 软删除 |
索引:
ix_invite_codes_codeON (code) UNIQUEix_invite_codes_owner_idON (owner_id)ix_invite_codes_status_expiresON (status, expires_at)
CHECK 约束:
status IN ('active', 'disabled')used_count >= 0max_uses IS NULL OR max_uses > 0
profiles 表变更
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| referred_by | UUID | FK → profiles.id, nullable | 被谁邀请 |
索引:
ix_profiles_referred_byON (referred_by)
API 变更
POST /auth/verifications
Request:
{
"username": "string (3-30 chars)",
"email": "string (email)",
"password": "string (min 6 chars)",
"redirect_to": "string?",
"invite_code": "string (8 chars)?" // 新增,可选
}
Response: 202 Accepted(不变)
注册流程
┌─────────────────────────────────────────────────────────────────┐
│ 1. POST /auth/verifications │
│ - 存储 username + invite_code 到 Supabase metadata │
│ - 发送 OTP 邮件 │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 2. POST /auth/verifications/verify │
│ - 验证 OTP │
│ - 创建 auth.users 记录 │
│ - 触发 on_auth_user_created trigger │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 3. Trigger: on_auth_user_created │
│ a. INSERT INTO profiles (id, username, ...) │
│ b. 生成 8 位随机邀请码 │
│ c. INSERT INTO invite_codes (code, owner_id, ...) │
│ d. 从 metadata 取 invite_code,执行邀请校验逻辑 │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 4. 邀请码校验逻辑 │
│ IF invite_code 存在 AND │
│ status = 'active' AND │
│ (expires_at IS NULL OR expires_at > now()) AND │
│ (max_uses IS NULL OR used_count < max_uses) │
│ THEN │
│ UPDATE profiles SET referred_by = invite_codes.owner_id │
│ UPDATE invite_codes SET used_count = used_count + 1 │
│ END IF │
└─────────────────────────────────────────────────────────────────┘
邀请码生成规则
- 8 位随机字符串
- 字符集:
ABCDEFGHJKLMNPQRSTUVWXYZ23456789(排除易混淆字符 0/O/1/I/L) - 唯一性:数据库 UNIQUE 约束 + 生成时冲突重试(最多 10 次)
使用记录查询
通过 profiles 表查询:
-- 查询某个邀请码的使用记录
SELECT p.id, p.username, p.created_at
FROM profiles p
JOIN invite_codes ic ON ic.owner_id = :owner_id
WHERE p.referred_by = ic.owner_id
ORDER BY p.created_at DESC;
-- 查询某个用户邀请了多少人
SELECT COUNT(*) FROM profiles WHERE referred_by = :user_id;
边界情况
| 场景 | 处理方式 |
|---|---|
| 邀请码不存在 | 跳过邀请,注册正常成功 |
| 邀请码已禁用 | 跳过邀请 |
| 邀请码已过期 | 跳过邀请 |
| 邀请码已达上限 | 跳过邀请 |
| 用户自邀(用自己的码) | 不可能,用户注册时还没有邀请码 |
| 重复使用同一邀请码 | 允许(until max_uses) |
后续扩展
- 奖励系统:通过
reward_configJSONB 字段配置不同奖励策略 - 运营批量码:
owner_id = NULL的邀请码,支持市场推广 - 邀请排行榜:基于
used_count或 profiles 关联查询 - 邀请码回收:软删除
deleted_at,保留历史记录
迁移计划
- 新增迁移文件创建
invite_codes表 - 新增迁移文件给
profiles表添加referred_by字段 - 修改
on_auth_user_createdtrigger 增加邀请码逻辑 - 修改
VerificationCreateRequestschema 添加invite_code字段 - 修改
create_verificationgateway 传递invite_code到 metadata
测试用例
- 注册时不填邀请码 → 正常注册,生成专属邀请码
- 注册时填写有效邀请码 → 关联邀请关系,used_count +1
- 注册时填写无效邀请码 → 正常注册,无邀请关系
- 邀请码达上限后使用 → 正常注册,无邀请关系
- 运营邀请码使用 → 正常注册,无 referred_by(owner_id = NULL)