Lead pipeline built from chat conversations
Once the WhatsApp bot was qualifying leads around the clock, a new problem surfaced almost immediately: the admissions team had no way to see what was happening. Conversations lived inside WhatsApp on a phone screen, lead statuses existed only in the bot's database, and the only way to check if someone was "ready to buy" was to query PostgreSQL directly. The school needed a proper sales dashboard — something the team could open every morning, see the pipeline at a glance, and know exactly who to call first.
kanban and chat history
We built a lead CRM tailored specifically to this workflow. The centerpiece is a Kanban board with four columns — all leads, ready to buy, qualified, and postponed — matching the exact categories the WhatsApp bot assigns during conversations. Each card shows the lead's name, phone number, last message timestamp, and a snippet of the most recent exchange. The team drags cards between columns as conversations progress: someone who was "qualified" last week might move to "ready to buy" after a follow-up, or to "postponed" if they say they're traveling. Drag-and-drop is built with dnd-kit, and every move triggers an optimistic update — the card moves instantly on screen, the API call fires in the background, and if the server rejects the change, the card snaps back to its original column. It's a small UX detail, but when you're moving ten cards in a row during a morning review, lag is unacceptable.
Beyond the board, there's a full chat history viewer. Every WhatsApp conversation the bot has had — and every message sent by a human agent after handoff — is visible inside the dashboard. This includes media: photos students send of their current textbooks, screenshots of competitor pricing, even voice messages rendered as playable audio clips. Getting media to display correctly was more involved than expected. WhatsApp media files are saved on the server by the Node.js bridge, but the dashboard runs on a separate frontend — so every image and audio file routes through the FastAPI backend, which serves them with proper authentication headers. It's essentially a media proxy, and it needed to handle file types that WhatsApp sends in its own compressed formats.
statistics and access
The statistics page gives the team a bird's-eye view: total leads this week, conversion rates by status, average time from first message to qualification, and trend charts showing how volume changes over time. Charts are built with Recharts, pulling aggregated data from the backend. One design decision we debated was whether statistics should update in real time or on refresh. Real-time would mean either WebSocket connections or constant polling, adding complexity for a team of two people who check the dashboard a few times a day. We went with polling on a 30-second interval when the stats page is active — simple, predictable, and good enough for the actual use pattern. If the team grows and the dashboard becomes a command center, we'd switch to server-sent events, but over-engineering for a future that might not arrive is a pattern we try to avoid.
Access control is JWT-based — the school's director and the two admissions staff each have accounts, and the API rejects unauthenticated requests. It's a simple setup because the user base is three people, but the auth layer is built properly so it can scale to roles and permissions later without a rewrite. The frontend is Next.js with React and Tailwind, keeping the stack consistent with the school's other tooling and making maintenance straightforward.
results
The result is that the admissions team starts each day with a clear picture: who's hot, who needs a nudge, and who's gone quiet. They stopped losing track of leads that fell between the cracks of a phone screen, and the director can see conversion metrics without asking anyone to pull numbers. The takeaway from this build: a CRM doesn't need to be Salesforce. When you control the data source — in this case, the WhatsApp bot feeding qualified leads directly into the pipeline — you can build something purpose-fit that the team actually uses, instead of configuring a generic tool that nobody opens after the first week.
Stack
Frontend: Next.js 16, React 19, Tailwind 4, Recharts, dnd-kit
Backend: FastAPI, PostgreSQL
Auth: JWT
