← 返回宏观 DAG

Service Delivery Sub-DAG

服务交付子图 | Check-in → Queue → Service → Complete → 出口
2026-03-22 | Spec 098-business-dag-audit

健康度总览

9
总边数
6
已连通
2
部分连通
1
断裂

服务交付 DAG

已连通 (端到端代码链路验证)
部分连通 (后端存在但链路有缺口)
断裂 (未实现)
graph TD
  APT["Appointment (预约已存在)"]
  KIOSK["Kiosk Check-in (自助终端签到)"]
  FRONT["Front Desk Check-in (前台签到)"]
  WALKIN["Walk-in (无预约到店)"]
  QUEUE["Queue (等待队列)"]
  ASSIGN["Assign Technician (分配技师)"]
  INPROG["In-Progress (服务进行中)"]
  COMPLETE["Completed (服务完成)"]

  PAY_EXIT["Payment (收款出口)"]
  RET_EXIT["Retention (留存出口)"]
  OPS_EXIT["Operations (运营出口)"]

  APT -->|"D1 Kiosk 签到"| KIOSK
  APT -->|"D2 前台签到"| FRONT
  WALKIN -->|"D3 Walk-in 自动签到"| KIOSK
  KIOSK -->|"D4 入队"| QUEUE
  FRONT -->|"D5 入队"| QUEUE
  QUEUE -->|"D6 分配技师"| ASSIGN
  ASSIGN -->|"D7 开始服务"| INPROG
  INPROG -->|"D8 完成服务"| COMPLETE
  COMPLETE -->|"D9 收款出口"| PAY_EXIT
  COMPLETE -->|"D10 留存出口"| RET_EXIT
  COMPLETE -->|"D11 运营出口"| OPS_EXIT

  style APT fill:#1a2332,stroke:#3b82f6,color:#e0e0e0
  style KIOSK fill:#1a2332,stroke:#06b6d4,color:#e0e0e0
  style FRONT fill:#1a2332,stroke:#06b6d4,color:#e0e0e0
  style WALKIN fill:#1a2332,stroke:#8b5cf6,color:#e0e0e0
  style QUEUE fill:#1a2332,stroke:#f59e0b,color:#e0e0e0
  style ASSIGN fill:#1a2332,stroke:#f59e0b,color:#e0e0e0
  style INPROG fill:#1a2332,stroke:#22c55e,color:#e0e0e0
  style COMPLETE fill:#1a2332,stroke:#22c55e,color:#e0e0e0
  style PAY_EXIT fill:#0d2818,stroke:#22c55e,color:#22c55e,stroke-dasharray:5
  style RET_EXIT fill:#2d1f0d,stroke:#f59e0b,color:#f59e0b,stroke-dasharray:5
  style OPS_EXIT fill:#2d0d0d,stroke:#ef4444,color:#ef4444,stroke-dasharray:5

  linkStyle 0 stroke:#22c55e,stroke-width:2px
  linkStyle 1 stroke:#22c55e,stroke-width:2px
  linkStyle 2 stroke:#22c55e,stroke-width:2px
  linkStyle 3 stroke:#22c55e,stroke-width:2px
  linkStyle 4 stroke:#22c55e,stroke-width:2px
  linkStyle 5 stroke:#f59e0b,stroke-width:2px,stroke-dasharray:5
  linkStyle 6 stroke:#f59e0b,stroke-width:2px,stroke-dasharray:5
  linkStyle 7 stroke:#22c55e,stroke-width:2px
  linkStyle 8 stroke:#22c55e,stroke-width:2px
  linkStyle 9 stroke:#f59e0b,stroke-width:2px,stroke-dasharray:5
  linkStyle 10 stroke:#ef4444,stroke-width:2px,stroke-dasharray:5
    

边审计表

状态 涉及端口 代码路径 备注
D1 Appointment → Kiosk 签到 Kiosk, API frontend/.../terminal/[store_code]/page.tsx
frontend/.../terminal/[store_code]/confirm/page.tsx
api/checkin.js POST /api/checkin
services/checkinService.js processCheckin()
Kiosk 终端主页输入手机号 → 调用 /api/checkin/verify/:phone 查找今日预约 → confirm 页面调用 POST /api/checkin 执行签到。
链路完整:手机号验证 → 预约匹配 → 签到记录创建 → 状态更新为 in_progress
D2 Appointment → 前台签到 Web Admin, API frontend/.../admin/checkin/page.tsx
frontend/.../admin/checkin/queue/page.tsx
api/checkin.js POST /api/checkin
services/checkinService.js quickVerifyAndCheckin()
管理后台签到模块包含三个子页面:Queue、Stats、Config。
Quick Check-in 路径:GET /api/checkin/today-appointments 获取今日预约列表 → POST /api/checkin/quick-verify 通过手机尾号 4 位验证并签到。
Quick check-in 将状态设为 checked_in(注意:与 Kiosk 的 in_progress 不同)。
D3 Walk-in → 自动签到 Kiosk, API frontend/.../terminal/[store_code]/walkin/page.tsx
api/public/booking.js POST /api/public/booking/confirm
services/checkinService.js processWalkinCheckin()
两条 Walk-in 路径均实现:
(a) Kiosk Booking 自动签到:walkin 页面通过 POST /api/public/booking/confirm 创建预约(source: 'kiosk'),若日期为今天则自动插入 checkins 记录并将状态设为 checked_in。 前端通过 auto_checked_in 字段判断。
(b) Walk-in 签到processWalkinCheckin() 创建 walk-in 预约(source: 'walkin', 状态直接设为 in_progress)并自动创建 checkin + queue 记录。
D4/D5 Check-in → Queue API (内部) services/checkinService.js addToQueue()
表: checkin_queue
processCheckin()processWalkinCheckin() 均在签到后调用 addToQueue()
队列记录包含 position、status('waiting')、estimated_start_time。
预计等待时间算法简单:(position - 1) x 30min 固定值。
注意:Quick Check-in (quickVerifyAndCheckin) 路径仅更新 appointment 状态, 未调用 addToQueue(),即快速签到的客人不进入等待队列。
D6 Queue → 分配技师 Web Admin, API services/booking/auto-assign-service.js
api/public/booking.js (L2895)
components/Checkin/Admin/QueueManager.tsx
Auto-assign 在预约创建阶段执行api/public/booking.jsassignTechnician()), 而非在队列阶段。策略为 least-busy(当天最空闲)。
Queue → 分配技师的链路不存在:Queue 的 start-servicecall-next 操作在 QueueManager 前端中调用,但 API 端点 /api/queue/:id/start-service 无路由注册 (server.js 中未挂载 queue 路由,仅有测试文件 tests/api/queue.test.js 引用该 API)。
结论:技师分配发生在预约阶段,队列阶段的技师(重新)分配链路断裂。
D7 Queue → In-Progress Web Admin components/Checkin/Admin/QueueManager.tsx startService()
API: POST /api/queue/:id/start-service
QueueManager 前端调用 POST /api/queue/:queueId/start-service 标记开始服务。
但该 API 端点未在 server.js 中挂载(同 D6 问题)。
前端代码已就绪(startService、completeService、markNoShow),后端路由缺失。
间接路径可用:管理后台的 Appointment Board 可通过 PUT /api/appointments/:id/status 手动将状态从 checked_in/in_progress 切换,但绕过了队列系统。
D8 In-Progress → Completed Web, Mobile, API api/appointments.js PUT /:id/status (L2062-2084)
api/mobile/my-services.js PUT /complete/:appointmentServiceId
状态流转: in_progress → ['completed', 'cancelled']
两条路径完成服务标记:
(a) Web 管理后台:通过 Appointment Board 更新状态,有完整的状态流转校验 (STATUS_TRANSITIONS 映射表)。
(b) 员工移动端PUT /api/mobile/my-services/complete/:id 从 sub_appointments 查找 appointment_id 并更新状态。
状态变为 completed 时触发:conversion tracking、guest tagging event、booking metrics。
D9 Completed → Payment 出口 Web, API components/Appointment/AppointmentDetailModal.tsx (L606)
frontend/.../checkout/[appointmentId]/page.tsx
api/payment/checkout-routes.js POST /api/payment/checkout
AppointmentDetailModal 包含"收款"按钮(canTakePayment 条件守卫), 点击后跳转 /checkout/{appointmentId}
Checkout 页面使用 NewCheckoutFlow 组件,支持 Cash + POS Card + Gift Card 支付方式。
链路完整:预约详情 → 收款按钮 → Checkout 页面 → Payment API。
D10 Completed → Retention 出口 API (event) services/automation/trigger-engine.js SERVICE_COMPLETED
api/appointments.js (L2271) _emitGuestTaggingEvent
services/tagging/eventListener.js (L32) handleAppointmentCompleted
services/research/conversionService.js APPOINTMENT_COMPLETED
服务完成触发多个事件:
(a) Guest Tagging 事件 (appointment_completed) → 活跃度标签自动更新;
(b) Conversion tracking → 研究平台归因;
(c) Trigger engine 注册 service_completed 事件类型,可配置自动化模板。
:automation trigger engine 中 service_completed 事件类型已注册, 实际触发调用链未直接从 appointment status update 中发出(仅 tagging 和 conversion)。 Review solicitation 仅在 Agent tool 中存在,未作为 automation action 接入。
D11 Completed → Operations 出口 - services/timeClockService.js (独立系统)
services/timeCardService.js (独立系统)
api/appointments.js 状态更新 handler
服务完成不直接触发运营数据记录
Time Clock 是独立的员工打卡系统(clock in/out/break),与服务完成事件无关联。
Payroll 报表通过查询 appointments WHERE status = 'completed' 间接聚合数据, 但不是由完成事件触发的实时数据流。
缺失:预约完成后应记录员工实际服务时长(actual_duration vs scheduled_duration), 用于准确的工时统计和佣金计算。当前 commission 记录由支付完成触发(Payment 子图), 而非由服务完成触发。

松散点汇总

1. Queue API 路由未挂载

QueueManager.tsx 前端组件调用 /api/queue/:id/start-service/api/queue/:id/complete/api/queue/:id/no-show 等端点, 但 server.js 中未注册 queue 路由。测试文件 tests/api/queue.test.js 定义了完整的 API 契约,说明原本计划实现但未完成路由挂载。

影响:队列管理页面(/admin/checkin/queue)的"开始服务"/"完成"/"未到"按钮均无效。 员工只能通过 Appointment Board 手动改状态,绕过队列系统。

2. Quick Check-in 跳过队列

quickVerifyAndCheckin() 仅更新 appointment 状态为 checked_in, 未调用 addToQueue()。通过前台 Quick Check-in 签到的客人不出现在等待队列中, 导致队列数据不完整。

3. 签到状态不一致

三种签到方式产生不同的 appointment 状态:

checked_inin_progress 在状态流转表中是两个独立状态, 但语义上都表示"客人已到店"。这可能导致报表和队列统计口径不一致。

4. 服务完成未记录实际工时

Appointment 状态变为 completed 时,未记录 actual_end_time 或 actual_duration。 Time Clock 系统是独立的员工打卡系统(上下班),不追踪单次服务时长。 Commission 记录由 Payment 子图触发,而非服务完成触发。

影响:无法准确度量"预约时长 vs 实际服务时长"偏差, 影响排班优化和技师效率分析。

5. 等待时间算法过于简化

addToQueue() 中预计等待时间计算为 (position - 1) x 30min 固定值, 未参考实际预约的 duration_minutes 或当前服务进度。对客人的等待预期管理不准确。

跨子图引用

入口:来自 Conversion 子图

Delivery 子图的入口是已创建的 Appointment 对象。来源包括:

详见 Conversion 子图(待审计)

出口 D9:→ Payment 子图

服务完成后通过 AppointmentDetailModal 的"收款"按钮进入 Checkout 页面 (/checkout/{appointmentId})。Checkout 页面触发支付流程(Cash / POS Card / Gift Card)。

详见 Payment 子图(待审计)

出口 D10:→ Retention 子图

服务完成触发 appointment_completed 事件,被 Guest Tagging 和 Conversion Tracking 消费。 Trigger engine 注册了 service_completed 事件类型用于自动化营销(如满意度调查、复购优惠)。 但 review solicitation 未接入 automation action,仅在 Agent tool 中可用。

详见 Retention 子图(待审计)

出口 D11:→ Operations 子图

服务完成不直接触发运营数据记录。Time Clock 是独立系统。 Payroll 报表通过 SELECT ... FROM appointments WHERE status = 'completed' 间接聚合, 但不是事件驱动的实时数据流。Commission 记录由 Payment 完成触发(经 Payment 子图)。

详见 Operations 子图(待审计)

附录:预约状态生命周期(Delivery 段)

stateDiagram-v2
  [*] --> pending : 预约创建
  pending --> confirmed : 确认
  confirmed --> checked_in : Quick Check-in / Kiosk Auto
  confirmed --> in_progress : Kiosk Check-in / Walk-in
  pending --> checked_in : Quick Check-in
  checked_in --> in_progress : 开始服务
  in_progress --> completed : 完成服务
  completed --> pending_payment : 进入收款 (Payment 子图)
  pending_payment --> finished : 支付完成
  finished --> closed : 关闭

  note right of checked_in : Quick Check-in 和 Kiosk Auto\n产生此状态
  note right of in_progress : Kiosk 签到和 Walk-in\n直接产生此状态
  note right of completed : 触发 tagging + conversion\n+ automation 事件