Lighthouse Graphics needed a way to sell AI voice receptionists to their own customers — and, later, to sell the selling. A white-label platform where agencies could onboard their own sub-tenants, rebrand the UI, and plug in their CRM of choice.
┌──────────────────────┐
│ Reseller · Tenant │ ← white-label UI, Vue 3
└──────────┬───────────┘
│
┌────────┴────────┐
│ Laravel API │ ← Sanctum · role-scoped
└───┬─────┬───────┘
│ │
┌─────────────┘ └────────────────┐
│ │
┌────────▼─────────┐ ┌───────────▼──────────┐
│ Supabase (pg) │ │ n8n workflows │
│ · tenants │ │ · agent config (LLM) │
│ · agents │ │ · GHL sync │
│ · call_logs │ │ · webhooks │
└────────┬─────────┘ └───────────┬──────────┘
│ │
┌────────▼─────────┐ ┌───────────▼──────────┐
│ Pinecone KB │ │ Voice (Pipecat) │
│ · 1536-d cosine │ │ · Deepgram + 11Labs │
│ · reseller scope │ │ · Claude / OpenAI │
└──────────────────┘ └──────────────────────┘ A per-tenant namespace was the textbook answer — but the number of resellers was bounded while tenants per reseller were not. Reseller-scoped namespaces with tenant filters gave us cheaper indexing and simpler cache invalidation, without leaking data between resellers (the actual trust boundary).
Writing a task-graph engine is a whole product. n8n was close enough, had the integrations we needed on day one, and let non-engineers ship automations. We wrote a thin MCP layer (later open-sourced) so Claude could drive n8n workflows directly.
Agency owners don't want to fill out 40 fields to set up a voice agent. We built a meta-agent that interviews them in chat and writes the agent config as it goes. Faster than any form — and it doubled as onboarding.
We built the voice layer behind an interface the rest of the code couldn't see past — providers could be swapped per tenant without the app knowing the difference. Pipecat became the default for accounts that wanted tighter control over the call pipeline.