Skip to content
← All results

Case study / Dubai-based forex broker / 2026

Know what reached customers. See what needs attention.

An internal Next.js console replacing a spreadsheet send-ledger — with role-based access, audit logging and per-message funnel reporting.

01 / What changed

From activity without a record to a system you can inspect.

Before

Campaign state lived in a spreadsheet the automation both read and wrote. It hit rate limits under load, and nobody could say which template failed or why.

After

A relational send ledger, an append-only event log and a console with per-template funnels, failure reasons and access controls.

02 / How it works

Every branch has a reason.

Campaign delivery console

Identifiers, endpoints and customer data removed.

03 / The decisions

Reliability lives in the details.

  1. 01

    Moved the send ledger into a relational schema with a uniqueness constraint across channel, recipient, campaign and date

  2. 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

  3. 03

    Separated status events into an append-only table fed by delivery webhooks, giving a real funnel from accepted through delivered, read and replied

  4. 04

    Built attribution across three databases in application code rather than cross-database SQL, keeping each connection read-only and independently replaceable

  5. 05

    Masked contact details server-side so raw customer data never reaches the browser, including for read-only share links

  6. 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

04 / What it changed

  • Next.js
  • MySQL
  • NextAuth
  • Claude
  • Docker
  • GCP
  • Recharts
  • 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

What the evidence shows

The console reports operational state — what was sent, delivered, read and replied to. It does not attribute revenue to any single message.

Your next chapter

Can your team see what your campaigns actually did?

Bring one process, one bottleneck or one growth goal. Let’s find a useful next step.

Book a strategy call