SSE and realtime
Nova Print uses Server-Sent Events (text/event-stream) for live order comments, consolidated order feeds, customer-link chat/status, and admin notifications. Implementations: pos/sse.py (backend-main/pos/sse.py), customerlink/sse.py (backend-main/customerlink/sse.py), pos/notification_views.py (backend-main/pos/notification_views.py).
All streams are in-memory (defaultdict lists + locks). Code comments note Redis pub/sub would be needed for multi-process production fan-out.
Auth for EventSource
Browsers' EventSource cannot set Authorization or X-POS-Access-Key. Pattern:
| Client | Query / header |
|---|---|
| POS | ?access_key= or header X-POS-Access-Key |
| Admin consolidated / notifications | ?token= (JWT access) — required on admin order + notification streams |
| Legacy per-order comments | access_key or token query or Authorization: Bearer |
| Public checkout | No auth — pos_slug + link_code in path |
Common optional cursor: ?last_event_time=<unix float>. New subscribers without a cursor get a 120s lookback (SSE_CONNECT_LOOKBACK_SECONDS) so reconnects do not miss events.
Heartbeats: roughly every 15s (event: heartbeat). Poll sleep is ~2s (order consolidated) or ~0.5s (customer-link global).
Endpoints
POS / admin orders (pos/urls.py (backend-main/pos/urls.py))
| Path | View | Auth | Events |
|---|---|---|---|
/api/pos-orders/stream/ | POSOrdersSSEView | POS access key | Session pos_{id}: connected, new_comment, order_update, notification, heartbeat |
/api/admin/orders/stream/ | AdminOrdersSSEView | ?token= JWT | Session admin: same order event types |
/api/orders/<order_id>/comments/stream/ | OrderCommentsSSEView | POS key or JWT | Per-order: connected, new_comment, order_update, heartbeat |
/api/admin/notifications/stream/ | AdminNotificationsSSEView | ?token= JWT | notification, heartbeat |
Publish helpers in pos/sse.py: notify_new_comment, notify_order_update, notify_pos_notification. Admin notifications: notify_admin in notification_views.py.
Consolidated streams replace opening one SSE connection per order.
Customer links (customerlink/urls.py (backend-main/customerlink/urls.py))
| Path | View | Auth | Events |
|---|---|---|---|
/api/customer-links/stream/ | GlobalCustomerLinkCommentsSSEView | POS access key | All links for POS; payload includes link_id |
/api/customer-links/<link_id>/comments/stream/ | CustomerLinkCommentsSSEView | POS access key | Single link |
/api/checkout/<pos_slug>/<link_code>/comments/stream/ | CustomerLinkCommentsPublicSSEView | Public | Same link events; 410 if archived |
Event types from customerlink/sse.py (backend-main/customerlink/sse.py):
event: name | When |
|---|---|
connected | Stream open |
new_comment | Chat message (notify_new_link_comment) |
status_change | Link status change |
approval_change | Design approval units snapshot |
link_submitted | On link stream after submit |
customer_link_submitted | Also pushed toward POS global awareness from notify_link_submission |
heartbeat | Keep-alive |
Call sites include customerlink serializers/views (submit, step3, comments) and POS order/workflow code that fans out approval/status to checkout.
Client tips
- Prefer consolidated
/api/pos-orders/stream/and/api/customer-links/stream/over per-resource streams. - Pass
last_event_timefrom the last received event timestamp on reconnect. - Responses set
Cache-Control: no-cache,X-Accel-Buffering: no, and permissive CORS headers for SSE. - Persist notifications via REST (
/api/pos-notifications/,/api/admin/notifications/); SSE is the live push layer on top.