Every surface, with the file paths.
Five product surfaces. For each one: what it does, how it's wired, and the specific safety machinery that exists so an engineer can't silently regress it.
Inbound email pipeline
SendGrid Inbound Parse → multi-stage AI safety chain → reply.
- Webhook secret verified with crypto.timingSafeEqual; production rejects unsigned
- SendGrid raw + parsed modes both supported (parses MIME when raw)
- Lead lookup keyed strictly by email (or phone for SMS) — never both
- Idempotent reply: SHA256 hash over (lead, message, minute) prevents retry duplicates
- Per-channel system prompt assembled per request from dealership profile + agent identity
- Inventory-grounded smart-component dropped if confidence < threshold (no hallucinated cars)
- Post-generation chain: stripEmDashes → stripUngroundedClaims → HTML sanitizer
app/api/webhooks/email/route.ts · trigger/SendResponse.ts · lib/prompts/emailSystemPrompt.tsInbound message answered in under a minute, in the dealership's voice, without quoting a price the AI shouldn't.
Outbound campaigns with AI targeting
Describe the audience in English; the assistant translates to a typed Supabase query.
- Vercel AI SDK generateObject with zod schema — never returns free-text SQL
- Two modes: chat (t=0.6) and analysis (t=0.1) auto-detected from intent
- On error returns 4xx/5xx — explicitly never falls back to 'all leads'
- Operator confirms the resolved segment before fan-out
- A/B variants split into leads_a / leads_b at confirm time, reproducible at re-send
- Trigger.dev v3 fan-out — one job per lead, observable in the Trigger dashboard
- Lead-field interpolations HTML-escaped via lib/text/escapeLeadField
/api/campaigns-ai · /api/campaigns/[id]/trigger · trigger/sendCampaign{Emails,Sms}.ts"Everyone who asked about a RAV4 in 30 days and never replied" — typed query, confirmed segment, two-stage safety, real send.
Embedded chat widget
One <script> tag. Shadow DOM (not iframe). Per-widget Origin allow-list.
- Loader served from /widget.js with controlled CORS / CORP / cache headers
- Renders inline via Shadow DOM so host-page CSP can't block it
- Pre-conversion transcripts buffer in widget_sessions.messages_buffer (no CRM clutter)
- Promotes to a real leads row only when contact info (regex EMAIL_RE / PHONE_RE) appears
- Per-widget allowed_origins[] checked against the request's Origin header — primary abuse gate
- Inventory query inline so 'do you have a RAV4?' answers immediately
- 8-hour session TTL — kiosk-safe (next visitor doesn't inherit prior lead)
app/widget.js/route.ts · app/api/widget/chat/route.ts · widget_sessions tableCustomer asks 'do you have a 2024 RAV4?' on the dealership site; gets a real answer + scheduled callback.
Lead pipeline
One lead row per customer, captured from any channel.
- Six capture sources: email, SMS, voice, widget conversion, CSV upload, ADF feed
- Lookup keyed by ONE of email or phone (never both) — shared landlines don't merge customers
- Conversation history filtered per channel — email ≠ SMS thread
- Lead scoring materialized to leads.lead_score (0–100), drives queue ordering
- DNC flags (do_not_email, do_not_mail) honored on outbound; SMS opt-out via lib/compliance/sms
- next_followup column drives the appointment-reminder Trigger task
supabase-actions/leads/getLeadByEmailorPhone.ts · lib/leads/{deduplication,routing,validation}.tsLead history is one queryable timeline per customer, not a pile of duplicate rows from cross-channel double-counts.
Voice (Twilio + personaplex)
Twilio handles the carrier; a separate Python service handles voice cloning.
- Inbound voice → /api/twilio/incoming-call → /api/twilio/process-speech (TTL-mapped state)
- STT + intent extraction in-app via OpenRouter; system prompt from voiceSystemPrompt.ts
- Voice cloning service is a separate FastAPI app (personaplex-service) — independent scaling
- WebSocket bridge to personaplex-service authed via BRIDGE_SECRET signed token
- Recording disclosure prompt wired into the call-open path
- Outbound voice campaigns via trigger/aiCallAgent.ts
app/api/twilio/* · lib/voice/* · personaplex-service/server.pyInbound calls answered by an AI that knows the dealership's hours, current inventory, and what to never quote.