{"id":50972865,"url":"https://github.com/madebyaris/time-tracker-freelance","last_synced_at":"2026-06-19T04:02:07.021Z","repository":{"id":353545527,"uuid":"1219682899","full_name":"madebyaris/time-tracker-freelance","owner":"madebyaris","description":"Local-first time tracker for indie freelancers with macOS desktop app, invoices, reports, optional sync, and a private Cloudflare web dashboard.","archived":false,"fork":false,"pushed_at":"2026-05-12T02:53:02.000Z","size":2304,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-12T04:34:53.022Z","etag":null,"topics":["billing","cloudflare-workers","d1","desktop-app","freelancer-tools","invoices","invoicing","local-first","macos","offline-first","privacy-focused","productivity","react","self-hosted","sqlite","tauri","time-tracker","time-tracking","timetracking","typescript"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/madebyaris.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-24T05:51:05.000Z","updated_at":"2026-05-12T02:53:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/madebyaris/time-tracker-freelance","commit_stats":null,"previous_names":["madebyaris/time-tracker-freelance"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/madebyaris/time-tracker-freelance","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madebyaris%2Ftime-tracker-freelance","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madebyaris%2Ftime-tracker-freelance/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madebyaris%2Ftime-tracker-freelance/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madebyaris%2Ftime-tracker-freelance/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/madebyaris","download_url":"https://codeload.github.com/madebyaris/time-tracker-freelance/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madebyaris%2Ftime-tracker-freelance/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34516549,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-19T02:00:06.005Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["billing","cloudflare-workers","d1","desktop-app","freelancer-tools","invoices","invoicing","local-first","macos","offline-first","privacy-focused","productivity","react","self-hosted","sqlite","tauri","time-tracker","time-tracking","timetracking","typescript"],"created_at":"2026-06-19T04:02:06.259Z","updated_at":"2026-06-19T04:02:07.014Z","avatar_url":"https://github.com/madebyaris.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/readme/hero.svg\" alt=\"Tickr hero banner\" width=\"100%\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"specs/active/ttf-002/feature-brief.md\"\u003e\u003cimg src=\"https://img.shields.io/badge/status-ttf--002%20shipped-18c37e?style=flat-square\" alt=\"ttf-002 shipped\" /\u003e\u003c/a\u003e\n  \u003ca href=\"specs/active/ttf-004/feature-brief.md\"\u003e\u003cimg src=\"https://img.shields.io/badge/deploy-Cloudflare%20shipped-18c37e?style=flat-square\" alt=\"Cloudflare deploy shipped\" /\u003e\u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/platform-macOS%20first-111827?style=flat-square\" alt=\"macOS first\" /\u003e\n  \u003cimg src=\"https://img.shields.io/badge/offline-local%20first-0f766e?style=flat-square\" alt=\"Local first\" /\u003e\n  \u003cimg src=\"https://img.shields.io/badge/stack-Tauri%202%20%2B%20React%20%2B%20Rust-1d4ed8?style=flat-square\" alt=\"Tauri React Rust\" /\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eTickr\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  A local-first time tracker for indie freelancers on macOS.\n\u003c/p\u003e\n\nTickr helps freelancers track time, manage clients/projects, prepare invoices, and optionally sync data to a private web dashboard.\n\nYou can use it in two ways:\n\n- **Offline desktop app**: best if you only need Tickr on one Mac.\n- **Private hosted dashboard**: best if you want browser access and desktop sync.\n\nThe easiest hosted setup is **Cloudflare Workers + D1**. VPS support is available as a manual Node/Postgres path, but it is not yet packaged as a one-command production installer.\n\n## What Tickr Does\n\n- Track time with a native macOS app.\n- Start timers from a quick panel with global shortcuts.\n- Pause and resume without losing accurate billable time.\n- Manage clients, projects, tasks, reports, and invoices.\n- Add client logos, addresses, tax IDs, websites, phone numbers, and rates.\n- Export CSV data.\n- Generate branded PDF invoices with your logo, address, tax ID, signature, and payment instructions.\n- Sync to a private API and view the same data in a web dashboard.\n\n## Pick Your Setup\n\n### Option 1: Offline Mac App\n\nChoose this if you only want to track time on your Mac.\n\nYou do **not** need an account, server, Cloudflare, VPS, or database. Your data stays local on your computer.\n\n### Option 2: Cloudflare Web Dashboard\n\nChoose this if you want:\n\n- A private website for your dashboard.\n- Desktop sync.\n- No VPS maintenance.\n- A simpler future deployment path.\n\nThis is the recommended hosted setup.\n\n### Option 3: VPS / Self-Hosted Server\n\nChoose this only if you specifically want to run your own Linux server.\n\nCurrent VPS support is a manual Node.js API + Postgres setup. It works as a self-host path, but it does not yet include a polished Docker/Nginx/Caddy production bundle.\n\n## Before You Start\n\n### Prerequisites\n\n- Node.js 20+\n- pnpm 10+\n- Rust stable, only if you want to run or build the desktop app from source.\n- Docker, only if you want local Postgres or VPS-style self-hosting.\n- A Cloudflare account, only if you want the recommended hosted dashboard.\n\nInstall project dependencies:\n\n```bash\npnpm install\n```\n\n## Use Tickr Offline\n\nRun the desktop app:\n\n```bash\npnpm desktop\n```\n\nBuild the desktop app:\n\n```bash\npnpm desktop:build\n```\n\n### Pre-Built Installers\n\nTagged releases publish installers for macOS (Apple Silicon + Intel),\nWindows, and Linux on the [GitHub Releases page](../../releases).\n\nThese builds are not signed by an Apple Developer ID or an EV Windows\ncertificate, so Gatekeeper / SmartScreen will warn you on first launch. See\n[docs/install-unsigned.md](docs/install-unsigned.md) for the one-time bypass\nsteps for each platform.\n\nUseful shortcuts:\n\n| Shortcut | Action |\n|---|---|\n| `Cmd+Shift+Space` | Open or close the quick panel |\n| `Option+Cmd+T` | Start or stop the timer |\n| `Enter` in quick panel | Start tracking |\n| `Esc` in quick panel | Close the panel |\n| `Cmd+O` in quick panel | Open the full app |\n| `Cmd+Q` | Quit |\n\n## Deploy the Web Dashboard on Cloudflare\n\nThis is the recommended deployment for non-developers because it avoids managing a VPS.\n\n### What Cloudflare Will Host\n\n- The web dashboard.\n- The API routes for login and sync.\n- The D1 database that stores hosted sync data.\n\n### 1. Log In to Cloudflare\n\n```bash\npnpm --filter @ttf/api exec wrangler login\n```\n\n### 2. Create Databases\n\n```bash\npnpm --filter @ttf/api exec wrangler d1 create tickr-staging\npnpm --filter @ttf/api exec wrangler d1 create tickr-prod\n```\n\nCloudflare will print database IDs. Copy those IDs into `infra/wrangler/wrangler.jsonc`:\n\n- Put the staging ID in `env.staging.d1_databases[0].database_id`.\n- Put the production ID in `env.production.d1_databases[0].database_id`.\n\n### 3. Add Login Secrets\n\nRun these commands:\n\n```bash\nopenssl rand -hex 32 | pnpm --filter @ttf/api exec wrangler secret put JWT_SECRET -c ../../infra/wrangler/wrangler.jsonc --env staging\nopenssl rand -hex 32 | pnpm --filter @ttf/api exec wrangler secret put JWT_SECRET -c ../../infra/wrangler/wrangler.jsonc --env production\n```\n\n### 4. Create the Database Tables\n\n```bash\npnpm cf:migrate:staging\npnpm --filter @ttf/api exec wrangler d1 migrations apply tickr-prod --remote -c ../../infra/wrangler/wrangler.jsonc --env production\n```\n\n### 5. Test Before Deploying\n\n```bash\npnpm cf:check\npnpm cf:types:check\npnpm cf:deploy:dry\n```\n\n### 6. Deploy\n\n```bash\npnpm cf:deploy:staging\n```\n\nFor the detailed Cloudflare guide, see [docs/deploy-cloudflare.md](docs/deploy-cloudflare.md).\n\n## Connect the Desktop App to Your Hosted Dashboard\n\n1. Open the deployed website.\n2. Register the first user.\n3. Log in.\n4. Use the web dashboard normally in your browser.\n5. Create a desktop sync token with the command below.\n6. Open Tickr desktop settings and paste:\n   - Backend URL: your hosted Worker URL.\n   - Token: the token from the command below.\n\nDesktop sync still uses a Bearer token. The web dashboard uses a safer browser cookie session.\n\nReplace the email, password, and URL before running this:\n\n```bash\ncurl -sS \\\n  -H \"content-type: application/json\" \\\n  -X POST \"https://your-worker-url.example/auth/login\" \\\n  --data '{\"email\":\"you@example.com\",\"password\":\"your-password\"}'\n```\n\nCopy the `token` value from the response into the desktop app settings.\n\n## Run Locally With Sync\n\nThis is useful if you want to test the backend and web dashboard before deploying.\n\nStart Postgres:\n\n```bash\npnpm db:up\n```\n\nSet local environment variables:\n\n```bash\nexport DATABASE_URL=postgres://postgres:postgres@localhost:5432/timetracker\nexport JWT_SECRET=$(openssl rand -hex 32)\nexport CORS_ORIGIN=http://localhost:1420,http://localhost:5173\nexport REGISTRATION_MODE=open\n```\n\nApply database migrations:\n\n```bash\npnpm db:migrate:pg\n```\n\nStart the API:\n\n```bash\npnpm api\n```\n\nStart the web dashboard in a second terminal:\n\n```bash\npnpm web\n```\n\nOpen `http://localhost:5173`, register a user, and connect the desktop app to `http://localhost:8787` if you want desktop sync.\n\n## VPS / Self-Hosted Notes\n\nThe VPS path is currently for people comfortable running Node.js, Postgres, and a reverse proxy.\n\nMinimum pieces:\n\n- Postgres database.\n- Node.js API from `apps/api`.\n- Built web dashboard from `apps/web/dist`.\n- HTTPS reverse proxy such as Caddy or Nginx.\n- Environment variables from `.env.example`.\n\nRequired API environment variables:\n\n```bash\nDATABASE_URL=postgres://USER:PASSWORD@HOST:5432/timetracker\nJWT_SECRET=replace-with-openssl-rand-hex-32\nPORT=8787\nCORS_ORIGIN=https://your-domain.example\nREGISTRATION_MODE=first-user\n```\n\nProduction VPS checklist:\n\n- Run `pnpm db:migrate:pg` before starting the API.\n- Run `pnpm api:build`.\n- Start `apps/api/dist/index.node.js` with a process manager.\n- Serve `apps/web/dist` from your reverse proxy.\n- Proxy `/auth/*`, `/sync/*`, and `/health` to the API.\n- Use HTTPS.\n\nThis README intentionally treats Cloudflare as the easier hosted path until the VPS setup has its own production Docker/reverse-proxy package.\n\n## Common Commands\n\n| Script | Description |\n|---|---|\n| `pnpm desktop` | Run the macOS desktop app |\n| `pnpm desktop:build` | Build the desktop app |\n| `pnpm web` | Run the web dashboard locally |\n| `pnpm web:build` | Build the web dashboard |\n| `pnpm api` | Run the Node/Postgres API locally |\n| `pnpm api:build` | Build the API |\n| `pnpm build` | Build everything |\n| `pnpm typecheck` | Typecheck all workspaces |\n| `pnpm db:up` | Start local Postgres |\n| `pnpm db:migrate:pg` | Apply Postgres migrations |\n| `pnpm cf:check` | Validate Cloudflare deploy with a dry run |\n| `pnpm cf:migrate:staging` | Apply staging D1 migrations |\n| `pnpm cf:deploy:staging` | Deploy to Cloudflare staging |\n\n## Project Layout\n\n```text\napps/\n  desktop/      macOS desktop app\n  web/          browser dashboard\n  api/          hosted API for sync and auth\npackages/\n  db/           database schemas and migrations\n  shared/       shared sync contracts and utilities\n  ui/           shared UI components\n  invoice-pdf/  PDF invoice template\ninfra/\n  docker/       local Postgres compose file\n  wrangler/     Cloudflare Worker deploy config\ndocs/\n  deploy-cloudflare.md\n```\n\n## Feature Specs\n\nThis repo uses Spec-Driven Development. Completed work is documented in `specs/active`.\n\n- [`ttf-001`](specs/active/ttf-001/feature-brief.md): first desktop/API/web sync foundation.\n- [`ttf-002`](specs/active/ttf-002/feature-brief.md): richer clients, quick panel, menubar timer, real pause.\n- [`ttf-003`](specs/active/ttf-003/feature-brief.md): invoice PDF export and branded invoice profile.\n- [`ttf-004`](specs/active/ttf-004/feature-brief.md): Cloudflare deployability and web auth hardening.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmadebyaris%2Ftime-tracker-freelance","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmadebyaris%2Ftime-tracker-freelance","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmadebyaris%2Ftime-tracker-freelance/lists"}