Design review · 14 November 2026

Account
企业身份与治理

从一封邀请出发,理解企业、成员、组织、用户组和授权如何协作;同时审视设计距离真实可用还有多远。

01 / Boundary

先看清这是什么

account 管理“谁属于哪个企业、组织和用户组,以及在这些范围里有什么管理权”。用户账号与登录身份由 auth 管理;平台操作员及应用分配由 management 管理。

状态判定:仓库没有 account 服务实现。本文的业务流程和 12 张表是设计中的目标状态,不是已经实现或验收的功能。deploy/local/mysql/stubs/30-account.sql 只是本地/测试契约桩,仅含企业、组织、组、审计四张简化表和种子数据;不能用它证明真实业务可运行。

auth · 认证

管理账号、登录、会话与验证结果;account 读取其发布的视图。

account · 治理

管理企业成员、组织、邀请、角色、组、云绑定及本应用审计。

management · 平台

管理操作员与应用分配;按已知 ID 读取 account 的组织、组视图。

02 / Concepts

一张图看关系

auth 账号 U ──< 企业成员资格 >── 企业 E ──< 组织 O │ │ │ │ 发出邀请 I < 组织归属 >── U │ │ ├──< 用户组成员 >── 用户组 G 主组织选择(每账号至多一个) ├──< 角色授予 ──> 企业 / 组织 / 用户组 └──< 验证委托 ──> 邀请或云绑定所有者 云账号绑定:所有者是账号或企业;审计:记录动作、结果及当时核实的企业归属

成员资格 ≠ 组织归属

先成为企业成员才能归属该企业组织;没有业务组织时自动归入默认组织。

组织 ≠ 用户组

组织属于企业并可有层级;用户组是本站集合,可跨企业,管理权独立。

创始人 ≠ 角色

创始人是企业治理身份;角色是单独授予并带具体范围的权限事实。

组织层级只表达结构,不继承管理权限。主组织是账号跨企业的单一选择,可为空;只有当前有效组织归属可被选中。

03 / A story

林加入星河科技

假设本站已有账号:陈(U1)和林(U2)。这是一组虚构的设计示例,ID 是阅读用别名,生产设计使用 UUIDv7。

1 · 开通陈创建星河 E1;成为创始成员,系统建立默认组织 O0,并按条件初始化主组织。
→
2 · 邀请陈邀请 lin@example.com。邀请 I1 规定拟授企业管理员角色。
→
3 · 验证林登录本站;account 核验令牌并登记委托,auth 验证指定邮箱。
→
4 · 接受account 再核对当前邀请、委派资格和验证结果;成员、默认归属、角色与审计同事务提交。

随后陈创建研发部 O1 并安排林加入;林在 E1 有业务组织后,默认归属自动移除。若林此前的主组织指向 O0,该选择先被清空;林可自行选 O1。平台操作员另建跨企业用户组 G1 并任命组管理员,组管理员将林加入。组关系与企业成员资格相互独立。

失败与恢复:邀请过期、撤销、令牌轮换、邮箱验证不匹配、邀请人失去委派资格均不能完成首次接受。接受已提交但响应丢失时,同一账号以原操作键和原请求恢复结果;不能再次消费或重复授予。
04 / Concrete data

把概念放进表里

以下为同一时点的设计示例快照:林已接受邀请并进入研发部。为可读性只展示关键列;T0 为 2026-11-01 09:00,T1 为 11-02 10:00,T2 为 11-03 10:00(UTC);H、D、C 为摘要/密文占位符,非可用凭据。省略的时间戳和摘要列仍须遵循设计。表之间的别名是引用,不是实际 SQL 值。

企业与组织

设计表示例行(关键列)约束与含义
account_enterpriseid=E1 · name=星河科技 · founder_id=U1 · create_operation_id=OP0 · create_request_hash=H0企业 ID 主键;创始人 + 开通请求键唯一。
account_enterprise_member(E1,U1,T0)
(E1,U2,T1)
复合主键 (enterprise_id, account_id);移除后当前关系物理删除。
account_organization(O0,E1,默认组织,NULL,true,E1)
(O1,E1,研发部,NULL,false,NULL)
列依次为 id、enterprise_id、name、parent_id、is_default、default_enterprise_id;每企业至多一个默认组织。
account_organization_member(E1,O0,U1,T0)
(E1,O1,U2,T2)
列为 enterprise_id、organization_id、account_id、joined_at;林有业务归属,故不再属于 O0。
account_primary_organization(U1,O0,T0)
(U2,O1,T2)
列为 account_id、organization_id、updated_at;只能指向本人现有归属。

邀请、验证与权限

设计表示例行(关键列)约束与含义
account_invitationid=I1 · enterprise_id=E1 · normalized_email=lin@example.com · inviter_id=U1 · proposed_role=enterprise_admin · status=accepted · token_version=1 · token_digest=D1 · accepted_account_id=U2 · accept_operation_id=OP1 · accept_request_hash=H1 · accepted_at=T1过期由时间计算;接受的账号、键、摘要和时间共同保存。令牌明文不入表。
account_verification_requestid=VR1 · purpose=invitation_accept · subject_id=U2 · operation_id=OP1 · method=email · normalized_target=lin@example.com · invitation_id=I1 · owner_type=NULL · owner_id=NULL · created_at=2026-11-02 09:55 · expires_at=2026-11-02 10:25这是验证委托,不是验证结果;结果由 auth 持有。示例假定尚未被清理。
account_role_grant(R1,U2,enterprise_admin,enterprise,E1,T1)
(R2,U1,group_admin,group,G1,T2)
列为 id、account_id、role_code、scope_type、scope_id、granted_at;范围配对受约束。

独立用户组、绑定与审计

设计表示例行(关键列)约束与含义
account_user_groupid=G1 · name=试用成员 · description=NULL · created_at=T2组不属于企业;操作员登记,组管理员另行授予。
account_group_member(G1,U2,T2)列为 group_id、account_id、joined_at;移除企业成员不会自动删除组关系。
account_external_bindingowner_type=enterprise · owner_id=E1 · provider=huawei · external_domain=huawei-cn · external_account_id=HC1 · operation_id=OP2 · request_hash=H2 · verification_id=V2 · created_at=T2假设该站能力已验收并开启;同一所有者至多一个绑定,同一云账号可被多个所有者绑定。
account_audit_eventevent_id=A1 · event_version=1 · occurred_at=T1 · category=user · actor_type=user · actor_id=U2 · action=invitation.accept · target_type=invitation · target_id=I1 · enterprise_id=E1 · outcome=success · policy_version=p2 · policy_matches=[] · details={}发生时核实企业归属;记录历史,不依赖业务对象当前存在。其他可空字段此例为 NULL。

上表展示业务关键列,不是完整 DDL 或可直接执行的 INSERT。设计还包含索引、事务、保留和保护规则;完整字段请参阅文末各 DATA 文档。桩 SQL 的结构与这份设计并不完全一致。

05 / Hard review

场景完备吗?还不够。

文档对并发、授权和恢复的设计相当细,但“写了规则”距离“产品场景可交付”还有明显距离。以下区分未实现、未定方案和明确不在首期的边界。

P0 · 没有可运行的 account 服务。 企业开通、邀请、组织和角色都是设计;缺少真实数据库、接口、端到端和故障注入验收。契约桩只说明消费者可开发,不能证明业务能交付。应先打通开通→邀请→接受→撤权的完整链路并留验收证据。
P0 · 企业 IdP 登录缺失。 当前用户登录规格列出验证码、微信、GitHub 等渠道,没有客户企业级 IdP 的配置、发现、协议、身份映射与生命周期规则。操作员 IdP 明确属于平台工作人员,不能当作客户企业 SSO。若企业客户要求员工用自有 IdP 登录,这是首期需求缺口,不能靠邀请自动补齐。
P1 · 企业治理的退出路径不完整。 创始人交接、成员主动退出、组织与组删除明确不在首期。创始人离职、企业解散、误建组织或员工自行离开时缺少产品内闭环;应确定人工恢复、归档与责任人,并明确何时纳入产品。
P1 · 云绑定渠道未落地。 两站渠道步骤与回调待验收,功能受开关控制;首期没有解绑或替换。云账号换主体、误绑或原账号不可用时缺少自助恢复路径。先完成渠道验收与运营处置方案。
P1 · 邀请交付和恢复需要实证。 设计考虑重发、轮换、撤销竞争及响应丢失,但邮件延迟、重复投递、限流、发送失败、验证过期与服务中断仍需真实依赖下测试;“已签发”不等于邮件已送达。
P1 · 离职后的访问范围易被误解。 移除企业成员会清理该企业组织及角色,但独立用户组、应用对账号的直授、个人云绑定仍保留。若业务期望“一键离职即撤销全部访问”,现有边界不满足;必须确定跨企业及平台资源的撤权策略。
P2 · 治理和运维闭环仍待确定。 例如无可用管理员时谁能恢复、数据保留与导出、客户侧排障和批量入离职如何处理,需要按目标客户与运营责任补充需求、流程和验收;这些是待决产品问题,不能从现有设计推断已有支持。

优先级为本次专业评估,不是仓库既定排期。首期排除的能力是产品选择,但一旦目标客户需要相应场景,就构成实际缺口。

06 / Enterprise federation

平台既可以是客户端,也可以是 IdP

企业员工发起登录
→
企业 IdP认证员工,并提供经过验证的身份声明
→
本平台 · 客户端OIDC Client / RP,或 SAML SP;映射账号、检查成员资格、建立会话
→
第三方应用若接入本平台,本平台在这一段可作为 IdP/OIDC Provider

推荐业务表述:“企业身份提供商联合登录(企业 SSO)”。企业配置自己的 IdP;受邀员工使用企业身份登录平台,平台完成身份映射后,根据企业成员资格与角色授权。

需要明确:企业 IdP 如何与企业绑定和发现;采用 OIDC 还是 SAML;使用发行方 + 稳定主体标识映射,还是允许经验证邮箱参与首次关联;邀请邮箱与 IdP 身份不匹配时如何处理;停用、离职、会话撤销和 IdP 不可用时如何处置。不能仅凭相同邮箱静默合并账号,也不能把认证成功当成企业授权成功。自动建账号或自动加企业(JIT provisioning)是另一个明确的产品决策。

07 / Sources

追溯到仓库

以下为工作区内的参考文件名称;在线版本不公开仓库源文件。