forked from ChaiHao/BPOS-MVP
基线:鉴权会话+工作组+工作台三区修复+编排工作区+产品设计文档
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
@@ -1,22 +1,25 @@
|
||||
# module: org
|
||||
|
||||
职责: 员工与岗位:账号、岗位授权(客体三类 × 动作三种)、停用前置检查、会话装载、
|
||||
岗位在岗人员查询(负责人四策略解析的候选集来源)、种子数据播种
|
||||
职责: 员工与岗位:账号、口令与登录会话(ADR-010)、岗位授权(客体三类 × 动作三种)、
|
||||
停用前置检查、岗位在岗人员查询(负责人四策略解析的候选集来源)、
|
||||
工作组(ADR-011:起单时的岗位绑定)、种子数据播种
|
||||
不负责: 负责人解析算法本身(见 process)、任务与卡的在途判定(经 InFlightWorkProbe 端口由 app 注入)、
|
||||
鉴权中间件与 cookie 会话(app 层)
|
||||
鉴权中间件与 cookie 的读写(app 层:§4「中间件在 app 层,身份判定读 org 出口」)
|
||||
|
||||
公开出口: index.ts
|
||||
- 类型:`OrgService` `StaffWithPosition` `CreateStaffInput` 与 @contracts 的 `Staff` / `Position` /
|
||||
`Grant` / `GrantObject` / `GrantAction` / `DisableCheck` / `Session` 转出
|
||||
- 类型:`OrgService` `StaffWithPosition` `CreateStaffInput` `IssuedSession` 与 @contracts 的
|
||||
`Staff` / `Position` / `Grant` / `GrantObject` / `GrantAction` / `DisableCheck` / `Session` 转出
|
||||
- 错误:`StaffNotFoundError` `PositionNotFoundError` `AccountTakenError` `DisableBlockedError`
|
||||
- 端口类型:`PositionRepository` `StaffRepository` `GrantRepository` `InFlightWorkProbe`
|
||||
`Clock` `IdGenerator`
|
||||
- 端口类型:`PositionRepository` `StaffRepository` `GrantRepository` `SessionRepository`
|
||||
`WorkGroupRepository` `PasswordHasher` `InFlightWorkProbe` `Clock` `IdGenerator`
|
||||
- 用例工厂:`createOrgService(deps: OrgServiceDeps): OrgService`
|
||||
- 纯函数:`isAuthorized` `actionCovers` `objectCovers`
|
||||
- 常量:`POSITION_SEED` `STAFF_SEED` `DEFAULT_LOGIN_ACCOUNT`
|
||||
- adapter 工厂(供 app 装配):`createPositionRepository` `createStaffRepository`
|
||||
`createGrantRepository` `objectKeyOf`
|
||||
- Drizzle 表(供 app 迁移与 join):`positionTable` `staffTable` `grantTable`
|
||||
`createGrantRepository` `createSessionRepository` `createWorkGroupRepository` `objectKeyOf`
|
||||
- 口令散列(供 app 装 `PasswordHasher`):`hashPassword` `verifyPassword` `newSessionToken`
|
||||
- Drizzle 表(供 app 迁移与 join):`positionTable` `staffTable` `grantTable` `sessionTable`
|
||||
`workGroupTable`
|
||||
|
||||
层级: L1(编码规范 §4)
|
||||
依赖: @contracts;@shared/db(Drizzle 句柄与 sys schema)
|
||||
@@ -28,6 +31,17 @@
|
||||
- 动作蕴含:治理 ⊃ 写 ⊃ 读;数据客体三级覆盖(域 ⊃ 对象 ⊃ 字段)
|
||||
- 停用是全有全无:前置检查未过即抛 `DisableBlockedError`,不做部分执行
|
||||
- `authorize` 对停用员工恒 false
|
||||
- `ensureSeeded` 幂等:按 code / account 判存在,已存在则跳过,不覆盖人工改动
|
||||
- `ensureSeeded` 幂等:按 code / account 判存在,已存在则跳过,不覆盖人工改动;
|
||||
唯一例外是**补种口令** —— 已存在但 `password_hash` 为空的员工会被补上初始口令,
|
||||
否则 ADR-010 之前建的账号永远登不进(这不算覆盖人工改动:空不是改动)
|
||||
- **登录失败不区分原因**:账号不存在 / 已停用 / 未设口令 / 口令错,一律 `undefined`;
|
||||
且无论账号是否存在都走一遍散列比对,免得响应时间泄漏账号是否存在
|
||||
- **明文永不落库**:口令只在 `login` / `setPassword` 的入参上停留一瞬,落库前即散列
|
||||
- **会话可即刻作废**:服务端表而非签名 cookie —— `logout` 立刻生效;
|
||||
`disableStaff` 连带 `revokeAllOf`,被停用的人拿旧 cookie 也办不了事
|
||||
- **工作组是绑定不是策略**(ADR-011):它给出岗位的人选,四策略于是无从发问;
|
||||
`bindingOf` 只出成员表快照,在岗与否由调用方(process)核 —— 岗位候选集核不了跨岗位的绑定
|
||||
|
||||
影响半径: index/contract/port 未变 → 对外零影响
|
||||
影响半径: contract 增 `login` / `logout` / `resolveSession` / `setPassword` 与 `IssuedSession`;
|
||||
port 增 `SessionRepository` / `PasswordHasher`,`StaffRepository` 增两个口令读写方法;
|
||||
下游只有 app(装配 + 鉴权中间件),depcruise 已反查确认
|
||||
|
||||
Reference in New Issue
Block a user