An open-source car logbook PWA for Australian taxpayers using the ATO logbook method to claim work-related car expenses. Track trips, odometer readings, and business-use percentage, then generate the records the ATO expects for your logbook period.
β οΈ Early stage β use with caution. This project is a 100% AI-coded experiment (see Built with Claude). It is not yet battle-tested. Always double-check every figure before you lodge anything with the ATO, and confirm with a registered tax agent. Not tax advice.
Every line of this project β code, tests, docs, and this README β was written by Claude (Anthropic's Claude Code), with a human acting only as product owner: setting direction, reviewing, and approving. No human hand-wrote the implementation. It was built the "vibecoded" way: brainstorm β plan β test-driven development β PR review β deploy, all driven by Claude.
That's the fun of it β and the caveat. It's early and experimental; treat outputs as a starting point, not gospel. Bug reports and scrutiny welcome via Issues.
New here or not a developer? The Wiki
is a plain-English manual: what you need, a step-by-step setup guide, how to
use the app day to day, the logbook method explained, and the reports. Source
lives in wiki/ and is published to the Wiki automatically.
- Next.js 16 (App Router, TypeScript strict mode)
- Tailwind CSS 4
- Cloudflare Workers via OpenNext β hosting, D1 (database), R2 (receipt storage), Workers AI
- Drizzle ORM β D1 schema and queries
- Vitest β unit tests, including the tax engine
pnpm install
pnpm devOpen http://localhost:3000.
Copy .env.example to .dev.vars and fill in local-only values before
running anything that needs them:
cp .env.example .dev.varsEach user self-hosts their own copy on Cloudflare Workers (via
OpenNext). You deploy a
tagged release, not main.
1. Log in to your Cloudflare account (once):
corepack pnpm install # installs the pinned local wrangler
corepack pnpm exec wrangler loginUse the project-local
wrangler(corepack pnpm exec wrangler β¦), notpnpm dlx wrangler. On pnpm 12dlxblocks theesbuild/workerdbuild scripts and aborts withERR_PNPM_IGNORED_BUILDS. The local binary is already pinned inpackage.jsonand matches CI.
2. Create the Cloudflare resources (once), then note the printed IDs:
corepack pnpm exec wrangler d1 create ginoos-log-book
corepack pnpm exec wrangler r2 bucket create ginoos-log-book-receipts
# Workers AI needs no resource β the [ai] binding is enough.3. Configure wrangler β copy the example and paste your own database_id:
cp wrangler.toml.example wrangler.toml # gitignored; never commit real IDs
# edit wrangler.toml: set database_id (the id printed by `d1 create` above)4. Apply migrations to the remote D1, then build + deploy:
pnpm cf-typegen # generate CloudflareEnv types (optional but recommended)
pnpm db:remote # wrangler d1 migrations apply DB --remote
pnpm run deploy # opennextjs-cloudflare build && ... deployUse pnpm preview to run the built Worker locally before deploying.
Use
pnpm run deploy, notpnpm deploy.deployis a built-in pnpm command, so the bare form ignores this project's script and aborts withERR_PNPM_INVALID_DEPLOY_TARGET. Therunprefix forces the package script.
Your checkout path must not contain an apostrophe (or other shell-special characters). OpenNext bakes the absolute build path into the bundled Worker, and esbuild then chokes on a path like
.../Ginoo's Log Book/...withExpected ")" but found "s". Clone into a plain path such asaussie-car-logbook/and the build succeeds.
This app has no built-in login; it assumes a single user and delegates
auth to Cloudflare Access
(free tier). Without this, your financial data is public. No custom domain
is needed β Access protects the *.workers.dev URL directly:
- Zero Trust (https://one.dash.cloudflare.com) β first time only, pick a team name and the Free plan.
- Workers & Pages β your Worker β Access tab β Protect this Worker behind Access, scope All traffic (production + preview URLs).
- Policy: rule type Emails (not "Email domain") β your own address only.
- Login method: One-time PIN (email code). If it isn't offered, enable it once under Zero Trust β Settings β Authentication β Login methods β Add β One-time PIN (new Zero Trust orgs no longer add it automatically). Add Google later if you like.
- Verify in an incognito window: the Cloudflare login page must appear before the app loads. Note a non-allowed email still sees that page and a "code emailed" message β Cloudflare does this to prevent address enumeration; only your allowed email actually receives a working code and reaches the app.
See SECURITY.md.
This is a public, open-source repository. Never commit:
- Real Cloudflare account IDs, D1 database IDs, or API tokens
.dev.vars,wrangler.toml, or any.env*file (only the*.exampletemplates with placeholder values are committed)- Trip logs, odometer readings, receipts/receipt images, or any other personal or financial data
Local secrets and personal data stay in gitignored files
(.dev.vars, wrangler.toml, .wrangler/, .open-next/) or in your own
Cloudflare account β never in the git history.
0 comments
log in to comment.