8.8 KiB
Urmi environment configuration
This document tracks every environment variable, where it lives, and how it flows through local development and Docker.
Quick start
Docker Compose (recommended)
cp .env.example .env
# Edit .env — at minimum set AUTH_SECRET; add Google vars if using Google sign-in
docker compose up --build
Run services outside Docker
# Terminal 1 — Postgres must already be running (e.g. via compose)
cp backend/.env.example backend/.env
# Terminal 2
cd backend && pip install -r requirements.txt && uvicorn app.main:app --reload
# Terminal 3
cp frontend/.env.example frontend/.env
cd frontend && npm install && npm run dev
Env file locations
| File | Used by | Purpose |
|---|---|---|
.env (repo root) |
Docker Compose | Auth secrets + Google OAuth for the backend container |
.env.example (repo root) |
You | Template for Compose |
backend/.env |
FastAPI (local run) | Full backend config when not using Compose |
backend/.env.example |
You | Template for local backend |
frontend/.env |
Vite (local run) | Browser API URL |
frontend/.env.example |
You | Template for local frontend |
There is no committed .env file. Only .env.example templates are checked in. Copy the relevant example before running.
How variables flow
Docker Compose path
.env (repo root)
│
├─► docker-compose.yml ${VAR} substitution
│
└─► backend container environment
│
└─► pydantic Settings in backend/app/config.py
Compose loads the root .env for ${VAR} substitution in the compose file automatically. The backend service also mounts .env via env_file when the file exists (required: false — stack starts without it).
| Compose env var | Backend setting | Default if unset |
|---|---|---|
DATABASE_URL |
database_url |
postgresql+psycopg://urmi:urmi@postgres:5432/urmi |
FRONTEND_ORIGIN |
frontend_origin |
http://localhost:5173 |
AUTH_SECRET |
auth_secret |
urmi-local-development-secret-change-me |
AUTH_COOKIE_SECURE |
auth_cookie_secure |
false |
GOOGLE_CLIENT_ID |
google_client_id |
empty |
GOOGLE_CLIENT_SECRET |
google_client_secret |
empty |
GOOGLE_REDIRECT_URI |
google_redirect_uri |
http://localhost:8000/api/v1/auth/google/callback |
ULTRONSMS_BASE_URL |
ultronsms_base_url |
https://ultronsms.com |
ULTRONSMS_USER |
ultronsms_user |
empty |
ULTRONSMS_PASSWORD |
ultronsms_password |
empty |
Frontend in Compose:
| Compose env var | Used by | Default |
|---|---|---|
VITE_API_URL |
frontend/src/lib/api.ts |
http://localhost:8000 |
Postgres in Compose (not read by backend config today — fixed in compose):
| Compose env var | Value |
|---|---|
POSTGRES_DB |
urmi |
POSTGRES_USER |
urmi |
POSTGRES_PASSWORD |
urmi |
Host port mapping: Postgres is exposed on 5433 (not 5432) to avoid clashing with a local Postgres install.
Local backend path (no Docker for API)
backend/.env ──or── ../.env (repo root)
│
└─► pydantic Settings (backend/app/config.py)
When running from backend/:
uvicorn app.main:app --reload
Settings are loaded from environment variables. Pydantic also reads:
backend/.env../.env(repo root)
Important: Use host port 5433 in DATABASE_URL when Postgres runs via Compose but the API runs on the host:
DATABASE_URL=postgresql+psycopg://urmi:urmi@localhost:5433/urmi
Inside the backend container, use the internal service name and port 5432:
DATABASE_URL=postgresql+psycopg://urmi:urmi@postgres:5432/urmi
Local frontend path (no Docker for UI)
frontend/.env
│
└─► VITE_API_URL ──► import.meta.env.VITE_API_URL
Vite bakes VITE_* variables at dev/build time. Restart the dev server after changing frontend/.env.
Backend variables (reference)
Defined in backend/app/config.py.
| Variable | Required | Default | Notes |
|---|---|---|---|
APP_NAME |
No | Urmi API |
OpenAPI title |
ENVIRONMENT |
No | development |
Informational |
DATABASE_URL |
Yes* | localhost URL | *Required for real DB access |
FRONTEND_ORIGIN |
Yes | http://localhost:5173 |
CORS + OAuth redirect target |
AUTH_SECRET |
Yes in prod | weak dev default | Signs session JWT cookies |
AUTH_COOKIE_SECURE |
No | false |
Set true when served over HTTPS |
ACCESS_TOKEN_MINUTES |
No | 10080 (7 days) |
Session lifetime |
GOOGLE_CLIENT_ID |
For Google login | empty | OAuth client ID |
GOOGLE_CLIENT_SECRET |
For Google login | empty | OAuth client secret |
GOOGLE_REDIRECT_URI |
For Google login | localhost callback | Must match Google Console |
Pydantic accepts both SCREAMING_SNAKE env names and lowercase field names.
Frontend variables (reference)
| Variable | Required | Default | Notes |
|---|---|---|---|
VITE_API_URL |
No | http://localhost:8000 |
All API calls + Google OAuth start URL |
Authentication env checklist
Email / password only (works out of the box)
- Copy
.env.example→.envat repo root (Compose) orbackend/.env.example→backend/.env(local API) - Set a strong
AUTH_SECRETbefore any shared/staging deploy - Ensure
FRONTEND_ORIGINmatches the URL you open in the browser
Google sign-in
-
Create a Web application OAuth client in Google Cloud Console
-
Authorized redirect URI:
http://localhost:8000/api/v1/auth/google/callback -
Set in
.env/backend/.env:GOOGLE_CLIENT_ID=... GOOGLE_CLIENT_SECRET=... GOOGLE_REDIRECT_URI=http://localhost:8000/api/v1/auth/google/callback -
Restart backend after changing auth env vars
-
FRONTEND_ORIGINmust match where users land after OAuth (defaulthttp://localhost:5173)
If Google vars are empty, the Continue with Google button returns 503 Google sign-in is not configured.
Infrastructure services (Compose)
These are configured in docker-compose.yml today. The backend does not consume them yet — documented here for when they are wired.
| Service | Profile | Key env | Host ports |
|---|---|---|---|
| Postgres | core | POSTGRES_* |
5433 → 5432 |
| Redis | core | none | 6379 |
| Kafka | data-plane |
KAFKA_CFG_* |
9092 |
| ClickHouse | analytics |
none | 8123, 9000 |
| MinIO | object-storage |
MINIO_ROOT_USER, MINIO_ROOT_PASSWORD |
9001, 9002 |
Start optional profiles:
docker compose --profile data-plane --profile analytics --profile object-storage up
Planned backend env (not implemented yet)
| Variable | Purpose |
|---|---|
REDIS_URL |
Rate limits, OTP state, cache |
KAFKA_BOOTSTRAP_SERVERS |
Event bus |
CLICKHOUSE_URL |
Analytics ingest |
S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET |
Object storage (MinIO locally) |
Production notes
- Never commit
.env— only.env.exampletemplates. - Rotate
AUTH_SECRET— invalidates all sessions when changed. - Set
AUTH_COOKIE_SECURE=truebehind HTTPS. - Use strong Postgres credentials — replace compose defaults.
- Update
FRONTEND_ORIGINandGOOGLE_REDIRECT_URIfor your production domain. - Frontend build: pass
VITE_API_URLat build time for production API host.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
/api/v1/auth/me 401 after login |
Cookie not sent | Same-site: frontend and API origins must work with credentials: 'include'; check CORS FRONTEND_ORIGIN |
| Google button 503 | Missing OAuth vars | Set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET, restart backend |
| Google redirect error | Redirect URI mismatch | Match GOOGLE_REDIRECT_URI exactly in Google Console |
| Backend can't connect to DB (local API) | Wrong host/port | Use localhost:5433 when Postgres runs in Docker |
| Backend can't connect to DB (container) | Wrong host | Use postgres:5432, not localhost |
| Frontend calls wrong API | Stale Vite env | Set VITE_API_URL in frontend/.env, restart npm run dev |
Changes to root .env ignored |
Compose not restarted | docker compose up -d --build backend |
Maintenance log
| Date | Change |
|---|---|
| 2026-08-30 | Initial env doc; added backend/.env.example, frontend/.env.example; expanded root .env.example |
When adding new env-dependent features, update:
backend/app/config.py(or relevant service config)- Matching
.env.examplefile(s) docker-compose.ymlif Compose should pass the variable- This document