Architecture
Architecture
One backend you own, a tiny widget, and a PWA inbox. Every external service sits behind an adapter.
System map#
Stack#
| Layer | Choice |
|---|---|
| Widget | Vanilla TypeScript, shadow DOM, Vite library build, lazy capture module (modern-screenshot) |
| API | FastAPI on Python 3.13 with uv, SQLAlchemy 2 async, Alembic migrations |
| Data | Postgres 16 with pgvector: conversations, leads, knowledge and vectors in one database |
| Realtime | WebSocket gateway with Redis pub/sub and an SSE fallback |
| Files | Any S3-compatible bucket (RustFS locally), private, behind signed URLs |
| Inbox / admin | Next.js 16 PWA, React 19, Tailwind v4, Firebase Auth and Cloud Messaging |
| LLM | Gemini Flash-Lite through a router with fallbacks; fake provider for tests |
Adapters: swap any dependency#
LLM, storage, push, email and CRM each sit behind one interface with a real and a fake implementation. Swapping a provider is one adapter plus config, not a rewrite. The fakes make the whole system run offline for development and tests.
| Seam | Today | Later |
|---|---|---|
| LLM | Gemini API (gemini_api), fake | Vertex AI as a second provider |
| Push | Firebase Cloud Messaging; logged when not configured | Slack, email digests |
| CRM | Internal leads + CSV, FakeCrm through the outbox | Twenty CRM adapter |
Resend when RESEND_API_KEY is set, otherwise logged | Org-level SMTP / provider settings | |
| Storage | S3-compatible (RustFS locally) | R2, S3, GCS interop |
Data model#
Outbox for side effects#
Pushes, emails and CRM writes are rows in an outbox table, delivered by a worker with retries and recorded per target. A failing provider never blocks a chat, and failures show in admin.
Security and privacy#
- Public project keys work only on allowlisted domains. Visitor tokens are HMAC-signed with a short lifetime.
identify()requires a server-side HMAC signature.- Role checks on every inbox and admin query. Sign-in is invite-only.
- Rate limits per IP, per visitor and per project, plus message and upload size caps.
- Email is never required. Screenshots are masked before upload and stored privately.
- Retention per project: 90 days for anonymous chats and 12 months for leads by default.