Auth & Workspace
Auth & Workspace
1. 目标 & 范围
目标:提供最小可用的多租户认证与 Workspace 管理能力,确保不同团队的研究数据严格隔离,并支持匿名受访者通过公开链接参与访谈。
在范围内(P0 MVP):
- 用户注册、登录与会话认证(邮箱+密码)
- Workspace 创建与基本 CRUD
- Workspace 成员邀请与角色分配(
researcher/admin) - 跨 Workspace 数据隔离(所有业务对象归属 workspace)
- Participant 匿名访问——通过
public_slug无需登录进入访谈 - Participant 记录创建与匿名标识
不在范围内(列入非目标):
- SSO / OAuth 第三方登录
- 复杂多团队分级权限(跨 Workspace 共享角色)
- Viewer 只读角色(P1 可扩展)
- 细粒度 Project 级权限覆盖(P1)
- SAML / SCIM 企业目录同步
2. 用户故事
researcher
- 作为 researcher,我希望用邮箱注册并创建 Workspace,以便开始管理研究项目。
- 作为 researcher,我希望邀请同事加入 Workspace 并分配角色,以便团队协作。
- 作为 researcher,我希望在 Workspace 内创建的 Projects 和 Studies 对其他 Workspace 不可见,以便保护研究数据安全。
admin
- 作为 admin,我希望能修改 Workspace 名称、管理成员(含移除),以便维护租户配置。
- 作为 admin,我希望查看成员列表及其角色,以便审计权限状态。
- 作为 admin,我希望所有关键操作都写入审计日志,以便事后追溯。
participant(受访者)
- 作为 participant,我希望通过 public link 直接进入访谈,无需注册账号,以便降低参与门槛。
- 作为 participant,我希望在访谈开始前看到数据使用说明与退出方式,以便知情同意。
- 作为 participant,我希望自己的身份在 Workspace 内用匿名 ID 标识,以便保护隐私。
3. 功能需求
3.1 认证
| 编号 | 优先级 | 描述 | 验收要点 |
|---|---|---|---|
| FR-01-01 | P0 | 邮箱+密码注册 | 邮箱格式校验;密码强度不低于 8 位含字母+数字;同一邮箱不可重复注册(返回 409);注册后自动登录并颁发会话 token |
| FR-01-02 | P0 | 邮箱+密码登录 | 凭证错误返回 401(不区分邮箱/密码哪个错);连续失败 5 次触发 30 秒冷却;登录成功颁发 JWT(含 user_id、workspace_id 列表、exp) |
| FR-01-03 | P0 | 会话 token 刷新 | access token 有效期 15 分钟;refresh token 有效期 7 天;刷新端点在 access token 过期后仍可用;refresh token 单次消费(rotation) |
| FR-01-04 | P0 | 登出 | 服务端使 refresh token 失效;前端清除本地存储 token |
| FR-01-05 | P0 | 密码重置 | 发送重置邮件(含带时效签名链接,有效期 1 小时);重置后所有已有 session 失效 |
3.2 Workspace 管理
| 编号 | 优先级 | 描述 | 验收要点 |
|---|---|---|---|
| FR-01-06 | P0 | 创建 Workspace | 注册流程后自动提示创建或加入 Workspace;name 必填,slug 自动生成(可手动改,全局唯一,仅含小写字母/数字/连字符);创建者自动成为 admin 角色 |
| FR-01-07 | P0 | 查询 & 切换 Workspace | 已登录用户可查看所有已加入的 Workspace 列表;切换 Workspace 时重新获取该 Workspace 的 context;同一用户可同时属于多个 Workspace |
| FR-01-08 | P0 | 更新 Workspace | admin 可修改 name 和 slug(slug 变更需确认,影响公开链接);researcher 无权修改 |
| FR-01-09 | P0 | 删除 Workspace | 仅 admin 可软删除;删除前要求输入 Workspace 名称确认;删除后该 Workspace 的所有 project / study / session / KB 数据不对外可见;写入 audit_logs |
3.3 成员管理
| 编号 | 优先级 | 描述 | 验收要点 |
|---|---|---|---|
| FR-01-10 | P0 | 邀请成员 | admin 可通过邮箱发送邀请;被邀请者尚未注册时邀请链接引导注册后自动加入;邀请链接有效期 72 小时;同一邮箱/Workspace 组合已存在时返回提示 |
| FR-01-11 | P0 | 角色分配 | 支持 admin / researcher 两种角色(见权限矩阵 §4);admin 可更改其他成员角色,但不可降级自己为最后一个 admin;角色变更写入 audit_logs |
| FR-01-12 | P0 | 移除成员 | admin 可将成员从 Workspace 移除;移除后该成员立即失去对该 Workspace 的 API 访问权;写入 audit_logs |
| FR-01-13 | P0 | 退出 Workspace | researcher 可主动退出;Workspace 唯一 admin 不可退出(须先转移 admin 或删除 Workspace) |
3.4 数据隔离
| 编号 | 优先级 | 描述 | 验收要点 |
|---|---|---|---|
| FR-01-14 | P0 | Workspace 级数据隔离 | 所有 API 查询必须携带 workspace_id scope;projects、studies、sessions、knowledge_bases、participants 均通过外键归属 workspace;服务层在 SQL 层强制追加 workspace_id = ? 条件,不依赖业务逻辑层过滤 |
| FR-01-15 | P0 | Participant 访问边界 | 持有 public_slug 的 participant 只能访问对应 study 的 session(读/写),不能枚举同 Workspace 其他 study/project;participant API 端点与 admin API 端点路径分离,中间件不互通 |
| FR-01-16 | P0 | 审计日志写入 | 以下操作必须写 audit_logs:Workspace CRUD、成员邀请/移除/角色变更、study 发布/下线、export 操作;actor_id 在 participant 操作时为空,resource_type 标注 participant |
3.5 Participant 匿名访问
| 编号 | 优先级 | 描述 | 验收要点 |
|---|---|---|---|
| FR-01-17 | P0 | Public link 进入访谈 | Participant 访问 GET /s/{public_slug} 无需登录;后端校验 study 状态为 published、public_slug 有效且未过期;校验通过后颁发临时 participant_token(JWT,仅含 participant_id + session_id + exp) |
| FR-01-18 | P0 | Participant 记录创建 | 首次进入时在 participants 表创建记录,workspace_id 来自 study 归属链(study → project → workspace);external_id 可选(由 URL query 参数传入,如招募平台 ID);匿名场景下 external_id 为空 |
| FR-01-19 | P0 | Public link 安全控制 | public_slug 使用 URL-safe 随机字符串(不可枚举);study 支持设置最大 session 数上限(超出拒绝新建);参见 06_ops/02_security_privacy 的 Public Link 安全节 |
| FR-01-20 | P0 | Consent 页面 | Participant 首次进入时展示知情同意页(调研目的、AI 主持说明、录音/记录说明、退出方式);同意前不创建 session;拒绝则跳出,不写 participants 记录 |
4. 关键流程
4.1 用户注册 & Workspace 创建
用户填写邮箱+密码 → POST /auth/register(创建 users 记录) → 返回 access_token + refresh_token → 前端跳转「创建或加入 Workspace」 → POST /workspaces(创建 workspaces 记录) → 创建 workspace_members 记录(role=admin) → 跳转 Workspace Dashboard4.2 成员邀请 & 加入
admin 输入被邀请者邮箱 + 选择角色 → POST /workspaces/{workspace_id}/invitations → 系统发送邀请邮件(含签名链接) → 被邀请者点击链接 → 若未注册:引导注册 → 自动加入 → 若已注册:直接加入(创建 workspace_members 记录) → 角色分配写入 audit_logs4.3 Participant 访问流程
研究人员发布 study(生成 public_slug) → 受访者访问 /s/{public_slug} → 后端校验 study 状态 & slug 有效性 → 前端展示 Consent 页面 → Participant 同意 → 后端创建 participants 记录(匿名或带 external_id) → 后端创建 sessions 记录 → 颁发 participant_token → 进入 Interview Runtime(见 [04_interview_runtime](/02_product/prd/04_interview_runtime))5. 数据
本模块涉及以下 data_model.md 中定义的表:
| 表名 | 本模块用途 |
|---|---|
users | 存储已注册的研究人员/admin 账号(邮箱、密码哈希、创建时间) |
workspaces | 顶层租户容器(id、name、slug、时间戳) |
workspace_members | 多对多关联 users ↔ workspaces,含 role(admin / researcher) |
participants | 受访者记录,workspace_id FK,含可选 external_id 与 metadata JSONB |
audit_logs | 记录所有关键操作,含 actor_id(可空)、action、resource_type、resource_id、before/after |
users表未在 data_model.md 中显式定义,MVP 实现时需补充(至少含id UUID、email TEXT UNIQUE、password_hash TEXT、created_at、updated_at)。
workspace_members表需补充(至少含id UUID、workspace_id UUID FK、user_id UUID FK、role TEXT、invited_by UUID、joined_at TIMESTAMPTZ)。
6. 接口
| 方法 | 路径 | 描述 | 认证 |
|---|---|---|---|
POST | /auth/register | 注册新用户 | 无 |
POST | /auth/login | 邮箱+密码登录,返回 JWT | 无 |
POST | /auth/refresh | 刷新 access token | refresh token |
POST | /auth/logout | 使 refresh token 失效 | access token |
POST | /auth/password-reset/request | 发送密码重置邮件 | 无 |
POST | /auth/password-reset/confirm | 提交新密码 | 签名链接 token |
POST | /workspaces | 创建 Workspace | access token |
GET | /workspaces | 查询当前用户所属 Workspace 列表 | access token |
GET | /workspaces/{workspace_id} | 获取单个 Workspace 详情 | access token + member |
PATCH | /workspaces/{workspace_id} | 更新 Workspace(admin 权限) | access token + admin |
DELETE | /workspaces/{workspace_id} | 软删除 Workspace(admin 权限) | access token + admin |
GET | /workspaces/{workspace_id}/members | 查询成员列表 | access token + member |
POST | /workspaces/{workspace_id}/invitations | 发送邀请 | access token + admin |
PATCH | /workspaces/{workspace_id}/members/{user_id} | 变更角色 | access token + admin |
DELETE | /workspaces/{workspace_id}/members/{user_id} | 移除成员 | access token + admin |
GET | /s/{public_slug} | Participant 入口,校验 slug,返回 study 基本信息 | 无 |
POST | /s/{public_slug}/sessions | 创建 session(含创建 participant 记录) | 无(或 Consent 确认 token) |
详细请求/响应结构见 api_contracts。
7. 验收标准
| 编号 | 标准(均可自动化测试) |
|---|---|
| AC-01-01 | 相同邮箱二次注册返回 HTTP 409,不创建新 user 记录。 |
| AC-01-02 | 登录凭证错误返回 HTTP 401,响应体不透露是邮箱还是密码错误。 |
| AC-01-03 | access token 过期后使用该 token 访问受保护端点返回 HTTP 401;使用有效 refresh token 换取新 access token 返回 HTTP 200,旧 refresh token 同时失效。 |
| AC-01-04 | 新注册用户在未加入任何 Workspace 时,GET /workspaces 返回空数组。 |
| AC-01-05 | 创建 Workspace 后,workspace_members 表中存在一条 role=admin 记录;workspaces.slug 在数据库层唯一约束可验证。 |
| AC-01-06 | researcher 角色调用 PATCH /workspaces/{id} 返回 HTTP 403。 |
| AC-01-07 | Workspace 唯一 admin 尝试降级自身角色返回 HTTP 422,并附带错误说明。 |
| AC-01-08 | 移除成员后,该成员立即无法访问该 Workspace 的任何端点(下一次请求返回 HTTP 403),无需等待 token 过期。 |
| AC-01-09 | 用 Workspace A 的 member access token 调用 Workspace B 的 GET /workspaces/{B}/members 返回 HTTP 403。 |
| AC-01-10 | GET /projects?workspace_id=A 在 SQL 层强制过滤,伪造 workspace_id 参数不返回其他 Workspace 的数据(可通过 SQL 查询日志验证)。 |
| AC-01-11 | 访问已下线(status != published)study 的 public link 返回 HTTP 404 或引导页,不进入访谈流程。 |
| AC-01-12 | 持有 participant_token 的请求不能访问 admin API(如 GET /workspaces),返回 HTTP 403。 |
| AC-01-13 | Participant 拒绝 Consent 后,participants 和 sessions 表中不产生新记录。 |
| AC-01-14 | study 设置最大 session 数为 N,第 N+1 次 POST /s/{slug}/sessions 请求返回 HTTP 429 或 403 并附带说明。 |
| AC-01-15 | 以下操作在 audit_logs 中各产生一条记录:Workspace 创建、成员邀请、角色变更、成员移除、Workspace 删除。 |
8. 边界 & 非目标
边界说明:
- 本模块只覆盖认证与 Workspace 层;Project / Study 的创建与管理见 02_projects_studies。
- Participant 的 session 生命周期(进入访谈、transcript、extraction)见 04_interview_runtime。
- Public link 的
public_slug字段定义在studies表,由 03_study_builder 中的发布流程生成;本模块仅负责入口校验与 participant 记录创建。
非目标(MVP 不做):
- SSO(Google / GitHub / SAML)登录
- 复杂多团队分级权限(跨 Workspace 角色继承)
- Viewer 只读角色
- Project 级权限覆盖(当前权限粒度到 Workspace)
- SCIM 自动化用户供给
- 邮箱验证(注册后强制验证)——MVP 注册后直接可用
- 多因素认证(MFA / TOTP)
9. 依赖 & 风险
依赖:
| 依赖项 | 说明 |
|---|---|
| 02_projects_studies | Project / Study 对象的 workspace_id FK 约束由本模块 Workspace 提供 |
| 03_study_builder | study 发布流程生成 public_slug,本模块 participant 入口依赖该字段 |
| 04_interview_runtime | participant_token 颁发后,interview runtime 验证该 token 并绑定 session |
| 06_ops/02_security_privacy | Public link 安全策略(随机 slug、rate limit、allowed domains)详见安全文档 |
audit_logs 表 | 本模块写入量最大,需确保该表有足够的写入性能与索引(resource_type、created_at) |
风险:
| 风险 | 影响 | 缓解措施 |
|---|---|---|
users 与 workspace_members 表尚未在 data_model.md 中显式定义 | 实现阶段可能出现字段对齐问题 | MVP 开始前补充完整 DDL;与 data_model.md 同步更新 |
| Participant token 无法主动撤销(JWT 无状态) | 若 study 提前下线,已颁发 token 在 exp 内仍可用 | 运行时校验 sessions.status 与 studies.status,不依赖 token 有效期单独判断 |
| 邮件发送依赖第三方服务(邀请、密码重置) | 邮件延迟或失败影响用户体验 | MVP 允许管理员手动复制邀请链接作为降级方案;记录发送失败 error log |
| Workspace 软删除后数据可见性 | 已删除 Workspace 的数据若未正确过滤可能泄露 | 所有查询在服务层统一追加 deleted_at IS NULL 条件;写集成测试覆盖 |