Skip to content

feat(auth): 开放邀请码注册,补齐填写邀请码接口 #355

Description

@xiaocheny214

背景

#327 在内测阶段关闭了公开注册。现在重新开放注册,以及验证码登录自动建号。邀请码是注册阶段的可选拉新手段,不是登录后补填关系。

后端实现见 #357;账号中心 / 工作台入口见 #359#362#363

产品规则

  1. 注册邀请码选填
    POST /auth/registerinvite_code 可选。

    • 有效且未过期:注册赠送 + 被邀请人邀请奖励;邀请人奖励受日限额
    • 缺省或空白:只发注册赠送
    • 非法或不存在:不建号,「邀请码无效」
    • 已过期:不建号,「邀请码已过期」(业务码 404)
  2. 邀请码只在注册时生效
    没有登录后补填。错过注册填写,只能再通过邀请别人获得奖励。分享链接仍是 /?account=register&invite=XXXX

  3. 验证码登录自动建号
    POST /auth/login-by-code:未知邮箱建号并送注册积分;已有账号只登录。此接口不兑换邀请码。

  4. 邀请码有效期
    生成后 QUOTA_INVITE_CODE_TTL_DAYS 天内有效,默认 30 天。过期后该码不能再用于注册。GET /quota/invite/code 若当前码已过期,自动签发新码(旧行保留)。

  5. 邀请码只增不删、全局唯一
    每个 code 永不复用、不覆盖。轮换是插入新行,并把仍有效的旧码 expires_at 置为当前时间(立即失效,行仍在,已发生的邀请记录继续指向旧码)。

  6. 邀请人每日奖励上限(不是流水总入账上限)
    未过期的码仍可被任意多名新用户注册使用,邀请关系照写。used_count 只计数、不封顶。
    邀请人每个 UTC 自然日最多因 3 次成功邀请获得奖励(QUOTA_INVITE_REWARD_DAILY_LIMIT,默认 3 × 200 = 600)。第 4 人及以后:关系仍写入,被邀请人仍得邀请奖励,邀请人当日不再入账。次日按 UTC 零点重置。
    计数口径:只数 windup_invite_record 里该邀请人当日新增的邀请关系,不扫描 windup_credit_transaction。因此注册赠送、生成扣费、以及后续付费购买 / 套餐兑换(应使用独立 CreditReason)都不会占用这 3 次 / 600 分。

  7. 积分

    场景 新用户 邀请人
    无邀请码注册 注册赠送 300
    有未过期邀请码注册(邀请人当日第 1–3 次) 注册赠送 300 + 邀请奖励 200 邀请奖励 200
    有未过期邀请码注册(邀请人当日第 4 次及以后) 注册赠送 300 + 邀请奖励 200 0(关系仍写入)
    验证码登录新建号 注册赠送 300

    QUOTA_REGISTER_GIFT_AMOUNT 默认 300;QUOTA_INVITE_REWARD_AMOUNT 默认 200。
    流水:REGISTER_GIFT / register:{user_id}INVITE_REWARD / invite:{invitee_id}:inviterinvite:{invitee_id}:invitee。邀请人超限时不写 *:inviter 那条流水。

  8. 形态
    字符集 ABCDEFGHJKLMNPQRSTUVWXYZ23456789(排除 I/O/0/1),长度 4–16,生成长度 8,大小写规范化。

主流程

注册
  ├─ 无 invite_code ──► 建号 + 300
  ├─ 有效未过期 ──► 建号 + 300 + 被邀请人 200
  │     ├─ 邀请人当日第 1–3 次 ──► 邀请人 +200(当日最多 600)
  │     └─ 邀请人当日第 4 次及以后 ──► 邀请人 +0,关系仍写入
  ├─ 已过期 ──► 不建号,「邀请码已过期」
  └─ 非法/不存在 ──► 不建号,「邀请码无效」

验证码登录
  ├─ 邮箱已存在 ──► 只登录
  └─ 邮箱不存在 ──► 建号 + 300(不兑邀请码)

我的邀请码
  GET  /quota/invite/code      返回未过期码;没有或已过期则签发新行
  POST /quota/invite/generate  插入新码,旧码立即过期但行保留

数据模型

windup_invite_code(历史码全部保留)

约束 说明
id PK
user_id NOT NULL, 索引(非唯一) 同一用户可有多行
code UNIQUE NOT NULL, String(16) 全局唯一,只增不改
used_count NOT NULL, 默认 0 该码成功邀请次数
expires_at timestamptz NOT NULL 过期时间;轮换时把旧行提前截断到现在
create_at / update_at timestamptz

当前有效码 = 该用户 expires_at > nowid 最大的一行。

windup_invite_record

约束 说明
id PK
inviter_id NOT NULL, 索引
invitee_id UNIQUE NOT NULL 每人最多一次邀请关系(仅注册时写入)
code NOT NULL 注册时使用的码,可指向已过期历史行
create_at timestamptz 日限额按此字段的 UTC 自然日计数

API

鉴权:register / send-code / login-by-code 白名单;invite 的 GET/POST generate 需登录。

已删除 POST /quota/invite/redeem(不再支持登录后补填)。

POST /auth/register

invite_code 可省略。过期码返回 message「邀请码已过期」、code=404。邀请人超日限额时仍建号,不返回错误。

POST /auth/login-by-code

未知邮箱建号并送注册积分。

GET /quota/invite/code

{
  "code": "AB23CD45",
  "used_count": 3,
  "expires_at": "2026-09-17T01:02:03Z",
  "create_at": "2026-08-18T01:02:03Z",
  "update_at": "2026-08-18T01:02:03Z"
}

POST /quota/invite/generate

插入新码并立即过期旧码。响应同上。

业务错误文案

情况 message code
非法或不存在 邀请码无效 400
已过期 邀请码已过期 404
邮箱已注册 邮箱已注册 400
账号封禁 账号已被封禁 400

前端分工(本 issue 不改前端)

PR 内容
#362 账号中心展示邀请码与分享链接;需去掉补填,并处理过期链接
#363 工作台入口提示(双方各得 200;可提示邀请人每日最多 3 次 / 600 分)

不包含

  • 运营后台批量发码
  • 邀请排行 / 独立落地页
  • 邀请人数终身上限
  • 登录后补填邀请码
  • 验证码登录时兑换邀请码
  • 付费购买积分、套餐兑换积分(独立 CreditReason,不走邀请日限额)

验收

  • 不带邀请码可注册,只发 300
  • 未过期邀请码注册:新用户 500;邀请人当日第 1–3 次得 200
  • 同一 UTC 日第 4 次邀请:仍建号、仍写关系、被邀请人仍得 200,邀请人当日不再 +200
  • 过期码不建号,返回「邀请码已过期」
  • 轮换后旧码行仍在且不能再注册;新码可用
  • GET 在旧码过期后签发新码,不覆盖旧行
  • login-by-code 未知邮箱建号送 300
  • POST /quota/invite/redeem
  • openapi.json 同步

相关

Metadata

Metadata

Labels

enhancementNew feature or request

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions