开发者用户图与邀请
目标读者:设计组织、项目和团队访问模型的后端与控制台开发者。
Alpha 账号的 user_type 是 developer 或 system_admin。开发者可以注册、登录、创建组织、创建项目并生成 Project Key;Project Key 可以使用 Public API 的 GET /v1/sdk/config、POST /v1/feedback/reports 和受 consent 限制的附件路由,但不能访问 /admin/v1/*。账号类型与 tenant 权限彼此独立,后台组织和项目访问始终由 membership 决定。
最小示例
flowchart LR
User["authenticated user"] --> UserType["user_type"]
UserType --> Developer["developer"]
UserType --> SystemAdmin["system_admin"]
User --> OrgMembership["organization membership"]
User --> ProjectMembership["project membership"]
OrgMembership --> Organization["organization"]
ProjectMembership --> Project["project"]
Organization --> Project["project"]
SystemAdmin --> SystemUsers["GET /admin/v1/system/users"]
Project --> ProjectKey["Project Key"]
ProjectKey --> PublicAPI["Public API SDK 配置与反馈写入"]
Project --> FeedbackReport["feedback_report"]
AdminUser 合同中的 user_type 是 system_admin 和 developer,用户状态是 active、disabled、pending_verification。system_admin 的唯一额外系统级能力是只读的 /admin/v1/system/users;它不是 tenant role,也不会自动获得任何组织或项目。system admin 如果加入 tenant,响应中的 role 仍是其真实 membership role;没有 membership 时,对该 tenant 的定向请求返回 403。
Organization 和 Project 响应都必须返回 membership role,取值只允许 owner、admin、developer、qa、viewer。成员本身的 user_type 可以是 developer 或 system_admin,但不会改变该 role。E2E 矩阵会验证开发者 A 创建组织/项目/key,开发者 B 通过邀请加入并读取项目,开发者 C 被拒绝访问。
GET /admin/v1/developer-graph 是一次返回当前用户及全部可见 organizations、projects、organization memberships 和 direct project memberships 的导航聚合。它不是 canonical list GET,不接受 limit/offset,响应也不使用 { items, offset, limit, total, has_more }。单独的组织、项目和成员集合端点仍使用分页契约。
邀请属于 canonical Alpha 管理 API。控制台通过 /admin/v1/organizations/{organization_id}/developer-invitations 创建和列出组织邀请。邀请方只复制一次性 token,不生成含凭证的链接。接受方打开不含凭证的 /invitations/accept 页面;未登录时先完成登录或注册,返回该页面后粘贴 token。token 只存在当前表单内存中,并通过 JSON body 发送到 /admin/v1/invitations/accept;不得进入 URL、return_to、浏览器存储或日志。
未带 project_id 的邀请会创建组织成员关系,并出现在 developer graph 的 memberships 中。带 project_id 的邀请只创建项目成员关系,并出现在 project_memberships 中;接受者可以访问该项目、反馈、附件和评论,但不能读取组织详情,也不会出现在组织成员列表里。
组织级邀请:
curl -X POST "$ADMIN_API/admin/v1/organizations/$ORG_ID/developer-invitations" \
-H "Authorization: Bearer $TOKEN_A" \
-H "Content-Type: application/json" \
-d '{"email":"developer-b@example.com","role":"developer"}'
curl -X POST "$ADMIN_API/admin/v1/invitations/accept" \
-H "Authorization: Bearer $TOKEN_B" \
-H "Content-Type: application/json" \
-d '{"token":"enb_inv_..."}'
项目级邀请:
curl -X POST "$ADMIN_API/admin/v1/projects/$PROJECT_ID/invitations" \
-H "Authorization: Bearer $TOKEN_A" \
-H "Content-Type: application/json" \
-d '{"email":"developer-d@example.com","role":"qa"}'
curl -X POST "$ADMIN_API/admin/v1/invitations/accept" \
-H "Authorization: Bearer $TOKEN_D" \
-H "Content-Type: application/json" \
-d '{"token":"enb_inv_..."}'
接受项目级邀请后,被邀请开发者访问 GET /admin/v1/projects/{project_id} 会成功,但访问 GET /admin/v1/organizations/{organization_id} 会返回 403。项目邀请列表和撤销响应不能包含 accept_token;只有创建响应会一次性显示它。撤销响应会包含 revoked_by_user_id 和 revoked_at,邀请审计 metadata 不能包含 token 值。
Alpha 验证矩阵使用 Developer B 测试组织级邀请,使用 Developer D 测试项目级邀请,Developer C 必须始终被拒绝。
常见错误
- 不要让 project key 读取反馈或管理用户。
- 不要根据
user_type绕过 tenant membership 检查。 - 不要创建含 token 的邀请 URL;只共享一次性 token 和通用
/invitations/accept页面。 - 不要在日志或列表响应中存储或暴露邀请 token。
- 不要对 Developer Graph 发送分页参数,也不要把它解析成 list envelope。
下一步
本地链路不通时阅读 故障排查。