Backend Environment Variables
Set these in docker-compose.yml under the backend service, or in a .env file.
| Variable | Default | Description |
|---|---|---|
PORT | 3001 | Backend API port |
DATABASE_URL | — | PostgreSQL connection string (e.g., postgresql://tandemu:tandemu@postgres:5432/tandemu) |
REDIS_URL | — | Redis connection string (e.g., redis://redis:6379) |
CLICKHOUSE_URL | — | ClickHouse HTTP URL (e.g., http://clickhouse:8123) |
JWT_SECRET | change-me-in-production | Secret for signing JWT tokens. Change this in production. |
CORS_ORIGIN | http://localhost:3000 | Allowed CORS origin for the frontend |
STRIPE_SECRET_KEY | — | Stripe secret key (SaaS billing, optional) |
STRIPE_WEBHOOK_SECRET | — | Stripe webhook signing secret (optional) |
Frontend Environment Variables
| Variable | Default | Description |
|---|---|---|
NEXT_PUBLIC_API_URL | http://localhost:3001 | Backend API URL (accessed from the browser) |
OTel Collector Configuration
The collector config is at otel-collector.yaml in the repo root. It defines:
Receivers:
- OTLP gRPC on port 4317
- OTLP HTTP on port 4318
Processors:
memory_limiter— Prevents OOM (512 MiB limit)batch— Batches 10,000 records or 5s, whichever comes first
Exporters:
clickhouse— Writes to ClickHouse with auto-schema creationdebug— Logs basic info (useful for troubleshooting)
To modify the pipeline, edit otel-collector.yaml and restart the collector:
docker compose restart otel-collectorDatabase
PostgreSQL Schema
Tables are created by migration scripts in packages/database/src/migrations/:
| Migration | Creates |
|---|---|
0001_initial.sql | organizations, users, memberships tables + RLS policies |
0002_teams_and_invites.sql | teams, team_members, invites tables + RLS |
0003_integrations.sql | integrations, integration_project_mappings tables + RLS |
All tables use Row-Level Security (RLS) for tenant isolation. Every query is scoped to the current organization via SET LOCAL app.current_tenant.
ClickHouse Tables
Created automatically by the OTel Collector on first startup:
| Table | Data |
|---|---|
otel_traces | Session spans, deployment events |
otel_metrics_sum | Code line counters (AI vs manual) |
otel_logs | Friction events (prompt loops, errors) |
Data has a 90-day TTL by default.
Applying Migrations
Migrations are idempotent (safe to run multiple times):
docker exec -i tandemu-postgres-1 psql -U tandemu -d tandemu < packages/database/src/migrations/0001_initial.sql
docker exec -i tandemu-postgres-1 psql -U tandemu -d tandemu < packages/database/src/migrations/0002_teams_and_invites.sql
docker exec -i tandemu-postgres-1 psql -U tandemu -d tandemu < packages/database/src/migrations/0003_integrations.sqlSecurity Notes
- Change
JWT_SECRETin production — the default is not secure - API tokens for integrations are stored in PostgreSQL — consider encrypting at rest in production
- RLS ensures organization data isolation at the database level
- CORS is restricted to the configured origin
- Stripe webhooks use cryptographic signature verification
Last updated on