# 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) ```bash 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 ```bash # 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 ```text .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) ```text backend/.env ──or── ../.env (repo root) │ └─► pydantic Settings (backend/app/config.py) ``` When running from `backend/`: ```bash uvicorn app.main:app --reload ``` Settings are loaded from environment variables. Pydantic also reads: 1. `backend/.env` 2. `../.env` (repo root) **Important:** Use host port **5433** in `DATABASE_URL` when Postgres runs via Compose but the API runs on the host: ```text DATABASE_URL=postgresql+psycopg://urmi:urmi@localhost:5433/urmi ``` Inside the backend container, use the internal service name and port 5432: ```text DATABASE_URL=postgresql+psycopg://urmi:urmi@postgres:5432/urmi ``` ### Local frontend path (no Docker for UI) ```text 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` → `.env` at repo root (Compose) or `backend/.env.example` → `backend/.env` (local API) - [ ] Set a strong `AUTH_SECRET` before any shared/staging deploy - [ ] Ensure `FRONTEND_ORIGIN` matches the URL you open in the browser ### Google sign-in - [ ] Create a **Web application** OAuth client in [Google Cloud Console](https://console.cloud.google.com/apis/credentials) - [ ] Authorized redirect URI: ```text http://localhost:8000/api/v1/auth/google/callback ``` - [ ] Set in `.env` / `backend/.env`: ```text 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_ORIGIN` must match where users land after OAuth (default `http://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: ```bash 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 1. **Never commit `.env`** — only `.env.example` templates. 2. **Rotate `AUTH_SECRET`** — invalidates all sessions when changed. 3. **Set `AUTH_COOKIE_SECURE=true`** behind HTTPS. 4. **Use strong Postgres credentials** — replace compose defaults. 5. **Update `FRONTEND_ORIGIN` and `GOOGLE_REDIRECT_URI`** for your production domain. 6. **Frontend build:** pass `VITE_API_URL` at 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: 1. `backend/app/config.py` (or relevant service config) 2. Matching `.env.example` file(s) 3. `docker-compose.yml` if Compose should pass the variable 4. This document