# Wotra — Working Time Tracker A self-hosted working time tracker with a Go backend and a Svelte PWA frontend. Offline-capable, single-binary deploy. ## Features - **Start / Stop** time tracking with an optional note. - **Close days**: merges all entries (worked_ms = sum of durations, breaks excluded). - **Mark days** as holiday, vacation, or sick (auto-credits expected daily hours). - **Close weeks**: computes overtime/undertime against a frozen snapshot of your expected hours. - **Settings history**: change hours/week with an `effective_from` date — past closed weeks are unaffected. - **PWA + offline**: works without a network connection; syncs via IndexedDB outbox when back online. - **CSV export**: entries, days, weeks. - **Midnight guard**: running entries are automatically stopped at 23:59:59 if they cross midnight. ## Quick Start ### Development ```bash # 1. Set your auth token export AUTH_TOKEN=mysecrettoken # 2. Start both servers make dev # Go API: http://localhost:8080 # Vite UI: http://localhost:5173 (with /api proxy) ``` Open `http://localhost:5173`, go to **Settings**, enter your token. ### Production (single binary) ```bash make build # builds web/ then embeds it in the Go binary # Run AUTH_TOKEN=mysecrettoken ./wotra # open http://localhost:8080 ``` ## Configuration (environment variables) | Variable | Default | Description | |-------------|-------------|----------------------------------------------| | `AUTH_TOKEN` | **required** | Bearer token for API access | | `PORT` | `8080` | HTTP port | | `DB_PATH` | `wotra.db` | SQLite database file path | | `TZ` | `UTC` | Timezone for day/week key calculation | ## API Reference All API endpoints require `Authorization: Bearer ` except `/healthz`. ### Entries | Method | Path | Description | |--------|-----------------------------|--------------------------| | POST | `/api/entries/start` | Start tracking | | POST | `/api/entries/{id}/stop` | Stop a specific entry | | GET | `/api/entries?from=&to=` | List entries by date | | PUT | `/api/entries/{id}` | Edit start/end/note | | DELETE | `/api/entries/{id}` | Soft-delete an entry | ### Days | Method | Path | Description | |--------|-------------------------------|--------------------------------------| | GET | `/api/days?from=&to=` | List closed days | | POST | `/api/days/{day}/close` | Close a day (merge entries) | | POST | `/api/days/{day}/mark` | Mark as holiday/vacation/sick | | DELETE | `/api/days/{day}/close` | Reopen a closed day | ### Weeks | Method | Path | Description | |--------|-------------------------------|--------------------------------------| | GET | `/api/weeks?from=&to=` | List closed weeks | | POST | `/api/weeks/{week}/close` | Close a week (compute overtime) | | DELETE | `/api/weeks/{week}/close` | Reopen a closed week | Week key format: `YYYY-Www` (e.g. `2024-W03`). ### Settings | Method | Path | Description | |--------|-------------------------|------------------------------------| | GET | `/api/settings` | Current effective settings | | PUT | `/api/settings` | Add a new settings version | | GET | `/api/settings/history` | All settings history | ### Export | Method | Path | Description | |--------|------------------------------|--------------------------| | GET | `/api/export/entries.csv` | Export entries as CSV | | GET | `/api/export/days.csv` | Export days as CSV | | GET | `/api/export/weeks.csv` | Export weeks as CSV | ### Sync | Method | Path | Description | |--------|-------------------|-------------------------------------| | POST | `/api/sync/pull` | Pull changes since a version | | POST | `/api/sync/push` | Push local changes (advisory) | ### Health | Method | Path | Description | |--------|-------------|--------------------------| | GET | `/healthz` | Unauthenticated health | ## Architecture ``` ┌─────────────────────────┐ ┌──────────────────────────┐ │ Svelte PWA (client) │ ◄─────► │ Go service (API) │ │ - IndexedDB (Dexie) │ HTTPS │ - REST/JSON endpoints │ │ - Service Worker │ JSON │ - Business logic │ │ - Sync outbox │ │ - SQLite (modernc) │ └─────────────────────────┘ └──────────────────────────┘ ``` See [PLAN.md](PLAN.md) for the full design document. ## Development Notes - **Go module**: `github.com/wotra/wotra` - **SQLite driver**: `modernc.org/sqlite` (pure Go, no CGO) - **Day boundary**: entries must not cross midnight; the server auto-stops any running entry at 23:59:59 local time. - **Settings history**: `effective_from` lets you change hours/week without rewriting past closed weeks. - **Overtime**: stored as a signed `delta_ms` on each `closed_weeks` row. Frozen at close time.