Appearance
Configure the Environment
TT Time Tracker uses a single environment file, .env, at the repo root. The NestJS API and BullMQ worker load it at runtime; the Vue frontend's VITE_* values are inlined into the client at build time.
Copy from the template:
bash
cp .env.example .envFrontend (VITE_*)
| Variable | Required | Default | Description |
|---|---|---|---|
VITE_APP_VERSION | No | 0.0.0 | Version string shown in the UI. |
The client talks to the API over a relative /api path (reverse-proxied to the NestJS service on the same origin), so there is no API-URL variable to set.
WARNING
VITE_* variables are inlined at build time. If you change them, you must rebuild the frontend. They are visible in the compiled JavaScript — do not put secrets here.
Backend
Required
| Variable | Description |
|---|---|
DATABASE_URL | PostgreSQL connection string, e.g. postgresql://tt:password@localhost:5432/tt?schema=public |
POSTGRES_PASSWORD | Password for the postgres Docker container (must match DATABASE_URL) |
REDIS_URL | Redis connection string, e.g. redis://localhost:6379 |
BETTER_AUTH_SECRET | Session signing secret. Generate with openssl rand -base64 32. Minimum 32 characters. |
BETTER_AUTH_URL | Public URL of the API, e.g. http://localhost:3000. Used for OAuth redirect URIs. |
RUSTFS_ACCESS_KEY | Access key for the S3-compatible file store. |
RUSTFS_SECRET_KEY | Secret key for the S3-compatible file store. |
Google OAuth (required for login)
| Variable | Description |
|---|---|
GOOGLE_CLIENT_ID | OAuth client ID from Google Cloud Console |
GOOGLE_CLIENT_SECRET | OAuth client secret |
Create credentials at console.cloud.google.com → APIs & Services → Credentials → Create OAuth 2.0 Client. Set the authorized redirect URI to {BETTER_AUTH_URL}/api/auth/callback/google.
File storage
| Variable | Default | Description |
|---|---|---|
RUSTFS_ENDPOINT | http://localhost:9000 | S3-compatible storage endpoint |
RUSTFS_BUCKET | tt-invoices | Bucket name for invoice files |
In production you can point this at AWS S3 or MinIO by changing RUSTFS_ENDPOINT and using the appropriate credentials.
AI invoice extraction
| Variable | Description |
|---|---|
OPENROUTER_KEY | OpenRouter API key for extracting structured data from invoices |
EXTRACTION_MODEL | Optional model override (default: google/gemini-2.5-flash) |
EXTRACTION_FALLBACK_MODEL | Optional fallback model (default: openai/gpt-5-mini) |
The key is required to run the worker — it refuses to boot without it. The API and client run fine without the worker; uploaded invoices then simply stay unprocessed until a worker is running.
(GOOGLE_APPLICATION_CREDENTIALS is not an app variable — it is only used by the one-off scripts/data-migration Firestore→Postgres tooling, which authenticates to Firebase via Google application-default credentials.)
Observability (optional)
All observability integrations are no-ops when their environment variables are unset — safe to skip in local development.
| Variable | Description |
|---|---|
SENTRY_DSN | Sentry DSN for backend (api + worker) error tracking |
SENTRY_DSN_FRONTEND | Sentry DSN for frontend error tracking (returned via /config) |