Skip to content

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-tracker

Step 2 — Install dependencies

bash
pnpm install

This installs dependencies for all packages and services in the monorepo.

Step 3 — Start the infrastructure

bash
pnpm db:up

This starts three Docker services in the background:

ServicePurposeDefault port
postgresPrimary database (PostgreSQL 16)5432
redisJob queue broker (Redis 7)6379
rustfsFile 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 .env

Open .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 32

Paste 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:migrate

This 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:api

The API starts on http://localhost:3000. Swagger UI is available at http://localhost:3000/docs.

Terminal 2 — Worker:

bash
pnpm dev:worker

Terminal 3 — Frontend:

bash
pnpm dev:client

The frontend starts on http://localhost:5173.

Step 7 — Verify everything is working

  1. Open http://localhost:5173 in your browser
  2. You should see the login page
  3. Sign in with Google OAuth (requires GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET) or create a user directly via the Prisma Studio:
bash
pnpm db:studio

Prisma 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

TT Time Tracker — Internal Documentation