邀请码模块 (Invite Code)
SayClaw 通过邀请码机制控制 OC 实例的领取资格。用户在领取实例时必须填写有效的邀请码,管理员可在 Admin 后台批量生成和管理邀请码。
设计目标
- 防止陌生人随意领取 OC 实例
- 支持定向分发(一人一码)和批量发放(多人共用)
- 完整的使用记录,可追溯每个码被谁、何时使用
数据库表
invite_codes — 邀请码主表
CREATE TABLE invite_codes (
id VARCHAR(36) PRIMARY KEY DEFAULT (UUID()),
code VARCHAR(32) NOT NULL UNIQUE,
note VARCHAR(255),
max_uses INT NOT NULL DEFAULT 1,
used_count INT NOT NULL DEFAULT 0,
expires_at DATETIME(3),
created_by VARCHAR(100),
created_at DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3),
INDEX idx_code (code)
);
| 字段 | 说明 |
|---|---|
code | 邀请码,格式 SAYCLAW-XXXXXXXX(8位大写字母数字) |
max_uses | 可使用次数;1 = 一次性;0 = 无限次 |
used_count | 已使用次数,每次成功领取 +1 |
expires_at | 过期时间,NULL 表示永不过期 |
note | 备注,如「送给 xxx」或「3月内测活动」 |
invite_code_uses — 使用记录表
CREATE TABLE invite_code_uses (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
code_id VARCHAR(36) NOT NULL,
user_id VARCHAR(36) NOT NULL,
instance_id VARCHAR(100) NOT NULL,
used_at DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3),
INDEX idx_code_id (code_id),
INDEX idx_user_id (user_id)
);
邀请码格式
SAYCLAW-X7K2MPQ4
- 前缀固定
SAYCLAW- - 后接 8 位大写字母 + 数字随机串
- 生成时自动去重,保证全库唯一
领取实例流程
用户点击「绑定」
↓
弹出邀请码确认框(必填)
↓
POST /api/v1/me/instances/claim
{ instance_id, invite_code }
↓
① 邀请码存在且未过期
② used_count < max_uses(或 max_uses=0)
③ 该用户未用过此码(invite_code_uses 查重)
④ 该用户当前实例数 < 1(每人限一个)
↓
全部通过
① INSERT user_instances
② INSERT invite_code_uses
③ UPDATE invite_codes SET used_count = used_count + 1
④ 触发 init_instance 任务(自动初始化 OC 实例)
错误码
| 场景 | 返回提示 |
|---|---|
| 邀请码字段为空 | "请填写邀请码" |
| 邀请码不存在 | "邀请码无效" |
| 邀请码已过期 | "邀请码已过期" |
| 邀请码次数已用完 | "邀请码已被使用完" |
| 同一用户重复使用同一码 | "你已使用过该邀请码" |
| 用户已有实例 | "每人仅限领取一个实例" |
Admin 管理接口
| 方法 | 路径 | 说明 |
|---|---|---|
GET | /api/v1/admin/invite-codes | 邀请码列表(含使用统计) |
POST | /api/v1/admin/invite-codes | 批量生成邀请码 |
DELETE | /api/v1/admin/invite-codes/:id | 作废某个码 |
GET | /api/v1/admin/invite-codes/:id/uses | 查看某码的使用记录 |
生成接口请求体
{
"count": 5,
"max_uses": 1,
"expires_days": 30,
"note": "3月内测用户"
}
| 字段 | 必填 | 说明 |
|---|---|---|
count | 是 | 一次生成几个,最多 100 |
max_uses | 否 | 每个码可用次数,默认 1;0 = 无限 |
expires_days | 否 | 有效天数,不填 = 永不过期 |
note | 否 | 备注说明 |
列表响应示例
{
"code": "0000",
"data": [
{
"id": "abc-123",
"code": "SAYCLAW-X7K2MPQ4",
"note": "3月内测用户",
"max_uses": 1,
"used_count": 0,
"expires_at": "2026-04-05T00:00:00Z",
"status": "valid",
"created_at": "2026-03-05T00:00:00Z"
}
]
}
status 取值:valid(有效)/ exhausted(已用完)/ expired(已过期)/ revoked(已作废)
Portal 前端交互
用户点击「绑定」后弹出二次确认框:
┌──────────────────────────────────┐
│ 🎫 输入邀请码领取实例 │
│ │
│ 实例:小二-实例06 │
│ │
│ 邀请码 [___________________] │
│ 没有邀请码?联系管理员 │
│ │
│ [取消] [确认领取] │
└──────────────────────────────────┘
- 邀请码输入框自动转为大写
- 点击「确认领取」时前端验证格式(非空,
SAYCLAW-前缀可选校验) - 成功后弹窗关闭,实例卡片刷新
Admin 后台页面(Soybean Admin)
新增「邀请码管理」菜单,功能包括:
| 功能 | 说明 |
|---|---|
| 邀请码列表 | 表格展示:码 / 备注 / 已用/上限 / 过期时间 / 状态 |
| 一键生成 | 弹窗填参数,批量生成并展示结果(可复制) |
| 作废 | 立即失效,已使用记录保留 |
| 使用记录 | 查看某码被哪些用户在何时用于领取哪个实例 |
实现优先级
| 阶段 | 内容 | 状态 |
|---|---|---|
| P0 | 建 invite_codes + invite_code_uses 表 | 待实现 |
| P0 | portal-api claimInstanceHandler 加邀请码校验 | 待实现 |
| P0 | portal 前端领取弹窗加邀请码输入框 | 待实现 |
| P1 | admin-api 4 个管理路由 | 待实现 |
| P1 | Soybean Admin「邀请码管理」页面 | 待实现 |