/* * **승인을 누가 받는가** — 그 자리를 밖으로 낸다. * * ── 왜 시임인가 (2026-08-31) ───────────────────────────────────────────── * 승인은 이미 이 저장소에 있다. `@things-factory/worklist` 가 결재선·위임·상신·「내가 승인할 것」 목록과 * 승인 화면까지 들고 있다. 그것을 다시 만들면 두 벌이 되고, 사고 뒤에 「어느 쪽 기록이 진짜인가」를 * 묻게 된다. * * 그런데 headless-twin 은 worklist 를 부를 수 없다 — worklist 는 조직도(Employee·Department·Role)와 * 화면 27쪽을 데리고 오는 업무 모듈이고, 이 패키지는 커널을 안는 헤드리스 서버다. 의존을 그 방향으로 * 걸면 커널을 쓰는 모든 배포가 조직도를 지게 된다. * * 그래서 **이 패키지는 자리만 만들고, 앱이 채운다**(operato-twin). 채우지 않은 배포에서는 게이트가 * 사라지지 않는다 — 승인 없이 지나가는 것이 아니라, 아래 §`twinCommands` 의 직접 결정이 유일한 문이 된다. */ import type { StoredCommand } from './command-dispatcher.js' /** 결재선에 올리는 자리 — 앱이 구현한다. */ export interface ApprovalGateway { /** 화면과 오류 문장에 쓰는 이름. 「어디서 승인하는가」를 사람에게 말해야 한다. */ label: string /** * 이 커맨드를 결재선에 올린다. * * 돌려주는 것은 **올라간 자리의 식별자**다. 이 값이 커맨드 행에 적히고, 그 뒤로는 직접 결정이 막힌다 * — 문이 두 벌이면 한쪽 기록에만 남는 승인이 생긴다. * * `context` 는 리졸버 문맥 그대로 넘긴다(트랜잭션·로그인한 사람·테넌트). 이 패키지가 그 모양을 알면 * 앱의 인증 구조를 여기서 다시 정의하게 된다. */ request(command: StoredCommand, context: any): Promise } let gateway: ApprovalGateway | undefined /** 앱이 부팅에서 한 번 부른다. */ export function setApprovalGateway(next: ApprovalGateway): void { gateway = next } /** 등록된 것이 없으면 `undefined` — 없음을 없음으로 답한다. */ export function approvalGateway(): ApprovalGateway | undefined { return gateway }