基线:鉴权会话+工作组+工作台三区修复+编排工作区+产品设计文档
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
@@ -82,6 +82,8 @@ export type HumanToolService = {
|
||||
/** 驳回重答:新卡实例,原卡闭合 —— 只增不改 */
|
||||
rejectAndReask(cardId: string, reason: string): Promise<IssuedChatCard>;
|
||||
openWorkOrders(taskId: TaskId): Promise<WorkOrder[]>;
|
||||
/** 全部工单(含已办结)—— 工作成果要回看定稿的报告,只给 open 就永远是空的 */
|
||||
allWorkOrders(taskId: TaskId): Promise<WorkOrder[]>;
|
||||
chatCards(taskId: TaskId): Promise<ChatCard[]>;
|
||||
/** org 停用前置检查要问的「待答卡」 */
|
||||
openCardsOf(staffId: StaffId): Promise<Array<{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
import type { ChatMessage, StaffId, TaskId, ViewBlock } from '@contracts';
|
||||
import type { InteractionPhase } from './internal/domain/control-handover.ts';
|
||||
import type { NarrativeEntry } from './internal/domain/chat-projection.ts';
|
||||
export type Clock = {
|
||||
now(): Date;
|
||||
};
|
||||
@@ -39,6 +40,11 @@ export type MemoryRecorder = {
|
||||
title: string;
|
||||
detail?: Record<string, unknown>;
|
||||
}): Promise<void>;
|
||||
/**
|
||||
* 叙事条目 —— 对话流与工作日志**同源不同筛选**:
|
||||
* AI 发言与系统事件不另设写入口,一律从任务记忆投影而来(见 `chat-projection`)。
|
||||
*/
|
||||
history(taskId: TaskId): Promise<readonly NarrativeEntry[]>;
|
||||
};
|
||||
/** 收件人解析 —— app 注入 `org`(L1):SSE 只推给有权看的人 */
|
||||
export type Audience = {
|
||||
|
||||
+26
-2
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* module: org —— 对外类型(编码规范 §10.1)。只有类型和常量,没有实现。
|
||||
*/
|
||||
import type { DisableCheck, Grant, GrantAction, GrantObject, Position, Session, Staff, StaffId } from '@contracts';
|
||||
export type { DisableCheck, Grant, GrantAction, GrantObject, Position, Session, Staff };
|
||||
import type { DisableCheck, Grant, GrantAction, GrantObject, Position, Session, Staff, StaffId, WorkGroup, WorkGroupBinding } from '@contracts';
|
||||
export type { DisableCheck, Grant, GrantAction, GrantObject, Position, Session, Staff, WorkGroup, WorkGroupBinding };
|
||||
/** 员工连同其岗位的读模型 —— 治理台员工管理列表用 */
|
||||
export type StaffWithPosition = Staff & {
|
||||
readonly position: Position;
|
||||
@@ -29,6 +29,11 @@ export declare class DisableBlockedError extends Error {
|
||||
readonly check: DisableCheck;
|
||||
constructor(check: DisableCheck);
|
||||
}
|
||||
/** 登录结果 —— token 交给 app 层种 cookie;失败一律 undefined,不区分原因 */
|
||||
export type IssuedSession = {
|
||||
readonly token: string;
|
||||
readonly expiresAt: string;
|
||||
};
|
||||
export type OrgService = {
|
||||
listStaff(): Promise<{
|
||||
staff: StaffWithPosition[];
|
||||
@@ -46,6 +51,25 @@ export type OrgService = {
|
||||
/** 岗位权限校验 —— app 层鉴权中间件读它 */
|
||||
authorize(staffId: StaffId, object: GrantObject, action: GrantAction): Promise<boolean>;
|
||||
loadSession(account: string): Promise<Session | undefined>;
|
||||
/** 口令核验通过即签发会话;账号不存在 / 已停用 / 未设口令 / 口令错,一律 undefined */
|
||||
login(account: string, password: string): Promise<IssuedSession | undefined>;
|
||||
/** 登出:该 token 立刻作废(服务端表,不是签名 cookie) */
|
||||
logout(token: string): Promise<void>;
|
||||
/** 解析会话 —— 命中即滑动续期;过期或已作废返回 undefined */
|
||||
resolveSession(token: string): Promise<Session | undefined>;
|
||||
/** 设定口令 —— 明文只在此处停留一瞬,落库前即散列 */
|
||||
setPassword(staffId: StaffId, password: string): Promise<void>;
|
||||
/** 建组 / 改组;id 留空即新建 */
|
||||
saveWorkGroup(input: {
|
||||
id?: string;
|
||||
name: string;
|
||||
ownerId: StaffId;
|
||||
members: Readonly<Record<string, StaffId>>;
|
||||
}): Promise<WorkGroup>;
|
||||
/** 某人的工作组 —— 起单时按来源人取,取不到即不装载(全走四策略) */
|
||||
workGroupOf(staffId: StaffId): Promise<WorkGroup | undefined>;
|
||||
/** 装进工作流的快照:改组不改已起的单 */
|
||||
bindingOf(staffId: StaffId): Promise<WorkGroupBinding | undefined>;
|
||||
/** 岗位在岗人员 —— 负责人四策略解析的候选集来源(由 process 调用) */
|
||||
staffOfPosition(positionCode: string): Promise<StaffWithPosition[]>;
|
||||
ensureSeeded(): Promise<void>;
|
||||
|
||||
+5
-4
@@ -1,12 +1,13 @@
|
||||
/**
|
||||
* module: org —— 唯一出口。只做 re-export,不写逻辑(编码规范 §10.1)。
|
||||
*/
|
||||
export type { CreateStaffInput, DisableCheck, Grant, GrantAction, GrantObject, OrgService, Position, Session, Staff, StaffWithPosition, } from './contract.ts';
|
||||
export type { CreateStaffInput, DisableCheck, Grant, GrantAction, GrantObject, IssuedSession, OrgService, Position, Session, Staff, StaffWithPosition, WorkGroup, WorkGroupBinding, } from './contract.ts';
|
||||
export { AccountTakenError, DisableBlockedError, PositionNotFoundError, StaffNotFoundError, } from './contract.ts';
|
||||
export type { Clock, GrantRepository, IdGenerator, InFlightWorkProbe, PositionRepository, StaffRepository, } from './port.ts';
|
||||
export type { Clock, GrantRepository, IdGenerator, InFlightWorkProbe, PasswordHasher, PositionRepository, SessionRepository, StaffRepository, WorkGroupRepository, } from './port.ts';
|
||||
export type { OrgServiceDeps } from './internal/usecase/org-service.ts';
|
||||
export { createOrgService } from './internal/usecase/org-service.ts';
|
||||
export { isAuthorized, actionCovers, objectCovers } from './internal/domain/authorization.ts';
|
||||
export { DEFAULT_LOGIN_ACCOUNT, POSITION_SEED, STAFF_SEED } from './internal/domain/seed-data.ts';
|
||||
export { createGrantRepository, createPositionRepository, createStaffRepository, objectKeyOf, } from './internal/adapter/org-repository.ts';
|
||||
export { grantTable, positionTable, staffTable } from './internal/adapter/org-schema.ts';
|
||||
export { createGrantRepository, createPositionRepository, createSessionRepository, createStaffRepository, createWorkGroupRepository, objectKeyOf, } from './internal/adapter/org-repository.ts';
|
||||
export { hashPassword, newSessionToken, verifyPassword } from './internal/adapter/password.ts';
|
||||
export { grantTable, positionTable, sessionTable, staffTable, workGroupTable } from './internal/adapter/org-schema.ts';
|
||||
|
||||
+32
-1
@@ -2,7 +2,7 @@
|
||||
* module: org —— 本模块要外界提供的能力(编码规范 §10.1 / §5.3)。
|
||||
* adapter 实现之,usecase 依赖之,app 装配之。
|
||||
*/
|
||||
import type { Grant, Position, PositionId, Staff, StaffId } from '@contracts';
|
||||
import type { Grant, Position, PositionId, Staff, StaffId, WorkGroup } from '@contracts';
|
||||
export type Clock = {
|
||||
now(): Date;
|
||||
};
|
||||
@@ -21,6 +21,32 @@ export type StaffRepository = {
|
||||
listByPosition(positionId: PositionId): Promise<Staff[]>;
|
||||
insert(staff: Staff): Promise<Staff>;
|
||||
setState(id: StaffId, state: Staff['state']): Promise<void>;
|
||||
/** 口令散列的读写 —— 明文不经此端口(ADR-010) */
|
||||
passwordHashOf(account: string): Promise<string | undefined>;
|
||||
setPasswordHash(id: StaffId, hash: string): Promise<void>;
|
||||
};
|
||||
/**
|
||||
* 会话仓储(ADR-010)—— 服务端表:登出即刻作废,停用员工连带清场。
|
||||
* token 即主键,不透明随机串,不编码任何身份信息。
|
||||
*/
|
||||
export type SessionRepository = {
|
||||
issue(input: {
|
||||
token: string;
|
||||
staffId: StaffId;
|
||||
expiresAt: Date;
|
||||
}): Promise<void>;
|
||||
/** 未过期才返回;命中同时滑动续期 */
|
||||
touch(token: string, now: Date, expiresAt: Date): Promise<{
|
||||
staffId: StaffId;
|
||||
} | undefined>;
|
||||
revoke(token: string): Promise<void>;
|
||||
revokeAllOf(staffId: StaffId): Promise<void>;
|
||||
};
|
||||
/** 口令散列器 —— 算法实现在 adapter,usecase 只认这两个动作 */
|
||||
export type PasswordHasher = {
|
||||
hash(password: string): Promise<string>;
|
||||
verify(password: string, stored: string | undefined): Promise<boolean>;
|
||||
newToken(): string;
|
||||
};
|
||||
export type GrantRepository = {
|
||||
listByPosition(positionId: PositionId): Promise<Grant[]>;
|
||||
@@ -44,6 +70,11 @@ export type InFlightWorkProbe = {
|
||||
title: string;
|
||||
}>>;
|
||||
};
|
||||
/** 工作组仓储(ADR-011) */
|
||||
export type WorkGroupRepository = {
|
||||
listByOwner(ownerId: StaffId): Promise<WorkGroup[]>;
|
||||
upsert(group: WorkGroup): Promise<WorkGroup>;
|
||||
};
|
||||
/** ID 生成 —— domain 零随机(§5.3) */
|
||||
export type IdGenerator = {
|
||||
next(): string;
|
||||
|
||||
@@ -24,6 +24,11 @@ export type WorkflowRecord = {
|
||||
by?: string;
|
||||
};
|
||||
readonly initiation: Record<string, unknown>;
|
||||
/**
|
||||
* 工作组绑定的**快照**(ADR-011):起单时按来源人装载,之后改组不影响这条单。
|
||||
* 留痕要能解释「当时为什么派给他」,而不是被今天的组织调整改写(同 AM 9.1 版本信封)。
|
||||
*/
|
||||
readonly workGroup?: Record<string, string>;
|
||||
/** 各节点输出口载荷 —— 边映射装配的来源 */
|
||||
readonly ports: Record<string, Record<string, unknown>>;
|
||||
readonly vars: Record<string, unknown>;
|
||||
@@ -65,6 +70,10 @@ export type OrgDirectory = {
|
||||
name: string;
|
||||
openTasks: number;
|
||||
}>>;
|
||||
/** 某人的工作组绑定(ADR-011)—— 起单时按来源人取,取不到即不装载 */
|
||||
workGroupBinding(staffId: string): Promise<Readonly<Record<string, string>> | undefined>;
|
||||
/** 在岗与否 —— 绑定的人已离岗就不硬用,退回四策略 */
|
||||
isActive(staffId: string): Promise<boolean>;
|
||||
};
|
||||
/** 起单与终态 —— app 注入 `task`(L6) */
|
||||
export type TaskGateway = {
|
||||
|
||||
Reference in New Issue
Block a user