Time Tracker
A browser-based time-tracking app: log daily work against projects, review totals in weekly and monthly views, and track project budgets with automatic cost calculation and soft breach warnings.
Stack: React 19 + Vite 6 (TypeScript strict) — Spring Boot 3.4 (Java 21) — PostgreSQL 17 via Docker Compose — Flyway for schema migrations — Tailwind CSS v4 — Biome 1.9 — Vitest.
AI disclosure: Code in this application was written with the help of AI agents. Architecture decisions were still driven by the creator of this project, with agent engineering used to steer implementation.
Features
- Daily time entries — date, project, duration (entered as h:mm), automatic cost from hourly rate; entries can be created, edited, and deleted
- Weekly view — navigate by ISO week; see total hours per day, individual entries, and a running week total
- Monthly view — per-project summary with time and cost progress bars; red banner when a budget is exceeded
- Project management — create and edit projects with time and cost budgets; set a project-level hourly rate or fall back to the user's default
- Multi-user — pick any seeded user from the dropdown and edit that user's name/default rate; cost is calculated using that user's rate when no project rate is set
- Soft budget enforcement — entries always save; over-budget projects are highlighted with a warning banner and colored bars
Quick start
Requires a full Java 21 JDK (not just a JRE) for Maven compilation.
mise installbelow handles this and setsJAVA_HOMEwhen commands are run throughmise. Without mise:sudo apt install openjdk-21-jdk, then ensurejava -versionreports 21 andJAVA_HOMEpoints at that JDK.
# 1. Pin toolchain — installs Java 21 JDK, Node 22, Maven, lefthook, gitleaks
mise install
# 2. Install deps, git hooks, .env, and validate Java + Maven wrapper
mise run setup
# 3. Start the database
docker compose up -d
Open two terminals:
# Backend → http://localhost:8080
mise run backend
# Frontend → http://localhost:5173 (proxies /api → :8080)
mise run frontend
If you have activated mise in your shell, the direct commands also work:
backend/mvnw -f backend/pom.xml spring-boot:run and cd frontend && npm run dev.
Docker (all-in-one app + database)
Build and run the bundled app container plus PostgreSQL:
docker compose -f docker-compose.full.yml up --build
- App: http://localhost:8080
- API: http://localhost:8080/api
- Database: postgres://app:app@localhost:5432/app_dev
Verify everything
mise run check # format-check + lint + test (both stacks)
Without mise:
# one-time setup
sudo apt install openjdk-21-jdk docker-compose-plugin
# Install Node 22 with your preferred Node version manager or distro-specific package.
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 # adjust if your JDK is elsewhere
npm --prefix frontend install
cp -n .env.example .env
backend/mvnw -f backend/pom.xml -v # primes the Maven wrapper cache
# checks
backend/mvnw -f backend/pom.xml spotless:check -q
cd frontend && npx biome check src
backend/mvnw -f backend/pom.xml test -q
cd frontend && npx vitest run
Design notes
Money and duration are stored as integers (cents and minutes respectively) to avoid floating-point
drift. Cost for a time entry is computed at read time: duration_minutes × effective_rate_cents / 60,
where the effective rate is the project's hourly_rate_cents if set, otherwise the user's
default_hourly_rate_cents. This means changing a rate retroactively updates all historical cost
totals — a deliberate trade-off for simplicity (see NEXT_STEPS.md for a snapshot-based alternative).
Budget warnings are soft: any entry saves regardless of budget status. Breach is detected in the
reporting layer by comparing aggregated totals to the project's time_budget_minutes and
cost_budget_cents. The monthly view renders a red warning banner and saturated progress bars for
any over-budget project.
Schema migrations are managed exclusively by Flyway (V1__init.sql for schema, V2__seed_demo_data.sql
for demo users and projects). Hibernate is set to validate — it never modifies the schema.
API shape — aggregation is done server-side via two dedicated endpoints:
GET /api/reports/weekly?userId=&week=YYYY-Www and GET /api/reports/monthly?userId=&month=YYYY-MM.
Resource endpoints live under /api/: users can be listed and updated, projects can be listed,
created, and updated, and time entries can be listed by date range, created, updated, and deleted.
Environment
.env.example documents all env vars. mise run setup copies it to .env automatically on first run.
Troubleshooting
backend/mvnw: ... exec: .../apache-maven-3.9.9/bin/mvn: not found— runmise run setupagain. The setup task primes the Maven wrapper cache. If it still fails, remove the broken cache withrm -rf ~/.m2/wrapper/dists/apache-maven-3.9.9*and rerunmise run setup.JAVA_HOME environment variable is not defined correctly— install a Java 21 JDK and setJAVA_HOME, or use the mise tasks (mise run backend,mise run check) aftermise install.