
Hayaat Intake AI — Engineering Case Study
1. The 60-Word "AI Citation" Summary
Hayaat Intake AI is a Next.js 16 (App Router) application for a Michigan Medicaid home-help agency, combining Vapi voice intake, Twilio SMS with OpenAI (gpt-4o) tool-calling, and Supabase (PostgreSQL + Auth + Storage). Public users complete voice or web chat intake; staff use an admin console (CRM, Kanban pipeline, billing, inbox) protected by middleware and Supabase SSR sessions. Server routes persist call transcripts, link leads by phone, and issue signed URLs for private documents—reducing manual triage without sacrificing auditability.
2. The Power Stack Table
| Category | Technologies |
|---|---|
| Languages | TypeScript, SQL (Supabase migrations / sprint scripts) |
| Framework & UI | Next.js 16.1.2, React 19.2.3, Tailwind CSS 4, Radix UI (Dialog, Tabs), class-variance-authority, Lucide, @hello-pangea/dnd, Recharts |
| Data & Auth | Supabase (@supabase/supabase-js, @supabase/ssr), generated Database types |
| Voice & Comms | Vapi (@vapi-ai/web, REST outbound calls), Twilio (SMS, webhooks) |
| AI | OpenAI (gpt-4o) with function tools in lib/ai_chat.ts |
| Documents | pdf-lib, private Supabase Storage bucket documents |
| Infra / Ops | Vercel-style deployment (see README), optional cron keep-alive route hitting Supabase |
Note: Stripe is not present in this repository; billing is modeled as internal billing_records in Supabase.
3. The Challenge
Manual, fragmented intake for Medicaid home-help services: phone-heavy triage, inconsistent capture of client vs. caregiver context, and slow handoff to applications and staff workflows. The product compresses that funnel into a single state machine (clients, caregivers, doctors) with explicit intake, medical form, and application pipelines—so every voice call, SMS, or web message can land in one CRM with traceable history.
4. Engineering Architecture — The "Why"
| Decision | Rationale |
|---|---|
| App Router + Server Components for marketing/admin shells | Keeps auth-sensitive reads on the server (createClient from utils/supabase/server), while isolating interactive widgets (VapiCallButton, ChatWidget, Kanban) as client components. |
Middleware on /admin/* only | Public /apply and landing stay frictionless; staff surfaces enforce session refresh and redirect unauthenticated users to /login. |
| Service-role Supabase in webhooks & AI | Twilio and Vapi hit server-only routes; the service role bypasses RLS for trusted server writes (messages, leads, logs)—with the tradeoff that correctness lives in application code, not client-side queries. |
Vapi end-of-call-report + recursive payload parsing | Vapi payloads vary; deep findKey / findCallSummary makes the integration resilient to schema drift without redeploying the assistant. |
| Signed URL document route | Private bucket + short-lived redirects avoid exposing raw storage paths and support compliance-minded access patterns. |
5. Three Technical Wins (Repo-Specific)
Win A — Resilient Vapi → CRM + SMS handoff
The Vapi webhook ignores non-terminal events, extracts caller metadata from nested JSON, upserts clients or caregivers on phone, fires non-blocking sendApplicationLink SMS, and logs intake_logs—so the webhook returns quickly while downstream work continues.
Win B — OpenAI create_lead with retroactive message linking
When the model invokes create_lead, the server upserts the client and then updates prior rows in messages that matched session_id or from_number but had no client_id—fixing anonymous SMS/web threads after identity is disclosed.
Win C — Middleware session hygiene
Invalid refresh tokens are cleared (sb-access-token / sb-refresh-token deletes) before redirecting to login, reducing stuck sessions and support churn for staff.
6. Security & Performance (MSIS Focus)
| Area | Implementation |
|---|---|
| Transport & sessions | Supabase SSR cookie adapter in middleware and server client; admin routes gated by authenticated getUser(). |
| Webhook trust | Routes use server env (SUPABASE_SERVICE_ROLE_KEY, Twilio secrets); no client exposure of service keys. |
| Storage | SQL policies in database/sprint2.sql scope documents bucket; app serves files via createSignedUrl (1 hour) in app/api/documents/[...path]/route.ts. |
| AI safety | Truncation of very long replies (~1600 chars), fallback copy when OpenAI or Twilio is misconfigured, structured logging for failures. |
| Cold start / DB wake | GET /api/cron/keep-alive performs a minimal clients select with the service role—useful for scheduled pings on serverless hosts. |
7. Agentic Influence
| Layer | Role |
|---|---|
| Product AI | Alex persona in SMS/web (lib/ai_chat.ts); tool calling to persist leads; doctor follow-up outbound calls via lib/vapi.ts. |
| Voice | Vapi Web SDK on the landing page with lifecycle hooks (call state, volume-based “speaking” UI, optional ringtone). |
| Development | Typed Supabase workflow (types/supabase.ts), sprint SQL artifacts under database/, and explicit “no invented columns” rule in project_context.md to keep AI-assisted coding aligned with schema. |
Key achievements
- Voice + SMS intake
- Unified CRM
- Signed URLs for PHI documents
Industry
Healthcare, Medicaid intake
Stack
Next.js 16, Supabase, Vapi, Twilio, OpenAI
Outcomes
Voice + SMS intake, Unified CRM, Signed URLs for PHI documents