Free, offline-first, browser-based time tracker and invoice generator. No account. No cloud. No subscription. All data stays on the user's device.
Check the webapp on https://tickkeep.mamoonalshamali.workers.dev
Tagline: Free. Offline. No sign-up.
npm install
npm run dev # local development
npm run build # production build → dist/
npm run preview # serve the production build locally
localStorage (debounced writes, quota-safe compaction, migration-proof merge on load, legacy timevault-v1 key auto-migrated)#/app/...) — works on any static host with zero rewrite rulesSKIP_WAITING update handshake; user data is never in the SW cachetickkeep-backup.json) moved between devices via the File System Access API (a Google Drive / OneDrive desktop-sync folder, or any local folder); conflict-safe pull that never overwrites without asking, plus optional scheduled auto-backup — no relay server#/app/tests) — 50+ cases including a 1000-client / 1000-project / 1000-invoice / 100-teammate stress run; snapshots and restores your data, survives mid-run navigationOpen the app → sidebar → System → Test bench → Run all.
The bench drives the real UI (clicks, typing, shortcuts, file imports), streams a log, times every case, and is safe on live data. It survives mid-run navigation and always returns you to the results.
Playwright specs live in tests/e2e/ (config in playwright.config.ts, chromium + mobile projects):
multi-tab.spec.ts — two tabs share storage; a timer started in one tab bills exactly once; writes propagate live.pdf.spec.ts — cold-start UI flow (client → project → entry → wizard) ending in a real INV-xxxx.pdf download.Run: npm run build, npm run preview, then npx playwright test.
npm run build · Output directory: dist.Same repo → Add New Project → framework Vite → build npm run build, output dist. Add the domain in project settings.
Both are free tiers; both serve the service worker and hash routes correctly with no extra config.
src/
lib/ store (persist, merge-safe migrations), invoice engine + PDF,
reports aggregation, collab merge, sync transports, undo stack,
platform services (rates, chime, feature flags), e2e engine
components/ ui kit, charts, icons
app/ pages: dashboard, timer/entries, calendar, projects, clients,
invoices, expenses, estimates, reports (+ builder), year review,
sync, import, settings, tests, legal, landing, shell
public/ manifest, sw.js, icons, robots, sitemap, og-image
tickkeep-backup.json; merges union adds, apply last-write-wins per record with a deterministic content-hash tiebreak (so all devices converge), propagate deletes via tombstones, and take the max invoice number. Rejected: event-sourced device logs (more moving parts for a 1–5 person audience; the single file is inspectable, trivially restorable, and already stress-tested at 1000×1000 scale) and CRDTs (binary, hard to debug, overkill). Revisit if multi-writer conflicts become frequent in the wild.canvas.measureText, no html2canvas screenshot pass, so output is byte-stable across browsers. Code-split — the ~130 KB gzip engine loads only when a PDF is generated. Rejected: pdfmake (adds a VFS font blob to the bundle for marginal gains at our three fixed templates).activeTimer.startedAt is an absolute timestamp written on punch-in; elapsed is always Date.now() − startedAt. Immune to tab throttling, sleep, crash, and restart; a 24h guard confirms runaway timers before saving.navigator.storage.persist() on boot, quota/usage estimation, a risk-graded banner with one-click export, folder auto-backup on an interval, receipt compression to ≤200 KB, and quota-safe persistence that strips base64 blobs before failing. Eviction is treated as probable, not possible.tickkeep-collab channel carries ledger-changed pings when team mode is on, and the bench verifies a timer started in one tab bills exactly once.Proprietary — TickKeep End-User License Agreement (EULA). All Rights Reserved. See LICENSE.
14 commits
6 commits
TypeScript
98.2%
CSS
1.0%
Free, offline-first, browser-based time tracker and invoice generator. No account. No cloud. No subscription. All data stays on the user's device.
Check the webapp on https://tickkeep.mamoonalshamali.workers.dev
Tagline: Free. Offline. No sign-up.
npm install
npm run dev # local development
npm run build # production build → dist/
npm run preview # serve the production build locally
localStorage (debounced writes, quota-safe compaction, migration-proof merge on load, legacy timevault-v1 key auto-migrated)#/app/...) — works on any static host with zero rewrite rulesSKIP_WAITING update handshake; user data is never in the SW cachetickkeep-backup.json) moved between devices via the File System Access API (a Google Drive / OneDrive desktop-sync folder, or any local folder); conflict-safe pull that never overwrites without asking, plus optional scheduled auto-backup — no relay server#/app/tests) — 50+ cases including a 1000-client / 1000-project / 1000-invoice / 100-teammate stress run; snapshots and restores your data, survives mid-run navigationOpen the app → sidebar → System → Test bench → Run all.
The bench drives the real UI (clicks, typing, shortcuts, file imports), streams a log, times every case, and is safe on live data. It survives mid-run navigation and always returns you to the results.
Playwright specs live in tests/e2e/ (config in playwright.config.ts, chromium + mobile projects):
multi-tab.spec.ts — two tabs share storage; a timer started in one tab bills exactly once; writes propagate live.pdf.spec.ts — cold-start UI flow (client → project → entry → wizard) ending in a real INV-xxxx.pdf download.Run: npm run build, npm run preview, then npx playwright test.
npm run build · Output directory: dist.Same repo → Add New Project → framework Vite → build npm run build, output dist. Add the domain in project settings.
Both are free tiers; both serve the service worker and hash routes correctly with no extra config.
src/
lib/ store (persist, merge-safe migrations), invoice engine + PDF,
reports aggregation, collab merge, sync transports, undo stack,
platform services (rates, chime, feature flags), e2e engine
components/ ui kit, charts, icons
app/ pages: dashboard, timer/entries, calendar, projects, clients,
invoices, expenses, estimates, reports (+ builder), year review,
sync, import, settings, tests, legal, landing, shell
public/ manifest, sw.js, icons, robots, sitemap, og-image
tickkeep-backup.json; merges union adds, apply last-write-wins per record with a deterministic content-hash tiebreak (so all devices converge), propagate deletes via tombstones, and take the max invoice number. Rejected: event-sourced device logs (more moving parts for a 1–5 person audience; the single file is inspectable, trivially restorable, and already stress-tested at 1000×1000 scale) and CRDTs (binary, hard to debug, overkill). Revisit if multi-writer conflicts become frequent in the wild.canvas.measureText, no html2canvas screenshot pass, so output is byte-stable across browsers. Code-split — the ~130 KB gzip engine loads only when a PDF is generated. Rejected: pdfmake (adds a VFS font blob to the bundle for marginal gains at our three fixed templates).activeTimer.startedAt is an absolute timestamp written on punch-in; elapsed is always Date.now() − startedAt. Immune to tab throttling, sleep, crash, and restart; a 24h guard confirms runaway timers before saving.navigator.storage.persist() on boot, quota/usage estimation, a risk-graded banner with one-click export, folder auto-backup on an interval, receipt compression to ≤200 KB, and quota-safe persistence that strips base64 blobs before failing. Eviction is treated as probable, not possible.tickkeep-collab channel carries ledger-changed pings when team mode is on, and the bench verifies a timer started in one tab bills exactly once.Proprietary — TickKeep End-User License Agreement (EULA). All Rights Reserved. See LICENSE.
14 commits
6 commits
TypeScript
98.2%
CSS
1.0%