Skip to content

Processors and workers

Middleware Backend is not a second database. It is processors (HTTP), webhook workers, and scheduled / queue workers. All of them read and write Core Backend.

Nest shape: one folder per capability, same as file-manager. Use Nest cron or a queue for schedules — do not keep Convex crons.ts in the Vue repo as the long-term home.

Sync HTTP processors

Frontend or another route calls these. User JWT (except where noted).

JobWinner URLThen Core Backend
AvailabilityPOST https://middleware-dev.bookdirect.live/api/v1/bookdirect/availability/checkGET rooms, rate_plans, bookings — return counts only
Start paymentPOST https://middleware-dev.bookdirect.live/api/v1/bookdirect/payments/initializePOST payment; GET booking (must be JWT owner)
Verify paymentPOST https://middleware-dev.bookdirect.live/api/v1/bookdirect/payments/verify/{reference}PUT payment + booking if paid
RefundPOST https://middleware-dev.bookdirect.live/api/v1/bookdirect/refundsPUT payment / booking cancelled
Send emailPOST https://middleware-dev.bookdirect.live/api/v1/bookdirect/emails/sendOptional metadata email_event_* on booking
Google ARI pushPOST https://middleware-dev.bookdirect.live/api/v1/bookdirect/google-rates/pushGET property (must own); metadata ari_last_push_at
Google rates pullPOST https://middleware-dev.bookdirect.live/api/v1/bookdirect/google-rates/pullOptional PUT rate_plan extra_data
Upload URLPOST https://middleware-dev.bookdirect.live/api/v1/nellalink/file-manager/aws/upload-urlFrontend then PUTs Core Backend gallery URLs

Details: availability, payments, refunds, emails, google-rates, file-manager.

IDOR: JWT owned_by on booking/property. Availability must not leak guest PII.

Webhook workers

PSP → Middleware Backend. No user JWT. Verify the provider signature, then update Core Backend.

JobWinner URLThen Core Backend
Paystack (and later Squad/Tsara)POST https://middleware-dev.bookdirect.live/api/v1/bookdirect/payments/webhook/paystackPUT payment paid; PUT booking confirmed; then emails

Do not accept a browser body that says “mark paid.”

IDOR: do not take owned_by from the PSP payload as a new owner.

Scheduled / queue workers (internal)

Not frontend-callable. Name them in code (src/routes/... or a workers/ folder). They GET/PUT Core Backend only.

JobTriggerCore Backend
Abandon stale holdsEvery 5–15 minBookings pending older than N minutes → cancelled (no PSP capture)
Invoice / pay-later reminderDailyGET pending bookings; POST emails
ARI reconcileHourly or nightlySame as google-rates push for published properties
Availability / inventory reconcileAfter booking stormsRe-read bookings; no local inventory table as truth
Email retryQueueFailed emails/send; metadata on booking

These replace Convex crons in bookdirect-legacy-code (convex/crons.ts). Do not document them as public OpenAPI operations. Optional comment in specs/middleware/v1 that workers are internal.

IDOR: workers use a Core Backend service x-api-key with tight path/entity scopes. They must not become a generic “update any booking” admin key for the frontend.

API-first. Middleware Backend wins over Core Backend when both exist.