Architecture

How the Elmo monorepo is structured and how the pieces fit together.

Monorepo Structure

Elmo is a pnpm monorepo managed by Turborepo. The codebase is split into apps (deployable) and packages (shared libraries).

.
├── apps/
│   ├── web/          # Main dashboard (TanStack Start)
│   ├── worker/       # Background job runner (pg-boss)
│   ├── cli/          # @elmohq/cli npm package
│   └── www/          # Marketing site (this site)

├── packages/
│   ├── ui/           # Shared UI components (shadcn/ui)
│   ├── lib/          # Shared business logic, DB schema, AI providers
│   ├── config/       # Deployment configuration types
│   ├── deployment/   # Deployment mode resolution
│   ├── demo/         # Demo mode implementation
│   ├── local/        # Local development mode
│   ├── whitelabel/   # White-label mode
│   ├── og/           # Shared OG image generation
│   └── api-spec/     # OpenAPI specification

├── docker/           # Dockerfile (multi-stage)
├── e2e/              # End-to-end tests
├── biome.json        # Linting and formatting
├── turbo.json        # Task pipeline configuration
└── pnpm-workspace.yaml

Tech Stack

LayerTechnology
LanguageTypeScript 5.x
FrameworkTanStack Start (App Router, SSR)
StylingTailwind CSS v4
Componentsshadcn/ui (new-york style)
Data FetchingSWR
DatabasePostgreSQL with Drizzle ORM
Job Queuepg-boss (Postgres-based)
TestingVitest
LintingBiome
MonorepoTurborepo + pnpm workspaces

How the Apps Connect

┌─────────────┐       ┌──────────────┐
│   Web App   │──────▶│  PostgreSQL   │◀──────│   Worker    │
│  (TanStack) │       │  (Drizzle)   │       │  (pg-boss)  │
└─────────────┘       └──────────────┘       └─────────────┘
       │                                            │
       │              ┌──────────────┐              │
       └─────────────▶│   packages/  │◀─────────────┘
                      │   lib/       │
                      │   config/    │
                      │   ui/        │
                      └──────────────┘
  • The Web App serves the dashboard UI and the REST API (/api/v1)
  • The Worker processes background jobs — querying AI models, running evaluations
  • Both import shared code from packages/lib (database schema, AI provider config) and packages/config (deployment types)
  • The CLI generates Docker Compose configurations and manages the deployment lifecycle

Deployment Modes

Each deployment mode is implemented as a separate package in packages/:

PackageModeDescription
packages/locallocalSingle-org, email/password auth
packages/demodemoRead-only demonstration
packages/whitelabelwhitelabelMulti-org with Auth0 SSO

The packages/deployment package resolves the active mode at runtime based on DEPLOYMENT_MODE and provides the correct implementation.

Database

The database schema is defined with Drizzle ORM in packages/lib/src/db/. Key tables include:

  • brands — Brand profiles with name, website, domains, aliases
  • prompts — Tracking prompts associated with brands
  • evaluations — Results from querying AI models
  • citations — URLs cited by AI models in their responses

Migrations are generated with drizzle-kit generate and applied with drizzle-kit migrate.

Was this page helpful?