Monzo-inspired savings calculator
A production-ready web app for the 1p Accumulator / Penny Challenge savings plan. Calculate deposits for any date range, month, or custom period—with Monzo branding, mobile-first design, and optional account saving.
- 3 modes: Next N days, Month, Custom range
- Anonymous: Use immediately with localStorage
- Account: Sign in via magic link to save states to DB
- Save/Load: Up to 10 saved states per user
- PWA: Installable on mobile
npm install
cp .env.example .env.local
cp .dev.vars.example .dev.vars
# Edit .env.local and .dev.vars with your values
npm run db:generate
npm run db:push
npm run devOpen http://localhost:3000.
To run the app in the Cloudflare Workers runtime locally (closer to production):
npm run previewUses .dev.vars for secrets (copy from .dev.vars.example).
| Layer | Tech |
|---|---|
| Hosting | Cloudflare Workers (OpenNext adapter) |
| Database | Neon PostgreSQL (auth + saved states) |
| Auth | Auth.js (NextAuth v5) – magic link (Resend) |
| ORM | Prisma |
| Validation | Zod |
| UI | Tailwind + shadcn |
| Variable | Required | Description |
|---|---|---|
AUTH_SECRET |
Yes (prod) | openssl rand -base64 32 |
AUTH_URL |
Yes (prod) | Full URL of your site |
DATABASE_URL |
Yes (prod) | Neon pooled connection string |
DIRECT_URL |
Yes (prod) | Neon direct connection string |
AUTH_RESEND_KEY |
Yes (prod) | Resend API key |
AUTH_RESEND_FROM |
No | Sender email (default: Resend onboarding) |
- Day 1 = 1p, Day k = k pence
- Sum days a to b: (b(b+1) − (a−1)a) / 2 pence
- 364 days: £664.30 | 365 days: £667.95
- Integer pence only—no floats
Notes:
- Free tier: Workers are limited to 3 MiB. A
scripts/replace-og-for-cf.mjsstep swaps@vercel/ogfor a stub (~2.1 MB saved) to stay under the limit. - Windows: Deploying locally can fail with
resvg.wasm?modulepath errors. Use GitHub Actions (recommended) or WSL.
- Push your repo to GitHub.
- Add these repository secrets (Settings → Secrets and variables → Actions):
CLOUDFLARE_API_TOKEN– from Cloudflare dashboard (Create Token → Edit Cloudflare Workers)CLOUDFLARE_ACCOUNT_ID– from Workers & Pages → Overview → Account IDAUTH_SECRET,AUTH_URL,DATABASE_URL,DIRECT_URL,AUTH_RESEND_KEY,AUTH_RESEND_FROM
- Push to
main– the workflow deploys automatically.
- Copy the production template and fill in your values:
cp .dev.vars.production.example .dev.vars.production # Edit .dev.vars.production with real production secrets - Run
npm run deploy:prod– loads vars, uploads secrets to Cloudflare, then builds and deploys.- Use
npm run deploy:prod -- --no-secretsto skip uploading secrets (e.g. if already set in the dashboard).
- Use
(Windows can fail on deploy—use WSL or GitHub Actions.)
Alternative (manual secrets): Set secrets in Cloudflare once, then npm run deploy:
npx wrangler secret put AUTH_SECRET
npx wrangler secret put AUTH_URL
# ... etcImportant: Use Workers (not Pages). Create → Workers & Pages → Workers → Create Worker → Connect to Git.
- Build command:
npm run build:workers(ornpx opennextjs-cloudflare build && node scripts/replace-og-for-cf.mjs) - Deploy command:
npx wrangler deploy(default) - Framework preset: None (or override if it defaults to Next.js)
- Build variables: Add
AUTH_SECRET,AUTH_URL,DATABASE_URL,DIRECT_URL,AUTH_RESEND_KEY,AUTH_RESEND_FROM - Push to trigger deploy. Cloudflare builds on Linux (avoids Windows issues).
If you used Pages by mistake: Cloudflare Pages expects pages_build_output_dir and uses the deprecated @cloudflare/next-on-pages adapter. This project uses Workers (OpenNext). Create a new Worker project: Workers & Pages → Workers → Create → Connect to Git. Use the build command above.
This error means the repo is connected to Cloudflare Pages, not Workers. Pages looks for static output; this app outputs a Worker bundle (.open-next/).
Fix: Create a Worker project and connect the same repo:
- Go to Workers & Pages
- Click Create → Worker (not "Pages")
- Choose Connect to Git → select your repo
- Set Build command:
npm ci && npx opennextjs-cloudflare build && node scripts/replace-og-for-cf.mjs - Set Deploy command:
npx wrangler deploy(or leave default) - Add build variables (secrets) for
AUTH_SECRET,AUTH_URL,DATABASE_URL,DIRECT_URL,AUTH_RESEND_KEY,AUTH_RESEND_FROM - Save. You can delete or ignore the old Pages project.
This means the build command is wrong. Cloudflare Workers Build must use OpenNext, not plain Next.js. Set the build command to:
npm run build:workers
Do not use npm run build (that runs next build and produces the wrong output).
The Worker needs runtime secrets (AUTH_SECRET, AUTH_URL, DATABASE_URL, DIRECT_URL, AUTH_RESEND_KEY, AUTH_RESEND_FROM). If they are missing, auth will fail.
- GitHub Actions: The workflow now uploads secrets after deploy. Ensure all 6 vars are set in repo Settings → Secrets and variables → Actions.
AUTH_URLmust match your Worker URL (e.g.https://monzo-1p-challenge-calculator.humzab1711.workers.dev). - Cloudflare Workers Build (connect Git): Add secrets in the dashboard: Workers & Pages → your Worker → Settings → Variables and Secrets → Add variable (encrypted).
- Manual deploy: Run
npm run deploy:prod(loads.dev.vars.productionand uploads secrets) or set them once:npx wrangler secret put AUTH_SECRET, etc.
| Command | Description |
|---|---|
npm run dev |
Start dev server |
npm run build |
Next.js build |
npm run build:cf |
Cloudflare build |
npm run build:workers |
Cloudflare build + OG stub (for Workers Build) |
npm run deploy |
Deploy to Cloudflare |
npm run deploy:prod |
Deploy using vars from .dev.vars.production |
npm run db:generate |
Generate Prisma client |
npm run db:push |
Push schema to DB |
npm run lint |
ESLint |
npm run test |
Unit tests (Vitest) |
npm run test:e2e |
Playwright E2E |
.cursor/rules/ # AI rules (design, DB, schema, security, etc.)
.github/ # CI/CD, issue templates, PR template
app/ # Next.js app router
prisma/ # Schema and migrations
src/ # Components, lib
- Zod validation on all input
- Rate limiting on
/api/saveand/api/saved - Security headers (CSP, X-Frame-Options, etc.)
- No secrets in client; env vars only
- Prisma for parameterized queries
- Auth.js for secure session
See SECURITY.md for reporting vulnerabilities.
Contributions are welcome! See CONTRIBUTING.md for guidelines and CODE_OF_CONDUCT.md for community standards.
See CHANGELOG.md for version history.