Caution
This entire project was built by Claude Code (Sonnet 4.6). Initiated, and then guided by human (me) prompting, a steady stream of “ah, and can you also…” and two evenings of iterative back and forth. Started from an empty folder, it evolved under its own self-authored guidance system (the agent memory living in docs/), to a working app with the only human-written content in these opening paragraphs.
Credit where it is due: impressive speed, clean UI, and a solid overall architecture. It even keeps its documentation up-to-date unprompted, in both the repository and the Wiki. That documentation however, rarely mentions “security” which is not an accident. The code relies on unvetted libraries, has not been pentested, and could theoretically exfiltrate your toothbrush for all I know. See SECURITY.md for the details.
A self-hosted personal work-timer PWA. Track time against named categories from any device, view weekly summaries, and copy them into Workday (or any time registration tool) with one click.
Runs as a PWA — installs to the macOS Dock and Android home screen with no app store required.
![]() Track — tap a category to start |
![]() Weekly — hours by category × day |
![]() Settings — categories & weekly goal |
- One-tap timer — tap a category to start, tap Stop to finish; starting a new category auto-stops the previous one
- Weekly goal — configurable hours per week (0–40); shown in the top bar and weekly summary, drives the rounding cap
- Weekly overview — time per category per day; click any cell to edit hours inline (totals update live as you type); export as CSV ready to paste into your time registration tool
- End-of-day rounding — round tracked minutes up to the nearest 30 or 60 minutes (configurable), capped at your weekly goal
- Light / dark / system theme — follows your OS preference by default; override per-device in Settings
- PWA — installable on macOS and Android, runs in standalone mode (no browser chrome)
- macOS status bar app — native Flutter app lives in the menu bar; icon shows active timer color +
CODE hh:mm; click to open a popover panel with full Track / Weekly / Settings functionality - Self-hosted — runs in Docker, no external services or accounts required beyond your own Authentik instance
| Layer | Choice |
|---|---|
| Frontend | React 18 + Vite + Tailwind CSS + shadcn/ui |
| Backend | Node.js 22 + Express + Drizzle ORM |
| Database | SQLite (better-sqlite3, WAL mode) |
| Auth | Authentik embedded outpost via Nginx Proxy Manager forward auth |
| Container | Docker Compose |
To deploy (production):
- Docker Engine 24+ with Docker Compose v2
- An Authentik instance (or another identity provider — see auth integration guide)
- Nginx Proxy Manager (or another reverse proxy with forward auth support)
- A domain name with SSL
To develop locally:
- Node.js 22+ — (nvm / fnm recommended for version management)
- Yarn 4 via Corepack (ships with Node.js 16.9+)
# 1. Install dependencies (requires Node 22+ and Yarn 4 via corepack)
corepack enable
yarn install
# 2. Start the backend (Terminal 1)
DEV_USER_ID=you@example.com yarn workspace @time-keeper/backend dev
# 3. Start the frontend (Terminal 2)
yarn workspace @time-keeper/frontend devOpen http://localhost:5173. Auth is bypassed in dev mode — all data is stored under the DEV_USER_ID value.
See docs/operations/deployment.md for the full guide, including:
- Docker Compose setup
- Nginx Proxy Manager configuration
- Authentik provider and outpost setup
The short version:
- Clone the repo on your VPS
docker compose up -d --build- Create a Proxy Provider in Authentik (forward auth mode, external host = your domain)
- Add it to your existing proxy outpost
- Add a proxy host in NPM pointing to
192.168.x.x:38521(your server's LAN IP) with the standard Authentik forward auth Advanced config
| Path | Contents |
|---|---|
| Wiki | Full user and operator documentation |
| AGENTS.md | Entry point for AI coding agents |
| docs/memory/INDEX.md | Architecture overview and session guide |
| docs/integration/auth.md | Authentik + NPM wiring |
| docs/integration/docker.md | Docker services and volumes |
| docs/integration/pwa.md | Installing on macOS and Android |
| docs/integration/api-subdomain.md | API subdomain setup for the native app |
| packages/macos_app/README.md | macOS status bar app — build & setup |
| docs/operations/deployment.md | Production deployment guide |
| docs/operations/runbooks.md | Common break/fix procedures |
| SECURITY.md | Security posture, risks, and dependency audit |
Categories are managed in the app itself (Settings tab). Add one category per booking type you want to track. The optional "Workday code" field appears in the weekly copy output.
The app is multi-user capable out of the box. Each user's data is fully isolated by the email address Authentik sets in the X-authentik-email header — no configuration required. Add users to your Authentik application and they each get their own independent set of categories and time entries.
There is no shared data, cross-user reporting, or admin interface — each user only ever sees their own data.
Original idea and product direction by the author. All code, architecture, and debugging by Claude Code (Claude Sonnet 4.5 / Opus 4.6, Anthropic).


