Skip to content
GoodDayAI
All cases

Internal CRM for an AI agency · Belarus

GoodDayAI CRM

Our own CRM for our own pipeline — on the same database as the site and the bots

The task

The agency already had a public site with a booking form and a Telegram bot, both writing clients into one Supabase table. What was missing was a working tool on top of that data: a sales pipeline with clear stages, analytics on money and where deals get stuck, and a way to track combined profit and split it between co-owners — without ever putting real client names and deal sums on the public site or in a bot that outsiders can reach.

Problems we solved

Client and deal data can’t sit on the public site, but the pipeline has to live somewhere.

A separate Next.js project on its own Vercel deployment and domain: the public site has no route that ever returns client data. Sign-in is a password behind an HMAC-signed httpOnly cookie, checked in middleware on every request, with anti-bruteforce, `noindex` and a strict CSP.

Deals move through 15 different stages — from first contact to renewal or pause — and it’s easy to mix up what follows what.

A kanban board backed by a status machine: every stage has its own set of allowed transitions, and an invalid jump is rejected at the API level, not just hidden in the UI. Cards move by drag-and-drop or a button; filters cover source, amount, "remind today" and stale deals.

A deal’s amount lived in a single field per client — there was no way to separately record a one-off setup fee and a recurring monthly subscription, and a monthly payment was only ever counted once in the report.

Split into two fields: the one-off setup fee counts as income once, when the deal is won; the monthly subscription feeds a separate MRR figure, drawn only from clients who are currently paying (renewal and pause are tracked separately and don’t get mixed together).

The two co-owners’ profit was tracked by hand, with no single place showing income, expenses and each person’s final share.

An "Expenses" section: a shared cash box by category across several currencies, profit = income from won deals minus expenses, each co-owner’s share set by a configurable percentage editable right in the UI.

Some clients come through franchise partners, and those partners must not see other clients or the shared cash box.

Multi-tenancy keyed on a `tenant` field: each franchise has its own account and password, sees only its own clients, and the owner’s expenses and analytics sections are unreachable for it — isolation is enforced in every API route, not just by hiding a button.

A missed call or a forgotten follow-up slips through the list of leads unnoticed.

Several independent "follow up" reminders per client, each with its own note; status changes and other actions are written to a `crm_log` audit trail with the name of whoever made them.

What we did

  • A 15-stage kanban board with validated transitions and drag-and-drop
  • Client card: services, a one-off setup fee and a monthly subscription as separate fields, requisites, a note, an action history
  • Analytics: win rate, MRR, a stage-by-stage conversion funnel, average deal size, "where deals get stuck"
  • Expenses and profit: a shared cash box by category and currency, each co-owner’s share configurable in the UI
  • Franchises: separate partner accounts with client isolation by `tenant`, enforced in every API route
  • Referral programme: personal gift links for friends, the reward granted only after the friend’s first payment
  • AI on top of the pipeline: a draft message to the client, natural-language Q&A over the whole deal base, lead scoring with a suggested next step
  • Several independent "follow up" reminders per client and a shared action log naming who did what
  • A separate hidden Vercel deployment, a password behind an HMAC cookie, anti-bruteforce, `noindex` and a strict CSP

How it looks

Homepage of the GoodDayAI CRM website on desktop
Homepage of the GoodDayAI CRM website on a phone