From 0d4811fee5bc1b7476a6d10d1579a758f49d2369 Mon Sep 17 00:00:00 2001 From: qzl Date: Fri, 27 Feb 2026 11:10:44 +0800 Subject: [PATCH] docs: add invite code design and backlog for user_agents trigger --- .opencode/opencode.json | 12 ++ docs/bugs/backlog.md | 35 +++++ docs/plans/2026-02-27-invite-code-design.md | 161 ++++++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 .opencode/opencode.json create mode 100644 docs/bugs/backlog.md create mode 100644 docs/plans/2026-02-27-invite-code-design.md diff --git a/.opencode/opencode.json b/.opencode/opencode.json new file mode 100644 index 0000000..69c4387 --- /dev/null +++ b/.opencode/opencode.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://opencode.ai/config.json", + "mcp": { + "supabase_mcp": { + "type": "remote", + "url": "http://localhost:8001/mcp", + "oauth": false, + "enabled": true, + "timeout": 10000 + } + } +} diff --git a/docs/bugs/backlog.md b/docs/bugs/backlog.md new file mode 100644 index 0000000..a316e51 --- /dev/null +++ b/docs/bugs/backlog.md @@ -0,0 +1,35 @@ +# Backlog - Known Issues & Improvements + +## Database Triggers + +### [TRIGGER-001] user_agents 自动创建 + +**Status**: Pending +**Priority**: Medium +**Created**: 2026-02-27 + +**Description**: +当新用户注册时,`user_agents` 表未自动创建默认 Agent 配置记录。 + +**Current Behavior**: +- `auth.users` → `profiles` 已有 trigger 自动创建 +- `user_agents` 无自动创建机制 + +**Expected Behavior**: +新用户注册后,应有默认的 Agent 配置(如 INTENT_RECOGNITION、TASK_EXECUTION、RESULT_REPORTING 三种类型)。 + +**Impact**: +- 用户首次使用 Agent Chat 功能时可能失败 +- 需要应用层手动初始化或前端引导配置 + +**Implementation Notes**: +- 需要先确定 `user_agents` 的默认配置设计 +- 可通过 `on_auth_user_created` trigger 扩展 +- 或在 `profiles` trigger 中调用 + +**Related Files**: +- `backend/alembic/versions/20260226_0001_initial_schema.py` (现有 trigger) +- `backend/src/models/user_agents.py` +- `backend/src/models/profile.py` + +--- diff --git a/docs/plans/2026-02-27-invite-code-design.md b/docs/plans/2026-02-27-invite-code-design.md new file mode 100644 index 0000000..fe31f5d --- /dev/null +++ b/docs/plans/2026-02-27-invite-code-design.md @@ -0,0 +1,161 @@ +# 邀请码机制设计 + +**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_code` ON (code) UNIQUE +- `ix_invite_codes_owner_id` ON (owner_id) +- `ix_invite_codes_status_expires` ON (status, expires_at) + +**CHECK 约束:** +- `status IN ('active', 'disabled')` +- `used_count >= 0` +- `max_uses IS NULL OR max_uses > 0` + +### profiles 表变更 + +| 字段 | 类型 | 约束 | 说明 | +|------|------|------|------| +| referred_by | UUID | FK → profiles.id, nullable | 被谁邀请 | + +**索引:** +- `ix_profiles_referred_by` ON (referred_by) + +## API 变更 + +### POST /auth/verifications + +**Request:** +```json +{ + "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 表查询: + +```sql +-- 查询某个邀请码的使用记录 +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) | + +## 后续扩展 + +1. **奖励系统**:通过 `reward_config` JSONB 字段配置不同奖励策略 +2. **运营批量码**:`owner_id = NULL` 的邀请码,支持市场推广 +3. **邀请排行榜**:基于 `used_count` 或 profiles 关联查询 +4. **邀请码回收**:软删除 `deleted_at`,保留历史记录 + +## 迁移计划 + +1. 新增迁移文件创建 `invite_codes` 表 +2. 新增迁移文件给 `profiles` 表添加 `referred_by` 字段 +3. 修改 `on_auth_user_created` trigger 增加邀请码逻辑 +4. 修改 `VerificationCreateRequest` schema 添加 `invite_code` 字段 +5. 修改 `create_verification` gateway 传递 `invite_code` 到 metadata + +## 测试用例 + +1. 注册时不填邀请码 → 正常注册,生成专属邀请码 +2. 注册时填写有效邀请码 → 关联邀请关系,used_count +1 +3. 注册时填写无效邀请码 → 正常注册,无邀请关系 +4. 邀请码达上限后使用 → 正常注册,无邀请关系 +5. 运营邀请码使用 → 正常注册,无 referred_by(owner_id = NULL)