Skip to main content

WebSocket Monitor & Print Job History

Scope: PWA settings screen for live Socket.IO diagnostics and recent thermal print queues. See also: KDS & printing model (three tracking entities), Print Bridge spec (agent lifecycle), Document print module (receipt/FEL jobs).


Purpose

The WebSocket Monitor (/settings/websockets) helps operators and developers at a location:

  1. See who is connected on the /restaurant and /kds Socket.IO namespaces.
  2. Inspect recent kitchen thermal print jobs (print_job) — the table behind KitchenPrintJobsTabContent.
  3. Inspect recent document print jobs (document_print_job) — receipts, bills, FEL, etc.
  4. Preview ticket payloads and match device records to live socket sessions.

Route: apps/frontend-pwa/src/pages/settings/websockets/WebSocketMonitorPage.tsx
Also linked from kitchen station settings (StationSocketsPanel → “Open WebSocket monitor”).


Data sources on the page

SectionTanStack Query key (approx.)HTTP endpointAuth
Live connectionswebsocketStatusGET /websocket-status?businessId=&locationId=Firebase
Kitchen print jobs tabkitchenPrintJobHistoryGET /print-jobs/history?locationId=&limit=20Firebase
Document print jobs tabdocumentPrintJobHistoryGET /document-print-jobs/history?businessId=&locationId=&limit=20Firebase
KDS deviceskds-devices-locationGET /restaurant/kitchen/devices?...Firebase
Kitchen stationskitchen-stations-ws-monitorGET /kitchen-stations?...Firebase

Poll intervals: WebSocket status and kitchen history 10 s; document history 15 s.

Implementation references:

  • Frontend service: apps/frontend-pwa/src/services/websocketStatusService.ts
  • Kitchen history controller: apps/backend/src/restaurant/interfaces/kitchen.controller.ts (GET print-jobs/history)
  • Kitchen history query: apps/backend/src/restaurant/infrastructure/print-job.repository.tsfindRecentByLocationId
  • Document history: apps/backend/src/document-print/interfaces/document-print.controller.tsGET history
  • WebSocket status: apps/backend/src/restaurant/interfaces/websocket-status.controller.ts

Kitchen print jobs tab (print_job)

What each row represents

One row = one print_job record: a thermal kitchen ticket queued for a kitchen_station, usually tied to an order_item.

This is not the same as kitchen_ticket (KDS acknowledgement). The monitor shows printer queue state only. For the full KDS vs printer split, see KDS & printing model.

Test prints: When print_job.order_item_id is NULL, the UI sets isTestPrint: true and shows a test-print label instead of a product name (station test from hardware settings).

UI column → data source

ColumnSource
Job IDprint_job.id
Productproduct.name via order_item.product_id, or test-print badge
Statusprint_job.status (pending, sent, printed, failed)
Stationkitchen_station.name
Order / Tableorder.document_number, dining_table.table_number
Error detailsprint_job.last_error
Createdprint_job.created_at
Printedprint_job.printed_at
PreviewClient-side ticket preview from ticketData in API response

Tables joined by findRecentByLocationId

Primary query (Kysely table names → PostgreSQL):

print_job
INNER JOIN kitchen_station ON kitchen_station.id = print_job.station_id
LEFT JOIN order_item ON order_item.id = print_job.order_item_id
LEFT JOIN order ON order.id = order_item.order_id
LEFT JOIN dining_table ON dining_table.id = order.table_id
LEFT JOIN product ON product.id = order_item.product_id
WHERE kitchen_station.location_id = :locationId
ORDER BY print_job.created_at DESC
LIMIT :limit -- default 20, max 100

Secondary query for modifiers (per distinct order_item_id in the result set):

order_item_modifier
WHERE order_item_id IN (...)
AND show_on_kitchen_ticket_snapshot IS NOT FALSE

Mapped through mapKitchenModifierLines() in @flowpos-workspace/receipt-layout (same helper as KDS print payload and document-print kitchen lines). See Kitchen ticket modifier rendering in menus-modifier-groups.

Entity relationship (kitchen history)

erDiagram
print_job ||--o| order_item : order_item_id
print_job }o--|| kitchen_station : station_id
kitchen_station }o--|| location : location_id
order_item }o--|| order : order_id
order_item }o--|| product : product_id
order }o--o| dining_table : table_id
order_item ||--o{ order_item_modifier : order_item_id
TableRoleWhy omitted
kitchen_ticketKDS bump/recall/voidSeparate lifecycle; admin KDS uses tickets, not this history API
product_station_assignmentRouting at send-to-kitchenUsed when jobs are created, not when listing history
kds_devicePaired screensLoaded separately on the monitor for socket ↔ device matching

Bridge/agent operations use GET /print-jobs?status=pending&stationId= and PATCH /print-jobs/:id (device token), documented in Print Bridge spec and restaurant-api-postman.


Document print jobs tab (document_print_job)

Separate queue for structured receipt documents (not kitchen line items).

AspectDetail
Tabledocument_print_job only (no joins in history list)
Scopebusiness_id + location_id
Module docsDocument print
BridgeList/patch via device token; WebSocket document_print_job.new

Columns on the monitor map directly to DocumentPrintJobSummary (jobKind, sourceType, sourceId, targetPrinterId, claimedBy, status timestamps, etc.).


Live WebSocket status

GET /websocket-status returns connection metadata for:

NamespaceTypical clientsRoom filter
/restaurantPWA POS, Print Bridge agentBusiness + location rooms
/kdsKDS kiosk / admin KDSrst:{businessId}:{locationId}:all and station rooms

Each client entry may include socketId, userId, userEmail, deviceId, deviceName, stationId, rooms, connectedAt. The monitor correlates deviceId with kds_device rows to show whether a paired device currently has an active socket.

Event payloads for real-time print (not the same as history REST):

EventNamespaceWhen
print_job.new/restaurantKitchen job created (send-to-kitchen)
print_job.updated/restaurantJob status patched (bridge or network printer)
document_print_job.new/restaurantDocument job enqueued

API quick reference

Kitchen history (Firebase — monitor page)

curl -X GET '{{BASE_URL}}/print-jobs/history?locationId={{locationId}}&limit=20' \
-H 'Authorization: Bearer {{ID_TOKEN}}'
  • Required: locationId
  • Optional: limit (1–100, default 20)
  • Response: Array of jobs with ticketData, stationName, isTestPrint, timestamps, lastError

Document history (Firebase — monitor page)

curl -X GET '{{BASE_URL}}/document-print-jobs/history?businessId={{businessId}}&locationId={{locationId}}&limit=20' \
-H 'Authorization: Bearer {{ID_TOKEN}}'

WebSocket status (Firebase)

curl -X GET '{{BASE_URL}}/websocket-status?businessId={{businessId}}&locationId={{locationId}}' \
-H 'Authorization: Bearer {{ID_TOKEN}}'

Debugging checklist

  1. Job ID in monitor but nothing printed — Check print_job.status and last_error; confirm Print Bridge subscribed to print_job.new for that station_id; see Print Bridge spec.
  2. KDS shows ticket, monitor empty for kitchen tab — KDS-only station may have kitchen_ticket without print_job; expected per KDS model.
  3. Wrong product/table on row — Trace order_item_idorder / product / dining_table; modifier text comes from order_item_modifier snapshots, not live catalog names.
  4. Stale list — History is poll-based (10 s); live status changes also emit print_job.updated on /restaurant.

TopicDocument
print_job vs kitchen_ticketkds-tracking-model.md
Schema DDL for print_jobRestaurant.md
cURL examples (list/patch jobs)restaurant-api-postman.md
Modifier snapshots on kitchen ticketsmenus-modifier-groups.md
Document print queuedocument-print/index.md

Last updated: 2026-05-21