Ambasdr lets anyone create a personal page with an AI-powered voice and chat agent that represents them. This documentation covers the platform architecture, local development workflow, API surface, agent prompt design, DigitalOcean deployment + CI/CD, and the running production-readiness list.
Ambasdr is a platform where users create a public-facing personal page tied to an AI agent. Visitors interact with the agent through voice (WebRTC via LiveKit) or text chat (SSE streaming). The agent is personalized through the user's profile, uploaded documents, social links, and custom instructions.
The platform handles the full lifecycle: user signup via Auth0, a six-step onboarding flow that collects profile data and documents, a dashboard for ongoing management, and a public page that visitors access via a unique slug.
Gin-based REST API with OpenAPI code generation, PostgreSQL storage, S3-compatible file uploads, and SSE chat streaming powered by an OpenAI-compatible LLM.
Vite + React 19 with Auth0 authentication, Tailwind CSS styling, LiveKit WebRTC voice, and Storybook component documentation.
Deepgram STT, ElevenLabs TTS, and Silero VAD compose a real-time voice pipeline that bridges LiveKit rooms to the backend chat API.
The repository is a monorepo with four primary workspaces and shared infrastructure configuration.
| Directory | Purpose |
|---|---|
backend/ |
Go API server and worker. Handles all HTTP endpoints, business logic, database access, file storage, and LLM integration. Uses Gin, goqu, pgx, and the Eino LLM framework. |
frontend/ |
React 19 SPA built with Vite. Auth0-protected dashboard, six-step onboarding, public page with voice/chat modes. Storybook for component docs. |
livekit-agent/ |
Python voice agent using LiveKit Agents SDK. Pulls the composed system prompt from the backend, drives Deepgram STT and ElevenLabs TTS directly, and exposes a search_knowledge function tool back to the LLM. Designed to be deployed to LiveKit Cloud in non-dev environments. |
knowledge-graph/ |
Python FastAPI service wrapping Graphiti. Builds and queries a per-user knowledge graph backed by Neo4j (graph), PostgreSQL (ingestion tracking / DLQ / audit), and MinIO (document storage). The backend talks to it over HTTP via KG_SERVICE_URL. |
mobile/ |
Expo + React Native app, including an on-device Storybook target. Early-stage; not part of the LiveKit / backend deployment loop. |
auth0/ |
Auth0 Post-Login Action (serverless JS). Provisions users in the backend on first login and caches the Ambasdr user ID in Auth0 app_metadata. |
docker-compose.yml |
Local infrastructure containers: PostgreSQL 16, Redis 7, Neo4j 5, MinIO (S3-compatible), OpenSearch 2, and the knowledge-graph FastAPI service. |
docs/ |
Design documents: authentication flow, architecture overview, LiveKit integration plan, and decision records. |
diorama-docs/ |
This documentation site. Docusaurus wrapper for browsing platform docs locally. |
Getting the full platform running locally requires Docker, Go, Node.js, and optionally Python 3.11+ for the voice agent. A tunneling service (ngrok) is needed for Auth0 integration.
Run make dev-up to start PostgreSQL, Redis, Neo4j, MinIO, and OpenSearch via Docker Compose. Health checks ensure all services are ready before proceeding.
Run make migrate-up to apply all schema migrations (15 as of this writing — users + onboarding, pages + documents + slug history, agent configs with focus / generated instructions / generation status, chat threads with channel + visitor role, KG ingestion tracking, page highlights, JSONB greeting messages, and billing fields).
Copy backend/.env.example to backend/.env and fill in: Auth0 domain and M2M secret, LLM API key, LiveKit credentials, Stripe (secret key + webhook secret + price ID), shared agent API key, and (if running the Graphiti sidecar) KG_SERVICE_URL. Frontend env vars are in frontend/.env — Auth0 SPA client ID, API URL, Stripe Payment Link, and Gemini key for the chat preview. Knowledge-graph env vars live in knowledge-graph/.env — Anthropic + OpenAI keys, plus the Neo4j / Postgres / MinIO connection settings.
Each engineer needs their own ngrok account and domain. The free tier provides a single static domain. Sign up at ngrok.com, retrieve your domain, then update the NGROK_PROVISION_DOMAIN in the Makefile (or create your own tunnel target). You must also update VITE_AUTH0_AUDIENCE in frontend/.env with your tunnel URL and register it as a callback URL in Auth0. Then run make ngrok-run to expose the local API. This is required for Auth0's Post-Login Action to reach the provisioning endpoint.
Run make run-api to start the Go API server on port 9080. It connects to all local infrastructure services automatically.
Run make frontend-install (first time), then make frontend-dev to start the Vite dev server on port 3003.
Run make kg-install (first time), then make kg-up to start the Graphiti FastAPI sidecar on port 8050 alongside its infra (Neo4j + KG Postgres DB + MinIO). The backend uses it to bake live KG context into generated agent prompts and to back the agent's search_knowledge function tool.
Run make agent-install (first time), then make agent-run to register the Python agent with LiveKit for voice sessions. Locally the agent registers against the LiveKit dev key; in staging/prod it's deployed to LiveKit Cloud via the lk CLI — see the deployment runbook.
Auth0's Post-Login Action runs in Auth0's cloud and must call the backend's POST /internal/users/provision endpoint. Without a public tunnel, authentication will succeed at Auth0 but the user won't be provisioned in the local database, causing 401 errors on all API calls.
The domain ambasdr-api.ngrok.app in the Makefile is specific to the project owner's ngrok account. Each engineer must create their own free ngrok account at ngrok.com, claim their static domain, and update three things: (1) the NGROK_PROVISION_DOMAIN variable in the Makefile, (2) VITE_AUTH0_AUDIENCE in frontend/.env with their tunnel URL, and (3) register the tunnel URL as an allowed callback in Auth0 using the Auth0 CLI.
Authentication uses Auth0 with Google as the only active social connection. The frontend UI shows Facebook and LinkedIn buttons, but those connections are not yet enabled in Auth0. The platform uses a Post-Login Action to provision users in the Ambasdr database on their first login.
Auth0 calls POST /internal/users/provision with the user's Auth0 subject, email, and avatar. The backend creates the user and returns a UUID. Auth0 caches this in app_metadata.ambasdr_user_id and injects it as a custom claim in the access token.
On subsequent logins, the cached ambasdr_user_id is read from app_metadata and injected into the token without calling the backend. This means returning users don't depend on backend availability during login.
Engineers should install the Auth0 CLI (auth0) and authenticate with auth0 login. This is needed for the make dev-reset and make dev-reset-user commands, which clear Auth0 app_metadata when resetting local state. The CLI is also used to manage callback URLs and Action secrets.
When you need a clean slate, the database and Auth0 caches must be reset together. Resetting only the database leaves stale user IDs in Auth0's app_metadata, causing 404 errors on login.
| Command | What it does |
|---|---|
make db-reset |
Drops all tables and re-runs migrations. Database only. Use this if you just need to clear data without touching Auth0. |
make dev-reset |
Runs db-reset, then clears app_metadata for all dev users via the Auth0 CLI. After this, log out and log back in to trigger a fresh provisioning call. |
make dev-reset-user EMAIL=user@example.com |
Clears app_metadata for a single Auth0 user. Useful when only one engineer needs to restart the onboarding flow without affecting others. |
Always log out of the frontend and log back in after a reset. The next login triggers the Auth0 Post-Login Action, which calls the provisioning endpoint and creates a fresh user in the database with a new UUID. Without re-logging, the frontend's cached access token still contains the old (now-deleted) user ID.
All local development tasks are managed through a root-level Makefile. Here are the key targets grouped by area.
| Target | Description |
|---|---|
dev-up / dev-down |
Start / stop Docker Compose services (PostgreSQL, Redis, Neo4j, MinIO, OpenSearch). |
migrate-up / migrate-down |
Run or rollback database migrations using golang-migrate. |
run-api |
Start the Go API server (go run cmd/api/main.go). |
run-worker |
Start the background worker for async tasks. |
build |
Compile both API and worker binaries to backend/bin/. |
test-unit |
Run Go unit tests (-tags unit). |
test-integration |
Run Go integration tests (-tags integration) against real containers (testcontainers). |
test-e2e |
Run Go end-to-end tests (-tags e2e). |
frontend-dev |
Start the Vite dev server with hot module replacement. |
run-storybook |
Start Storybook on port 6006 for component development. |
storybook-publish |
Publish Storybook to Chromatic using the token from frontend/.env. |
ngrok-run / ngrok-stop |
Start / stop the ngrok tunnel for Auth0 integration. |
agent-install |
Create Python venv and install LiveKit agent dependencies. |
agent-run |
Start the Python voice agent. |
kg-install |
Create Python venv and install Graphiti / knowledge-graph dependencies. |
kg-up / kg-down |
Start / stop the Graphiti FastAPI sidecar (port 8050) and its required infra containers. |
kg-reset |
Wipe the KG stores only — clears Neo4j, recreates the KG Postgres DB, empties the MinIO bucket. |
db-reset-full |
Run db-reset plus kg-reset so the app DB and KG stores reset together. |
check-services |
Verify every local dev process is up (containers, both Postgres DBs, backend API, Graphiti, frontend, voice agent, ngrok tunnel). |
docs-dev / docs-build |
Sync HTML and start (or build) the Docusaurus docs server (this site). |
Backend tests use testify suites with testcontainers for real PostgreSQL and MinIO instances. The database is never mocked. All tests run with build tags to separate unit, integration, and e2e concerns.
Tagged //go:build unit. Tests pure business logic without external dependencies. Run with make test-unit.
Tagged //go:build integration. Spins up real PostgreSQL and MinIO via testcontainers. Tests the full handler chain: HTTP request through router, service logic, repository, and database. Run with make test-integration.
Tagged //go:build e2e. Tests that require live external services (Auth0, LLM APIs). Run with make test-e2e.
Integration tests cover every HTTP endpoint with real request/response cycles. The test fixture (backend/tests/integration/fixtures.go) provides a shared TestFixture struct with repository, storage, and database clients. JWT helpers generate test tokens for authenticated requests.
Backend layers, frontend state management, LiveKit voice pipeline, Auth0 token flow, and how all components integrate.
The digest and rollup jobs behind every dashboard panel: what each value is computed from, how the time windows work, and why one eval run is not a measurement.
How a seeded demo page is built from an authored persona, why the seed writes conversations rather than panel data, and what a new UI surface owes the demo content.
The FastAPI sidecar that builds each user's knowledge graph: the Neo4j/Postgres/MinIO data stores, the ingestion pipeline, the HTTP API, and the Makefile commands.
All REST endpoints grouped by module, security schemes, request/response shapes, and SSE streaming protocol.
How the three-layer system prompt (personalization + operating contract + KG context) is composed and regenerated.
End-to-end runbook for hosting the platform on DigitalOcean (dev + prod) with the voice agent on LiveKit Cloud — Terraform provisioning, env vars, Caddy TLS + Cloudflare DNS, Auth0 / Stripe reconfiguration, and the CI/CD deploy pipeline.
Two lookup tables — one for prod, one for dev — covering the primary domain, the backend API base URL, the Auth0 tenant, the admin panel / Grafana / Portainer hostnames, the data stores, and the Stripe and CORS settings, each with the file or GitHub variable that defines it.
Every issue we hit during staging and every production-only concern we still need to address — consult before any DigitalOcean cutover so we don't repeat the trial-and-error.
The record of the public profile page redesign across web and mobile — workstreams, the chat experience, the add-contact vCard, and where the shipped code and decisions live.