Request Lifecycle¶
Two kinds of "requests" run through Prism: synchronous HTTP requests and asynchronous queue/cron work. Understanding both is essential — most Prism features are initiated by HTTP but completed asynchronously.
1. Synchronous HTTP request¶
flowchart TD
A[Incoming HTTP request] --> B["bodyParser (urlencoded + json)"]
B --> C[CORS wildcard]
C --> D["traceIdMiddleware<br/>(AsyncLocalStorage sets trace_id)"]
D --> E["requestLogger<br/>(detects plaintext password, never logs value)"]
E --> F{Route match}
F --> G["Route-level auth middleware<br/>(authMiddleware / adminMiddleware /<br/>appMiddleware / jwt* / crm_offer / injestion)"]
G -->|reject| G2[403/401 fail-closed]
G -->|pass, sets req.body.created_by /<br/>req.parent_business_id| H[Controller function]
H --> I["Business logic:<br/>commonFunctions / processLibrary / raw SQL / mongoose"]
I --> J{Work type}
J -->|read| K[Query Mongo/MySQL/Redis → respond]
J -->|write that needs async| L[Enqueue into a queue collection → respond 'accepted']
K --> M[JSON response]
L --> M
Middleware order (from index.js)¶
bodyParser.urlencoded+bodyParser.jsoncors()— wildcard origin ⚠️loggerService.traceIdMiddleware()— sets a request-scopedtrace_id(fromx-trace-idheader or a new UUID v4) so every log line in the request correlates.requestLogger— security monitor: flags requests carrying a plaintext password (logs metadata, never the value).- Route mounting, each route attaching its own auth middleware.
Auth selection by route family¶
| Route family | Base path | Typical middleware |
|---|---|---|
| CRM app (staff/web) | /crm_api, /crm_api/v2, /stats |
authMiddleware (some open) |
| Admin | within /crm_api |
adminMiddleware (business_id==1) |
| Customer app (loyalty) | prism_routes/loyalty_rewards |
appMiddleware |
| POS / 3rd-party integration | /integration/v1, parts of /injestion |
crm_offer_middleware |
| Order ingestion (specific) | /injestion/ls_center, /sync/crm/token |
injestion_middleware (static token) |
| WhatsApp login | prism_routes/whatsapp_login |
jwtWhatsappMiddleware |
Details: Authentication. Full route tables: API.
Important pattern: many controllers enqueue rather than fully process. E.g. an ingestion POST returns
200after inserting intocrm_queuewithstatus:0; the real work happens later in a cron. Always ask: "is this endpoint synchronous or fire-and-forget?"
2. Asynchronous (cron/queue) lifecycle¶
The generic queue pattern used throughout Prism:
stateDiagram-v2
[*] --> queued: producer inserts (status=0 / pending)
queued --> in_progress: cron picks batch
in_progress --> done: success (status=processed/sent)
in_progress --> retry: transient failure (retry_count++)
retry --> in_progress: next cron tick (backoff)
retry --> failed: max retries exceeded
in_progress --> failed: permanent error
done --> [*]
failed --> [*]
Concrete queues (see Queues for the full catalog):
| Queue | Producer | Consumer cron | Cadence |
|---|---|---|---|
crm_queue (orders) |
ingestion (Lambda + monolith) | ingestion crons | frequent poll |
crm_points_allocation_queue (MySQL) |
order processing, rewards, referral | points allocation cron | ~every 2 min, ~5000/batch, 5 retries |
| WhatsApp queue | campaign/journey builders | sendWhatsappMessageCron (+ transactional/remaining) |
~1–3 sec poll |
| SMS queue | campaign builders | smsQueueCron |
~3 min |
| Push queue | campaign builders | pushQueueCron |
~5 min |
notiJunk |
notification producers | processNotiQueue / delete crons |
periodic |
3. End-to-end: "an order becomes a WhatsApp win-back"¶
Ties the whole system together across sync + async boundaries:
sequenceDiagram
autonumber
participant POS
participant ING as Ingestion (HTTP/Lambda)
participant Q as crm_queue
participant PROC as Ingestion cron
participant C360 as Customer/Order data
participant PTS as Points queue (MySQL)
participant RFM as rfmSegments cron (nightly)
participant JRNY as processAutomatedCampaigns
participant WQ as WhatsApp queue
participant SND as sendWhatsappCron
participant GS as Gupshup/Meta
participant ROI as ROI attribution cron
POS->>ING: order
ING->>Q: enqueue status:0
PROC->>Q: drain
PROC->>C360: upsert customer + order
PROC->>PTS: enqueue earned points
Note over RFM: nightly
RFM->>C360: recompute R/F/M → segment=At Risk
Note over JRNY: journey 'Lost Customers' matches
JRNY->>WQ: enqueue message to At-Risk customer
SND->>WQ: poll
SND->>GS: send template
GS-->>SND: delivered/read webhook
Note over ROI: customer orders within attribution window
ROI->>C360: attribute revenue to journey
4. Error handling & tracing¶
trace_idflows through logs within a single HTTP request (AsyncLocalStorage). Grep logs bytrace_idto reconstruct a request. See Debugging.- Auth failures are fail-closed (403/500 on any error).
- Queue failures rely on
status+retry_countfields and backoff; there is no global DLQ — stuck items sit in the queue and are surfaced by cleanup/monitor crons. - Cron overlap protection: several crons use a status/lock document (e.g.
cron_stats,checkin_cron_status) to avoid concurrent runs; stuck-cron detection is reactive (~20 min) with a force-close fallback (~4 h). ⚠️ Not fully robust — see Tech Debt.
5. What to check when "nothing happened"¶
| Symptom | Where to look |
|---|---|
| Order didn't appear | crm_queue for status:0 stuck docs; ingestion cron logs |
| Points not credited | crm_points_allocation_queue status/retry; handleWalletPointsFlow logs |
| Campaign not delivered | WhatsApp/SMS/push queue status; business wallet balance; provider errors |
| Segment stale | rfmSegments / customerInsightsCron last run (cron_stats) |
| Dashboard number off | MIS/aggregation cron freshness; cross-widget integrity (see Common Issues) |
Related¶
Assessment¶
Level-5 production-debugging: ../15-Assessments/Level-5-Production-Debugging.md