Appearance
Local Development Setup
This tutorial walks you through getting the full TT Time Tracker stack running on your machine. By the end you will have:
- PostgreSQL, Redis, and RustFS running in Docker
- The NestJS API running with hot-reload on port 3000
- The BullMQ worker running in the background
- The Vue SPA running with hot-reload on port 5173
Prerequisites
Before you start, make sure you have:
- Node.js 20+ — check with
node -v - pnpm 10+ — install with
npm install -g pnpm@latest - Docker + Docker Compose — check with
docker compose version
Step 1 — Clone the repository
bash
git clone <repository-url> tt-time-tracker
cd tt-time-trackerStep 2 — Install dependencies
bash
pnpm installThis installs dependencies for all packages and services in the monorepo.
Step 3 — Start the infrastructure
bash
pnpm db:upThis starts three Docker services in the background:
| Service | Purpose | Default port |
|---|---|---|
postgres | Primary database (PostgreSQL 16) | 5432 |
redis | Job queue broker (Redis 7) | 6379 |
rustfs | File storage for invoices (S3-compatible) | 9000 (API), 9001 (console) |
Wait a few seconds for the health checks to pass. You can verify they are running with docker compose ps.
Step 4 — Configure the environment
Copy the example environment files:
bash
cp .env.backend.example .env.backend
cp .env.example .envOpen .env.backend and set the required values. For local development the defaults work, but you must set a BETTER_AUTH_SECRET:
bash
# Generate a secure secret
openssl rand -base64 32Paste the output as the value of BETTER_AUTH_SECRET in .env.backend.
Optional: AI-powered invoice OCR
To use the invoice OCR feature locally, set OPENAI_KEY and GOOGLE_APPLICATION_CREDENTIALS in .env.backend. The app works without them — invoices will stay in a pending state instead of being auto-processed.
Step 5 — Run database migrations
bash
pnpm db:migrateThis applies all Prisma migrations against the local PostgreSQL instance and generates the Prisma client.
Step 6 — Start the services
Open three terminal windows and run one command in each:
Terminal 1 — API:
bash
pnpm dev:apiThe API starts on http://localhost:3000. Swagger UI is available at http://localhost:3000/docs.
Terminal 2 — Worker:
bash
pnpm dev:workerTerminal 3 — Frontend:
bash
pnpm dev:clientThe frontend starts on http://localhost:5173.
Step 7 — Verify everything is working
- Open http://localhost:5173 in your browser
- You should see the login page
- Sign in with Google OAuth (requires
GOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRET) or create a user directly via the Prisma Studio:
bash
pnpm db:studioPrisma Studio opens at http://localhost:5555 where you can inspect and insert records directly.
Troubleshooting
pnpm db:migrate fails with "Connection refused" The PostgreSQL container is not ready yet. Wait 5–10 seconds and try again, or check docker compose ps to confirm the postgres service is healthy.
API fails to start with "Invalid AUTH_SECRET"BETTER_AUTH_SECRET must be at least 32 characters. Re-run openssl rand -base64 32 and update .env.backend.
Port conflict on 5432/6379 You may already have a local PostgreSQL or Redis instance running. Either stop them, or change the host ports in docker-compose.yaml and update the connection strings in .env.backend.
Next steps
- Read Build Your First Feature to learn the full development loop
- Browse the Reference section for schema, routes, and environment variable details