STT is a mobile-first time tracking PWA (Progressive Web App) for tracking work time and breaks.
It is built as a small, self-hostable stack:
- Backend: FastAPI + SQLAlchemy + SQLite (+ Alembic migrations)
- Frontend: Vite + React +
vite-plugin-pwa
- Clock events: COME / GO / BREAK_START / BREAK_END
- Dashboard: live status (OFF/WORKING/BREAK), worked/break totals, remaining targets
- History: recent entries (default: last 7 days) with edit/delete
- Reports: weekly and monthly reports with navigation (jump/prev/next)
- Absences: CRUD absences and absence reasons
- Notes: day notes visible in the monthly heatmap
- Multi-language UI: English + German
- Offline-friendly: PWA installable
- (Optional) Web Push notifications: per-user thresholds for work/break minutes
apps/api: FastAPI backendapps/web: Vite + React frontend
- Python 3.11+ (backend)
- Node.js 18+ (frontend)
uvfor Python dependency management
cd apps/api
# create/update local sqlite db
uv run alembic upgrade head
# start API
uv run uvicorn app.main:app --reloadThe API will run on http://localhost:8000.
Copy and edit apps/api/.env.example → apps/api/.env.
Important variables:
TT_BASE_URL(frontend origin for CORS, e.g.http://localhost:5173)TT_SQLITE_PATH(SQLite file path, default./data/app.db)TT_JWT_SECRET_KEY(change in production)
cd apps/web
npm install
# configure API base url
cp .env.example .env
npm run devThe frontend will run on http://localhost:5173.
apps/web/.env:
VITE_API_BASE_URL=http://localhost:8000STT supports real Web Push notifications (delivered even when the PWA is closed) with per-user threshold lists:
- “Work thresholds (minutes)” → e.g.
30, 60, 120 - “Break thresholds (minutes)” → e.g.
10, 20, 30
When a threshold is reached, the backend worker sends a push message like:
- “You have worked X minutes so far.”
- “You have taken X minutes break so far.”
Generate VAPID keys (example using py-vapid):
cd apps/api
uv run python -c "from py_vapid import Vapid; v=Vapid(); v.generate_keys(); print(v.public_key); print(v.private_key)"Add them to apps/api/.env:
TT_VAPID_PUBLIC_KEY=...
TT_VAPID_PRIVATE_KEY=...
TT_VAPID_SUBJECT=mailto:admin@example.comThe push sender runs as a separate process:
cd apps/api
uv run python -m app.push_workerOpen Settings → Push notifications and click Enable push.
Note:
- Web Push typically requires HTTPS (or
localhost). - iOS Safari has limitations; Chrome/Edge on desktop works best for testing.
- Backend:
apps/api/README.md - Frontend:
apps/web/README.md
This repository includes a docker-compose.yml that starts:
web(nginx serving the built PWA)api(FastAPI backend)push-worker(optional, sends Web Push notifications)
Copy the example file and adjust values as needed:
cp .env.docker.example .envNotes:
- All backend settings that are normally read from
apps/api/.envcan be supplied via Docker environment variables. - SQLite is stored in a named Docker volume (
stt-data).
docker compose up --buildThen open:
- Web UI: http://localhost:5173
- API: http://localhost:8000
To enable Web Push, set the VAPID variables in .env (docker compose env file):
TT_VAPID_PUBLIC_KEY=...
TT_VAPID_PRIVATE_KEY=...
TT_VAPID_SUBJECT=mailto:admin@example.comThen start the optional worker profile:
docker compose --profile push up --buildThe push-worker service uses the same env vars and the same SQLite database volume.
STT includes an email-based password reset flow:
- Login page → “Forgot password?”
- Request reset link via email
- Open link and set a new password
Backend configuration (environment variables):
TT_PUBLIC_APP_URL(required): Base URL of the web app, used to build the reset linkTT_SMTP_HOST/TT_SMTP_PORT/TT_SMTP_FROM(required)TT_SMTP_USER/TT_SMTP_PASSWORD(optional auth)TT_SMTP_STARTTLS(optional, default false)TT_SMTP_USE_TLS(optional SMTPS, default false)
Notes:
- Default is plain SMTP (no TLS). Enable STARTTLS/SMTPS via flags if needed.
- If
TT_SMTP_USERis set,TT_SMTP_PASSWORDmust also be set.