Dubai-based forex broker · 2026
Campaign delivery console
An internal Next.js console replacing a spreadsheet send-ledger — with role-based access, audit logging and per-message funnel reporting.
Simplified for publication. Identifiers, endpoints and customer data removed.
The problem
Campaign state lived in a spreadsheet that the automation both read and wrote. It hit the provider's read-rate ceiling under load, and concurrent runs could send the same customer the same message twice. There was also no way to answer basic questions: which template failed, and why.
What I built
- 01
Moved the send ledger into a relational schema with a uniqueness constraint across channel, recipient, campaign and date
- 02
Made dispatch claim-by-insert: the workflow inserts first and only sends if the insert created a row, so duplicates are impossible by construction rather than by check-then-act
- 03
Separated status events into an append-only table fed by delivery webhooks, giving a real funnel from accepted through delivered, read and replied
- 04
Built attribution across three databases in application code rather than cross-database SQL, keeping each connection read-only and independently replaceable
- 05
Masked contact details server-side so raw customer data never reaches the browser, including for read-only share links
- 06
Added a Claude-powered analyst over the campaign data with real guardrails — an access allow-list, a daily query quota, prompt caching to control cost, and a route that shows users exactly what the model can see
Outcome
The spreadsheet rate-limit failure mode was eliminated entirely
Duplicate sends became structurally impossible rather than merely unlikely
Per-template funnels and a failure-reason breakdown replaced manual reporting
Read-only share links let stakeholders see performance without an account and without exposing contact data
The analyst answers questions over aggregates only — raw contact rows are never sent to the model
Stack
- Next.js
- MySQL
- NextAuth
- Claude
- Docker
- GCP
- Recharts
Want something like this built?
Most of this is portable. The dedup, throttling and failure-handling patterns apply to any channel you send on.
Book a call