Architecture
The backend is Django served over Daphne (ASGI), which lets
DRF views and a Channels WebSocket consumer share one process.
Four apps — authen, menu,
payment, notifications — own their
own models, and cross-app events go through a
notify_user call that group-sends into the
Channels layer rather than apps reaching into each other's
state directly.
Order flow: trusting the server, not the client, for money
The checkout total is computed server-side when the Stripe PaymentIntent is created — the client submits order items, not a price. That's the one non-negotiable rule in a payment flow: a client-supplied total is a client-supplied discount waiting to happen.
POST /api/order-items — the client assembles items; no price travels with them.
POST /payment/create-checkout-session — the server recomputes the total from menu prices and creates the Stripe PaymentIntent.
Stripe Elements confirms payment directly against Stripe — card data never touches the Django backend.
PUT /api/orders marks the order complete, which calls notify_user() to push a WebSocket notification — the kitchen-to-customer update is a live event, not something the client has to poll for.
Auth: making token refresh invisible to callers
Access tokens expire; the interesting part is that no calling code anywhere in the app needs to know that. An axios interceptor sits in front of every request: on a 401, it transparently exchanges the refresh token for a new access token and replays the original request once, so the caller only ever sees a 200.
The same token is reused for the WebSocket connection
(/ws/notifications?token=), so a logged-in session
has exactly one source of truth for identity across both the
request/response API and the persistent notification channel.
Data model
Orders, order items, payments, and notifications are modeled as separate entities linked back to one order rather than collapsed into a single wide table — a payment's status and a notification's read state each evolve independently of the order's own lifecycle, which matters once refunds, partial payments, or repeated notifications enter the picture.