建组/改组:逐岗位选人,留空即回落四策略。绑定先于策略,起单时快照进工作流; 实测改绑定后新起单的 work_group 快照即含新成员表,在途不受影响。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
3.8 KiB
module: org
职责: 员工与岗位:账号、口令与登录会话(ADR-010)、岗位授权(客体三类 × 动作三种)、 停用前置检查、岗位在岗人员查询(负责人四策略解析的候选集来源)、 工作组(ADR-011:起单时的岗位绑定)、种子数据播种 不负责: 负责人解析算法本身(见 process)、任务与卡的在途判定(经 InFlightWorkProbe 端口由 app 注入)、 鉴权中间件与 cookie 的读写(app 层:§4「中间件在 app 层,身份判定读 org 出口」)
公开出口: index.ts
- 类型:
OrgServiceStaffWithPositionCreateStaffInputIssuedSession与 @contracts 的Staff/Position/Grant/GrantObject/GrantAction/DisableCheck/Session转出 - 错误:
StaffNotFoundErrorPositionNotFoundErrorAccountTakenErrorDisableBlockedError - 端口类型:
PositionRepositoryStaffRepositoryGrantRepositorySessionRepositoryWorkGroupRepositoryPasswordHasherInFlightWorkProbeClockIdGenerator - 用例工厂:
createOrgService(deps: OrgServiceDeps): OrgService - 纯函数:
isAuthorizedactionCoversobjectCovers - 常量:
POSITION_SEEDSTAFF_SEEDDEFAULT_LOGIN_ACCOUNT - adapter 工厂(供 app 装配):
createPositionRepositorycreateStaffRepositorycreateGrantRepositorycreateSessionRepositorycreateWorkGroupRepositoryobjectKeyOf - 口令散列(供 app 装
PasswordHasher):hashPasswordverifyPasswordnewSessionToken - Drizzle 表(供 app 迁移与 join):
positionTablestaffTablegrantTablesessionTableworkGroupTable
层级: L1(编码规范 §4)
依赖: @contracts;@shared/db(Drizzle 句柄与 sys schema)
port:InFlightWorkProbe(app 注入 task / human-tool 的只读用例)、IdGenerator
被依赖: process(负责人解析的候选集)、message、interaction、human-tool、report、
app(鉴权中间件与 /api/gov/staff 路由组装)
不变量:
- 动作蕴含:治理 ⊃ 写 ⊃ 读;数据客体三级覆盖(域 ⊃ 对象 ⊃ 字段)
- 停用是全有全无:前置检查未过即抛
DisableBlockedError,不做部分执行 authorize对停用员工恒 falseensureSeeded幂等:按 code / account 判存在,已存在则跳过,不覆盖人工改动; 唯一例外是补种口令 —— 已存在但password_hash为空的员工会被补上初始口令, 否则 ADR-010 之前建的账号永远登不进(这不算覆盖人工改动:空不是改动)- 登录失败不区分原因:账号不存在 / 已停用 / 未设口令 / 口令错,一律
undefined; 且无论账号是否存在都走一遍散列比对,免得响应时间泄漏账号是否存在 - 明文永不落库:口令只在
login/setPassword的入参上停留一瞬,落库前即散列 - 会话可即刻作废:服务端表而非签名 cookie ——
logout立刻生效;disableStaff连带revokeAllOf,被停用的人拿旧 cookie 也办不了事 - 工作组是绑定不是策略(ADR-011):它给出岗位的人选,四策略于是无从发问;
bindingOf只出成员表快照,在岗与否由调用方(process)核 —— 岗位候选集核不了跨岗位的绑定
影响半径: contract 增 login / logout / resolveSession / setPassword 与 IssuedSession;
port 增 SessionRepository / PasswordHasher,StaffRepository 增两个口令读写方法;
下游只有 app(装配 + 鉴权中间件),depcruise 已反查确认
近变(2026-07-27):模块面未变。app 层新增工作组读写路由
(GET|PUT /api/gov/work-groups),组装既有的 workGroupOf / saveWorkGroup
—— ADR-011 落地时欠的那个治理界面就此清账,一人一组的口径由 app 层按 ownerId 保证。