Appearance
Communication flows
The major flows as LLD sequence diagrams. Cross-cutting mechanics live in architecture — the send path, webhook/event processing, and failed-message/retry diagrams are there and every flow below rides them; they are not repeated per use case. Categories and prices per flow come from the Meta API assessment.
None of these flows is built. Each states its trigger point in the code that exists today, so the first implementation wires a known seam rather than inventing one.
1 · Order confirmation (buyer + merchant, one trigger)
Trigger: place-public-order succeeds — orders.buyer_phone is already NOT NULL for every order, anonymous or signed-in, so this flow needs no schema change and no app install on the buyer's side. Category UTILITY for both messages.
2 · Payment / transaction notification
Trigger: razorpay-webhook records a payment that payment_counts_as_collected() accepts — the enqueue rides the same transaction that writes the payment row, so a receipt can never be sent for money the ledger did not record.
3 · Order status updates (the Scan-to-collect loop's off-app half)
Trigger: manage-order transitions (ready → collected). The buyer has no app; WhatsApp is how "your idol is ready for collection" reaches them at all.
4 · Signup / onboarding communication
Trigger: onboarding completion (provision-workspace succeeds). One welcome message, factual, naming the next step — any promotional line forces MARKETING categorization and its price, so the copy stays utility-shaped. No OTP here: authentication is email OTP by ADR-0008, and Supabase cannot route OTP through our WABA natively (assessment §7).
5 · Template lifecycle: creation → Meta review → approval → usage
The registry mirrors Meta; Meta is the only approver. The dispatcher refuses any template whose mirrored status is not APPROVED — including a template that WAS approved and got paused for quality between campaign scheduling and execution.
6 · Promotional campaign (create → schedule → execute → track)
Consent-gated end to end; audience is resolved from the consent ledger at execution, not at creation. Meta's per-user marketing cap (131049) is expected steady-state noise in India — those recipients are recorded failed with the code and are not retried on a timer.
Campaign performance tracking is the last two lines — there is no separate pipeline. Delivered / read / failed are folds over communication_messages by campaign_id; click-through comes from Meta's template_analytics (opt-in, 90-day lookback); revenue attribution joins campaign → orders placed within the attribution window, on our own ledger.
7 · Usage, cost and billing visibility
Two sources reconciled, one truth per question — our ledger answers what we sent, Meta answers what Meta charges. There is no billing API (assessment §6): payment method and invoices are Billing Hub UI tasks on a runbook, and no recharge flow exists to diagram.
8 · Merchant / enterprise-specific communication (P3+)
The R1 architecture already carries the two columns that make this additive (workspace_id on every message, owner_workspace_id on every WABA). What changes per stage is who the sender is and who pays Meta — and the Tech Provider fact that reshapes the model: Tech Providers get no credit line, so a tenant with their own WABA attaches their own card and pays Meta directly.