**触发确认链路**(用户口述五步的第 4/5 步):
接收邮件 → 分类识别 → 命中 RFQ 事件 → ④(可选,运营勾)系统消息到指定人
工作台(带邮件内容)→ ⑤ 工作台点「确认起单」,流程才起。
· 命中不等于必起:勾了「需人工确认」,装配好的入参存成待确认单
(sys.trigger_pending,migration 0019),ConfirmDesk 端口把带来件内容的
系统消息送指定人(eventRef 挂票号,消息列表就地贴确认状态与那枚钮)。
· 先认领后起单:consumed_at 空才认得到 —— 两人同时点、一人点两次,都只起一条流;
起单失败退回认领,不留死票。确认人记进 source.by,留痕可查。
· 登记触发不走确认(登记那一下本身就是人在确认);勾了没指定人 = 配置错误入死信。
· 4 条单测 + 全链实测:投信 → triggersHit=1 且零直起 → AI 工作台收到确认消息
→ 确认起单 → 二次确认幂等回同一流号 → source.by = AI。
**运营中心重排**(区名即运行时:工作流是流程包的运行时,任务是活动的运行时):
· 新「工作流」区:在途看板(从任务区迁入)+ 运行配置 —— 每包的触发器
起单开关 / 确认打勾 / 确认人,和节点负责人(sys.node_owner)。
· 负责人三层:显式指派 > 运营配置 > 轮值 —— 合并点在 process.start,
复用既有派发链一行不改。
· 任务区瘦身成活动运行时(任务/审批/需处置);知识库区改名「数据」
(与设计中心的知识库解开同名);系统区只剩通道实例。
· 设计中心触发器详情页摘掉启停按钮 —— 设计只管设计,启停/确认全在运营。
· 旧深链有改嫁:tasks/board → runs/board,tasks/trg → runs/conf。
reset-runs 补 sys.trigger_pending(待确认单是运行痕 —— 和上回漏 trace_span 同类洞)。
邮件分类 Agent(第 ② 步)现由抽键正则 + S-FEEL 代位,升级路径记进 debt.md。
产品设计.md 运营章、trigger/process 两份 CONTRACT.md 同步。
五闸绿;契约快照随本提交入库。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
68 lines
3.1 KiB
TypeScript
68 lines
3.1 KiB
TypeScript
/**
|
|
* module: trigger —— 对外类型(编码规范 §10.1;语义出处 OS 3.1)。
|
|
*
|
|
* 触发器三类,**独立配置存放**,判定与调用接口调起。
|
|
* 触发器与流程包平级:增删启停不改流程包的任何版本。
|
|
*/
|
|
import type { TriggerConfig, TriggerKind } from '@contracts';
|
|
import type { AssemblyResult, EventScope } from './internal/domain/matching.ts';
|
|
export type { AssemblyResult, EventScope, TriggerConfig, TriggerKind };
|
|
export declare class TriggerInputMissingError extends Error {
|
|
readonly triggerId: string;
|
|
readonly fields: readonly string[];
|
|
constructor(triggerId: string, fields: readonly string[]);
|
|
}
|
|
export type FireOutcome = {
|
|
readonly triggerId: string;
|
|
readonly workflowId?: string;
|
|
/** 命中但勾了「需人工确认」:没起单,等指定人点头 —— 这一票的号 */
|
|
readonly pendingId?: string;
|
|
readonly skipped?: 'duplicate' | 'disabled' | 'input-missing' | 'no-confirmer';
|
|
readonly missing?: readonly string[];
|
|
};
|
|
/** 待确认单:装配好的一次起单,等指定人点「确认起单」 */
|
|
export type PendingFire = {
|
|
readonly id: string;
|
|
readonly triggerId: string;
|
|
readonly packageId: string;
|
|
/** 确认人快照 —— 确认路由按它认门 */
|
|
readonly staffId: string;
|
|
readonly subject: string;
|
|
readonly data: Record<string, unknown>;
|
|
readonly source: {
|
|
readonly kind: 'periodic' | 'event' | 'registration';
|
|
readonly ref: string;
|
|
readonly by?: string;
|
|
};
|
|
readonly preview: Readonly<Record<string, string>>;
|
|
readonly createdAt: string;
|
|
readonly consumedAt?: string;
|
|
readonly workflowId?: string;
|
|
};
|
|
export type TriggerService = {
|
|
list(): Promise<TriggerConfig[]>;
|
|
upsert(config: TriggerConfig): Promise<TriggerConfig>;
|
|
setEnabled(id: string, enabled: boolean): Promise<void>;
|
|
remove(id: string): Promise<void>;
|
|
/** 事件到达:命中判定 —— 供 `event` 的 `TriggerMatcher` 端口使用 */
|
|
match(scope: EventScope): Promise<string[]>;
|
|
/** 命中即起单;同一事件对同一触发器**至多起一单**(事件 ID 为幂等键) */
|
|
fireByEvent(triggerId: string, eventId: string, scope: EventScope): Promise<FireOutcome>;
|
|
/** 登记触发:人工起单的统一形态 —— 登记人即来源 */
|
|
fireByRegistration(triggerId: string, by: string, data: Record<string, unknown>): Promise<FireOutcome>;
|
|
/** 周期触发的到点扫描(由 pg-boss 定时调起) */
|
|
sweepPeriodic(now: Date): Promise<FireOutcome[]>;
|
|
/** 运营口:要不要人工确认、谁来确认 —— 与设计面的 upsert 分口 */
|
|
setConfirm(id: string, confirm: {
|
|
required: boolean;
|
|
staffId?: string;
|
|
}): Promise<void>;
|
|
/** 指定人点头 —— 幂等:已被确认过就回那条流的号,绝不起第二条 */
|
|
confirmPending(pendingId: string, by: string): Promise<{
|
|
workflowId: string;
|
|
alreadyStarted: boolean;
|
|
}>;
|
|
/** 待确认单批读 —— 工作台消息列表就地贴确认状态用 */
|
|
pendingByIds(ids: readonly string[]): Promise<PendingFire[]>;
|
|
};
|