M6(4/n): 工作台五要素齐活 —— 审批 / 消息 / 纪要 / 汇报

四个 desk-* feature 自 workbench 原型 ModuleWorkspace.tsx 平移(jc-* 类名原样),
共用件落 shared/desk/module-kit;mock 数据换成服务端投影:
  · desk-approval:审批点卡到审批人工位;依据快照、驳回走向(声明式)、驳回必附意见
  · desk-message:通知 + 跨任务征答**就地作答**;卡面表单由 card.ts schema 驱动,
    与后端回传校验同 schema;跨人卡不占任务清单,不开放任务对话流
  · desk-minute:纪要维护 + 决议登记起单;正文可续、决议只增
  · desk-report:四周期草案 + 度量八指标 + 确认即提交
左轨角标常驻(待批 / 未读),责任面要一眼看见什么在等我。

修一个真 bug:process.start 从不校验流程包的 callInterface,
先插工作流再由 task.start 撞活动契约 —— 失败就留下一条永远推不动的在途单。
改为**先校验后建单**(CallInterfaceViolationError),一条工作流都不留;
路由回 400 并带上缺哪个字段。已清掉这次触发出的两条孤儿单。

判据 ⑩ 纪要一环跑通:决议 → 登记触发 → 工作流 → A1 落到 BD 冯兵,
登记人即来源已记在单上;同一决议重复登记被 412 挡下。

gates: tsc / eslint / depcruise(316 模块)/ api-report / 380 测试 全绿

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
2026-07-27 03:53:36 +08:00
co-authored by Claude Opus 5
parent a60acb2e02
commit 3b9587563a
25 changed files with 1680 additions and 49 deletions
@@ -5,7 +5,7 @@
*/
import type { ProcessNode, ProcessPackage, StaffId, TerminalState, WorkflowState } from '@contracts';
import type { ProcessService, StartWorkflowInput } from '../../contract.ts';
import { NotPublishableError, PositionVacantError } from '../../contract.ts';
import { CallInterfaceViolationError, NotPublishableError, PositionVacantError } from '../../contract.ts';
import type {
ActivityDirectory,
ApprovalGateway,
@@ -15,6 +15,7 @@ import type {
OrgDirectory,
ProcessStore,
ReceiptNotifier,
SchemaValidator,
Sfeel,
TaskGateway,
WorkflowRecord,
@@ -31,6 +32,7 @@ export type ProcessServiceDeps = {
readonly tasks: TaskGateway;
readonly approvals: ApprovalGateway;
readonly sfeel: Sfeel;
readonly schemas: SchemaValidator;
readonly events: FlowEventPublisher;
readonly receipts: ReceiptNotifier;
readonly clock: Clock;
@@ -216,6 +218,11 @@ export function createProcessService(deps: ProcessServiceDeps): ProcessService {
const pkg = await requirePackage(input.packageId, input.packageVersion);
if (pkg.state !== 'published') throw new Error(`流程包未发布,不得起单:${pkg.id}@${pkg.version}`);
// 先校验后建单:不合调用接口契约的输入**一条工作流都不留**。
// (校验若放在建单之后,失败就会留下一条永远推不动的在途单,污染在途口径。)
const check = deps.schemas.validate(pkg.callInterface.input, input.data);
if (!check.ok) throw new CallInterfaceViolationError(pkg.id, check.errors);
const record: WorkflowRecord = {
id: deps.ids.next(),
packageId: pkg.id,