47dd2c97791e478d45f2d4d276d5836e7d0972f8
Settings configured mid-week (e.g. Thursday) have an effective_from of that date. CloseWeek was looking up settings as-of Monday, which predates the new settings row and fell back to the old default. Now uses today's date for the settings lookup, so any settings change made before closing the week is correctly reflected in expected_ms.
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_fromdate — 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
Tool versions are declared in mise.toml. Install mise and run mise install once to get the correct Go and Node versions.
Development
# Install frontend dependencies (first time only)
mise run install
# Start both servers (Go API + Vite dev server)
mise run dev
# Go API: http://localhost:8080
# Vite UI: http://localhost:5173 (with /api proxy)
AUTH_TOKEN defaults to devtoken in mise.toml. Override it by setting the variable in your environment before running.
Open http://localhost:5173, go to Settings, enter your token.
Production (single binary)
mise run build # builds web/ then embeds it in the Go binary
AUTH_TOKEN=mysecrettoken ./wotra
# open http://localhost:8080
All tasks
| Task | Description |
|---|---|
mise run build |
Build production binary (web + Go) |
mise run build:web |
Build Svelte frontend only |
mise run build:go |
Build Go binary only |
mise run dev |
Start API + UI dev servers concurrently |
mise run dev:api |
Start Go API server only |
mise run dev:ui |
Start Vite dev server only |
mise run test |
Run all Go tests |
mise run install |
Install frontend npm dependencies |
mise run clean |
Remove build artifacts |
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 <token> 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 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_fromlets you change hours/week without rewriting past closed weeks. - Overtime: stored as a signed
delta_mson eachclosed_weeksrow. Frozen at close time.
Description
Languages
Go
56.8%
Svelte
28.4%
TypeScript
14%
Dockerfile
0.5%
JavaScript
0.2%
Other
0.1%