组织与角色
组织用于把多个账号放进同一成员和账单范围。个人工作区和团队工作区可以切换;工具历史和积分当前仍属于个人账号,不会随着团队切换共享给其他成员。
当前可以做什么
- 在工作台侧栏的工作区选择器切换个人工作区或自己所属的团队。
- 在
/members创建团队;已有团队时仍可创建第二个团队。创建后自动切换到新团队。 - 按姓名或邮箱搜索整个团队的成员,每页 20 人,提供上一页、下一页和结果数量。
- 切换后重新读取会话、刷新工作区列表和成员查询,并使旧账单缓存失效。切换完成前禁用重复操作。
邀请邮件投递、邀请接受、成员角色编辑与成员移除界面仍待开发。 不应把现有成员目录当作完整的邀请或权限管理产品。
配置与代码入口
| 位置 | 内容 |
|---|---|
apps/api/lib/auth.ts | 组织插件、会话初始组织、支付权限 |
db/schema/organization.ts | 组织和成员数据 |
apps/app/components/layout/workspace-switcher.tsx | 工作区切换、加载与失败恢复 |
apps/app/lib/queries/organization.ts | 组织列表、创建、切换、搜索缓存 |
apps/app/routes/(app)/members.tsx | 成员搜索、分页和新团队表单 |
apps/api/routers/organization.ts | 带成员权限校验的跨页姓名 / 邮箱搜索 |
apps/api/routers/billing.ts | 活动组织成员校验和账单查询 |
插件允许用户创建组织,每个用户创建上限为五个,创建者角色为 owner。限制由服务端执行;组织选择器展示的是自己所属的组织,不能据其总数判断自己创建的组织数量。
角色与权限
| 角色值 | 中文含义 | 当前组织账单权限 |
|---|---|---|
owner | 所有者 | 可以管理 |
admin | 管理员 | 可以管理 |
member | 普通成员 | 可以查看所属组织套餐,不能管理 |
创建与切换调用 Better Auth 组织插件,由插件校验成员关系。成员搜索新增 tRPC 读取接口,因为插件原有过滤字段不能跨成员表搜索用户姓名和邮箱。该接口每次使用实时数据库重新校验成员关系;不信任前端组织 ID 或会话中的活动组织 ID,也不使用 Hyperdrive 缓存连接查询权限。
成员目录对组织内成员开放,只返回成员 ID、角色及用户 ID / 姓名 / 邮箱,不返回密码、凭据或其他账号字段。搜索只作用于授权组织,分页采用加入时间和成员 ID 的稳定排序;%、_ 和反斜杠按普通字符搜索。查询参数限制搜索文本长度和页码范围。
活动组织如何选择
新建会话时,findInitialOrganization() 按加入时间升序选择用户最早加入的组织;时间相同时按成员 ID 排序。没有成员关系时,活动组织为空。当前选择保存在当前服务端会话,重新登录仍按上述初始规则选择,不承诺跨会话记住上次工作区。
注册账号不会自动创建组织。成员页使用随机后缀生成唯一标识,同名团队和中文名称都可创建;创建成功后等待会话刷新,再显示新团队成员。创建失败保留表单和当前工作区,并显示服务端错误。
切换到个人工作区向插件提交 organizationId: null。只有服务端响应后才刷新界面,不先在本地假设切换成功。插件在拒绝已失去成员关系的工作区时可能清空活动组织,因此切换失败也要重新读取会话。侧栏保留错误提示;不可用团队可通过选择个人工作区恢复,组织列表加载失败可点击重试。
查询键包含用户、组织、搜索文本和页码。不同团队及不同搜索页面不复用结果;切换后回到第 1 页并清空成员搜索。工作区创建与切换串行执行,避免两个操作同时修改服务端会话。
组织与个人账单
存在活动组织时按组织计费,否则按用户个人计费。套餐查询使用实时 ctx.db 校验当前成员;订阅变更由 Stripe 插件的 authorizeReference 再校验所有者或管理员角色。
切换时取消旧账单请求、使账单缓存失效,再刷新会话和活动账单查询。会话查询在原缓存条目上更新,保持已挂载页面的订阅连接;不能直接移除正在使用的会话查询,否则侧栏和正文可能读取不同的会话状态。成员页不会用某个团队的套餐缓存展示另一个团队的状态。真实 Stripe 收费和回调仍需单独沙箱验收。
排查与验收
- 无团队账号打开成员页:显示个人工作区说明和创建表单。
- 创建两个团队:分别成为活动团队,两者都出现在侧栏选择器中。
- 在两支团队与个人工作区之间切换:选择器、成员目录和账单范围保持一致;历史和积分仍为本人数据。
- 搜索位于第二页的成员:第 1 页搜索结果能找到,不只搜索当前已加载数据。
- 超过 20 名成员:上一页 / 下一页覆盖全部成员,无重复;无匹配项显示空状态。
- 使用他人组织 ID 或已撤销成员关系:搜索与切换由服务端拒绝;旧会话不授予访问权。
- 切换失败:显示错误并重新同步会话,可回个人工作区;创建达到上限时显示错误且不改变当前工作区。
自动化检查涵盖真实数据库搜索、分页、成员隔离、撤销后的访问、特殊搜索字符、工作区切换接口与客户端缓存恢复。Cloudflare 部署、邀请投递和 Stripe 沙箱不属于这次已验证范围。