Overview
AwakeDesk is a multi-tenant SaaS that answers a business's phone with an AI receptionist. It picks up 24/7 in the business's own greeting, answers the questions customers actually ask, checks real availability, books the job straight into Google Calendar or a built-in appointment book, texts the confirmation, takes structured messages, and hands the call to a human when it should. Built, deployed, and sold end to end — product, billing, onboarding, and marketing — and live today answering three public demo lines.
The Challenge
A phone call is unforgiving. The receptionist has to respond in well under a second, cope with being interrupted, and never invent a price, an opening, or a promise — every slot it offers has to come back from the calendar first. It also has to serve a salon, an HVAC company, and a roofer from a single codebase without per-client forks, keep every tenant's data invisible to every other tenant, and meter and bill every call correctly from the very first customer.
What I Built
- Two-plane architecture — a Django + DRF control plane owns tenancy, configuration, scheduling, CRM, billing, and the dashboard; a separate media plane runs the realtime STT → LLM → TTS loop with barge-in behind a swappable
VoiceEngineinterface. The media plane imports no Django, and a test enforces the boundary so it can be promoted to its own deployable without a rewrite. - Agent compiled per call — when a call arrives, the whole assistant (prompt, voice, tools, and conversation policy) is compiled from the database for that tenant, cached in Redis, invalidated by model signals, and versioned by content hash so every call record says exactly which configuration answered it.
- Postgres row-level security for tenant isolation, with "red line" tests that prove one tenant can never read another's rows — not just scoped querysets.
- Scheduling adapters for Google Calendar (minimal free/busy and event scopes) and a native appointment book, with service durations, buffers, staff, hours, and holidays — and the ability for a caller to correct a time mid-call ("I said 10:15, not 10:30").
- Grounded answers — deterministic FAQ matching first, tenant-scoped pgvector RAG for the long tail, and a take-a-message fallback instead of an improvised answer.
- Telephony and SMS — Twilio numbers with carrier-side forwarding so the business keeps its number, A2P 10DLC-approved confirmation texts sent only after the caller agrees, owner notifications, and a native warm transfer to a human.
- Billing and metering — Stripe subscriptions with a founding plan, per-call usage and cost records, and a scheduled reaper that reconciles any call whose end-of-call report never arrived so no minute goes unbilled.
- Post-call pipeline — recording, transcript, summary, and disposition on every call, with a per-tenant retention window that actually purges what the privacy policy says it purges.
- Onboarding as data — customers are provisioned from YAML stencils (28 vertical templates) through a sales portal with a staff-only approve step; the files are the canonical config and git is the customer history.
Results
From an empty repository to a product answering a real phone number and booking into a real calendar in a single build cycle, then to a sellable product with live Stripe checkout, Google OAuth branding approved, three public demo lines, and the first founding customer being onboarded. Over 400 automated tests cover tenancy isolation, the tool loop, scheduling edge cases, and billing. Every real production call has finalized and billed correctly.
Tech Stack
Python, Django 5, Django REST Framework, PostgreSQL with pgvector and row-level security, Redis, Celery, Twilio, Stripe, Google Calendar API, a managed realtime voice engine, HTMX, Gunicorn, nginx, and Let's Encrypt.