![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
emiTMachine is a multi-user time tracking webapp for work sessions, tags, reports, TOTP, passkeys, recovery codes, and CSV history.
Activity history can be manually inserted, reviewed, edited, and deleted from the frontend. See doc/activity-management.md for the current default behavior and the planned admin-controlled permission model. Countdown behavior is documented in doc/countdowns.md.
The overtime/time-bank feature is documented in doc/overtime-bank.md. It is enabled per user by an admin, supports both overtime payment tracking and residual time-bank calculation, and lets users set their weekly target only once.
Root/admin behavior is documented in doc/admin-root.md.
- Username/password registration and login.
- Optional TOTP setup with QR code verification.
- Passkey registration/login flow with native WebAuthn ceremonies, persisted credential records, and challenge validation.
- Recovery codes for account recovery.
- Clock in/out workflow with editable client time confirmation.
- Tags with colors, including default
PresenceandSmart workingtags. - Daily, weekly, and monthly hour charts.
- CSV export and restore import.
- PostgreSQL database initialized from SQL, not backend startup code.
- Docker Compose stack for frontend, backend, and PostgreSQL.
- Reverse proxy deployment guides for Caddy and Nginx Proxy Manager.
docker compose up --buildServices:
- Frontend:
http://localhost:5173 - Backend API:
http://localhost:4000/api - PostgreSQL:
localhost:5432
The database is persisted in the postgres_data Docker volume. PostgreSQL schema initialization is mounted from backend/db/init.sql and runs when the database volume is first created.
postgres-backup writes a PostgreSQL dump with pg_dump every 8 hours to:
backups/postgres/emitmachine-latest.sql
Each run overwrites the previous backup atomically. The first dump is created as soon as PostgreSQL becomes healthy. Backup files are ignored by Git; only backups/postgres/.gitkeep is tracked so the host directory exists before Docker starts.
The backup container runs as ${UID:-1000}:${GID:-1000} so the generated file is writable by the host user on typical Linux deployments.
For a manual restore into a running local stack, use psql from the Postgres container:
docker compose exec -T postgres psql -U emitmachine -d emitmachine < backups/postgres/emitmachine-latest.sqlThe Compose file provides development defaults:
DATABASE_URL=postgres://emitmachine:emitmachine@postgres:5432/emitmachine
CORS_ORIGIN=http://localhost:5173
COOKIE_SECURE=false
LOG_LEVEL=info
LOG_FORMAT=pretty
RP_ID=localhost
RP_NAME=emiTMachine
TOTP_ENCRYPTION_KEY=replace-with-32-byte-base64-key
VITE_BACKEND_PROXY_TARGET=http://backend:4000
Logging defaults are intended for local development:
LOG_LEVEL: minimum backend log severity. Usedebugfor local troubleshooting,infofor normal development, andwarnorerrorto reduce noise.LOG_FORMAT: backend log format. Useprettyfor readable local logs andjsonwhen logs are collected by Docker, a reverse proxy, or a central logging system.
Change TOTP_ENCRYPTION_KEY, cookie settings, and database credentials for any non-local deployment. HTTPS and reverse proxy configuration are intentionally left for the deployment layer.
The repository includes two reverse proxy guides:
docker-reverse.md: Caddy-based deployment with manually provided TLS certificates.docker-reverse-npm.md: Nginx Proxy Manager deployment.
The Nginx Proxy Manager guide includes two Compose variants:
docker-compose-npm.yml: NPM with SQLite for NPM's own data.docker-compose-npm-advanced.yml: NPM with a dedicated MariaDB database for NPM's own data.
Both NPM variants keep emiTMachine on PostgreSQL. The NPM database is only for proxy hosts, certificates, NPM users, and NPM settings.
Passkeys require a secure browser context. Use one of these access patterns:
- Local development:
http://localhost:5173 - Remote server without HTTPS yet:
ssh -N -L 5173:localhost:5173 user@server, then openhttp://localhost:5173 - Production: HTTPS reverse proxy, with
RP_IDset to the public hostname andRP_ORIGINset to the exact browser origin
Do not open the app as http://<server-ip>:5173 for passkeys. Browsers reject WebAuthn on plain HTTP except for localhost.
Follow backend logs while using the app:
docker compose logs -f backendShow logs for all services:
docker compose logs -fShow recent PostgreSQL startup and migration logs:
docker compose logs --tail=100 postgresUse request ids to correlate browser, reverse proxy, and backend logs. Send an X-Request-Id header from a reverse proxy or API client, then search for the same value in backend logs. If no upstream request id is provided, the backend should generate one and include it in the response as X-Request-Id.
Common checks:
- Login or API calls fail: run
docker compose logs -f backendand look for the request method, path, status code, and request id. - The backend cannot connect to PostgreSQL: run
docker compose logs postgres backendand check for database health or authentication errors. - Logs are too noisy: set
LOG_LEVEL=warnindocker-compose.yml, then recreate the backend container withdocker compose up -d --build backend. - Structured log collection is needed: set
LOG_FORMAT=jsonand collect Docker stdout/stderr from the backend service.
More operational logging notes are in doc/troubleshooting.md.
This repository includes workspace agents for planning and implementing the project from todo.txt.
- Main coordination file:
AGENTS.md - Per-agent definitions:
.github/agents/ - Technical workflow notes:
doc/agentic-ai.md
Example prompts:
@ui/ux designer: Read todo.txt and propose the complete mobile-first page flow for emiTMachine.
@backend developer: Read todo.txt and list the required API endpoints, payloads, authorization requirements, and business rules.
@postgres db expert: Read todo.txt and design the PostgreSQL schema and init SQL for the application.







