Case study · Staffing and recruitment

A recruitment CRM holding 20,000+ live leads

High-volume staffing, and the pipeline lived in three places at once: inboxes, spreadsheets, and the reporting inside the ad platforms. Leads went missing between them.

20,000+ live leads managed Staffing and recruitment React/TS and PostgreSQL

Where the leads were going

Manual lead chaos across a high-volume staffing agency. Enquiries arrived by email, by web form and through ad platforms, and each channel had its own place to sit. Two consultants could work the same candidate without either of them knowing. Nobody could say what the pipeline was worth on a given morning without rebuilding it by hand in a spreadsheet.

What we built

One CRM, now carrying 20,000+ live leads. Website enquiries and Google Ads webhooks post straight into it, so the capture is not somebody's job any more. Role-based access governs who sees which desk. Email sequences run on a schedule instead of on memory, and a live dashboard shows the pipeline as it stands rather than as it stood last Thursday.

Two rules that did the real work

Deduplication is enforced at the database, not in the interface. A validation check in the front end is a suggestion; a constraint in PostgreSQL is a fact. The same candidate cannot be worked twice, and that single decision removed most of the friction between consultants.

A deal cannot be closed until its contract is attached. That was the client's rule, not ours, and it is the sort of thing an off-the-shelf CRM will let you configure as a reminder and nothing more. Here it is a condition of the state change.

Stack

React and TypeScript on the front. Express and PostgreSQL behind it, with Drizzle for the data layer and TanStack Query handling server state. The client owns the code and the repository history.

Want the same thing looked at in your business?

We map the process, find the part worth automating first, and give you a written scope with the phases separated. No obligation, and you keep the plan.