CRM · Full-stack web platform · AI automation
Easy Control
From web form to signed contract: AI qualifies, the CEO approves and WhatsApp follow-ups run on their own, with every send monitored.
- Client
- Bolsa Atleta USA
- Role
- Full-stack Software Engineer
- Year
- 2026
- Technologies
- Next.js
- React
- TypeScript
- Node.js
- PostgreSQL (Supabase)
- Google Cloud
- Gemini API
- GitHub Actions































Context
Bolsa Atleta USA advises Brazilian athletes seeking sports scholarships at schools and universities in the United States. The project covers the complete system: the public website with its assessment form, and Easy Control, the internal CRM and operations platform the CEO and the team use for sales, contracts and family follow-up. I built it as the sole engineer, AI-assisted (Claude Code), and it is in production.
Challenge
Leads from paid campaigns arrive at any hour and lose interest quickly. Most athletes are minors and the decision involves a large investment, so every automated message requires control over eligibility, timing and recipient. The system had to automate the sales funnel without removing human approval, and continuously monitor delivery, including silent failures from external providers.
Results
- Cloud Functions in production
- 27
- screens in Easy Control
- 60+
- pull requests merged in 2026
- 410+
- CI guard test files
- 41
Key deliverables
- 01Architected and built the public website and multi-step form with Next.js, React and TypeScript, with internationalization in Portuguese, English and Spanish and campaign attribution (UTM, source and device) stored on every lead in PostgreSQL (Supabase).
- 02Integrated Gemini into lead qualification with a versioned prompt, an auditable 0–100 financial score, five classification states and an adversarial second pass, keeping human approval before the first outbound outreach to each form lead.
- 03Built Easy Control with Next.js, React and Supabase, a platform with more than 60 screens (kanban pipeline with editable stages, executive War Room and approval queue), with role-based access control (RBAC) and PostgreSQL Row Level Security.
- 04Designed the Easy Control component library and design system with React, TypeScript and Tailwind CSS (color, typography, radius and shadow tokens, typed variants with class-variance-authority, drag-and-drop domain components, and light and dark themes), applied across every screen.
- 05Built the serverless backend with 27 Node.js 20 Cloud Functions on Google Cloud (AI qualification, WhatsApp cadence via Z-API, conversation flow engine, calendar, billing and data syncs), with idempotent sending and two independent sending safeguards in the flow engine.
- 06Implemented observability with 23 automated health checks (Cloud Function + Cloud Scheduler), WhatsApp and email alerts and a dead-man's switch on GitHub Actions, plus CI/CD with 41 guard test files that block merges on regressions.
Screens and components
The funnel on mobile
The funnel starts on the public website, in Portuguese, English and Spanish. The mobile-first form captures the investment range that feeds the AI score, and the approved lead gets the meeting invitation and confirmation on WhatsApp. The conversation was recreated with fictitious data.
Human approval
The approval dossier brings together Gemini's auditable score and reasoning so the CEO can decide. Recreated screen with fictitious data.

Pipeline with editable stages
The kanban pipeline has editable stages, and its first column is the human approval queue. Recreated screen with fictitious data.

War Room
The War Room brings revenue, funnel, cash and editable goals together on a single screen. Recreated screen with fictitious data.

Conversation flows
The conversation flow engine is channel-agnostic, measures lead capture and runs live on WhatsApp. Recreated screen with fictitious data.

Observability
The observability monitor runs automated checks every 30 minutes and confirms actual message delivery. Recreated screen with fictitious data.

Design system foundations
Light and dark theme tokens feed primitives with typed variants, reused across more than 60 screens.

Card anatomy
The kanban card is built from primitives and composes the column and the board, with every state coming from the component's own classes.

Domain components
Domain components cover loading, dragging, empty and error states, and switch themes through tokens alone.

Architecture
The board follows the lead journey from 1 to 10: from the Next.js form to PostgreSQL on Supabase, from the 27 Cloud Functions on Google Cloud to the CEO's approval and confirmed WhatsApp delivery, with the watcher outside Google Cloud and the decisions and trade-offs alongside.

Features and the pains they solve
Every feature was born from a real operational problem.
01
AI lead qualification
- Pain
- With a two-person operation, every meeting counts. The biggest cost was hours of meetings with mid-profile leads, plus forms filled in with random data.
- Solution
- Every new form triggers a Cloud Function that sends the sanitized data to Gemini (versioned prompt, temperature 0) and gets back a 0 to 100 financial score based on profession tier. A code-level gate stops junk data from ever coming out HOT or WARM, and the middle band gets an adversarial second pass.
Impact: 0 to 100 score · 5 classifications
02
Human approval queue
- Pain
- In the fully automated version, a HOT or WARM lead got its first WhatsApp message without any human review: the AI alone decided who was invited.
- Solution
- HOT and WARM leads come in as pending in the first pipeline column, with the AI dossier, and the CEO is notified right away. Only approval creates the deal and unlocks outreach; requalification never overrides that decision, and anything pending for more than 24 hours raises an alert.
Impact: 100% of first WhatsApps need approval
03
WhatsApp cadence
- Pain
- Campaign leads lose interest fast, so follow-ups have to go out at the right time and only to the right people: a single missing eligibility filter is enough for a message to reach someone out of profile or at the wrong moment.
- Solution
- Hourly schedulers send the first message and two follow-ups through Z‑API, filtering by class, timing and approval, and stop once the lead books a meeting. Each send is claimed with an atomic compare-and-set (CAS) before it goes out, and a CI guard test blocks the merge if any filter disappears.
Impact: Default: 22 h, 48 h and 7 days
04
Observability
- Pain
- A WhatsApp provider can answer 200 OK without delivering anything: without monitoring real delivery, the connection drops, the queues look up to date and nobody notices.
- Solution
- Every 30 minutes, a Cloud Function looks for positive signs of life, such as the connection state and the copy of each message WhatsApp echoes back as proof of delivery. Alerts go out on WhatsApp and by email, and a dead-man's switch on GitHub Actions fires if the monitor itself stops.
Impact: Up to 23 checks every 30 min
05
Meeting detection via Calendar
- Pain
- Meetings booked by leads could fail to reach the CRM, with no error or log, when the phone number came in a format the parser didn't recognize (like the area code in parentheses glued to the digits). And if Google's push failed, there was no second chance.
- Solution
- A Google Calendar push notification matches the event to the lead (email or last 10 digits of the phone), confirms the meeting to the lead with the Meet link, notifies the CEO and moves the deal to Meeting booked. An hourly sweep recovers anything the push missed.
Impact: Push + hourly sweep
06
Pipeline with editable stages
- Pain
- The CEO's sales process had 9 stages that didn't match the stages stored in the database, and renaming one would have required a database migration plus changes scattered across the code.
- Solution
- A drag-and-drop kanban whose column labels and order come from configuration, not from the database enum. Clicking a column lets the CEO edit its name, automations and AI agents, and create columns of their own.
Impact: 9 stages + up to 6 custom columns
07
War Room
- Pain
- Leads landed in a Google spreadsheet, and there was no single view of revenue, funnel and cash.
- Solution
- An executive dashboard that brings together MRR, ARR, total pipeline, average ticket and conversion, with shortcuts to the goal, funnel, cash, risk, positioning and family analyses, all computed from the CRM's own data.
Impact: 6 executive panels
08
Conversation flows
- Pain
- The conversation automation tool used before measured sends, not results: plenty of activity, but hardly any captured contact, email or phone number.
- Solution
- An in-house, channel-agnostic engine, live on WhatsApp and ready for Instagram (pending Meta's app review), with chained questions and a capture block that validates email and phone before saving. Every step goes to an append-only trail that measures capture block by block.
Impact: 2 independent sending safeguards
09
No-code automations
- Pain
- Operational rules, like a task for a stalled negotiation or a reminder for an upcoming installment, couldn't be set up without code.
- Solution
- A visual trigger, conditions and actions builder where the CEO sets up the rule. A Cloud Function runs the rules every hour with compare-and-set, retries with backoff and a 45–60 s pause between WhatsApp sends, and every new automation is monitored from the moment it is created.
Impact: 14 triggers and 7 action types
10
Meeting transcripts
- Pain
- The Google Meet transcript sat in a document attached to the event, outside the lead's history in the CRM.
- Solution
- A Cloud Function finds the document on the Calendar event, exports the text through the Drive API, optionally summarizes it with Gemini and stores it all on the deal, also on demand from the Meeting tab.
Impact: Every 2 h, no duplicates
11
Assessment form
- Pain
- Leads come from paid campaigns on mobile, some from outside Brazil, and the assessment is long. A form tied to Brazilian phone numbers and postal codes would shut those families out, and closing the tab halfway would lose the answers.
- Solution
- A 12-step mobile-first form in 2 stages, in Portuguese, English and Spanish, with international phone numbers, a country-aware address step and a draft saved on the device. Every submission stores UTMs, landing page, CTA and device alongside the lead.
Impact: 12 steps in 3 languages
12
Meta Ads spend and CAC
- Pain
- Marketing spend was entered by hand, per channel and per month, with no link to the campaigns that brought in each lead.
- Solution
- A daily sync with the Marketing API stores spend per campaign per day and matches the campaign ID with each lead's utm_id, computing CAC per lead, per qualified lead and per customer.
Impact: CAC at 3 funnel stages























