Skip to content

Hum2a/Monzo-1p-Challenge-Calculator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

93 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Monzo

1p Challenge Calculator

Monzo-inspired savings calculator

CI Deploy License: MIT Next.js Cloudflare

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.

Report Bug · Request Feature · Contributing


Features

  • 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

Quick Start

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 dev

Open http://localhost:3000.

Local Cloudflare preview

To run the app in the Cloudflare Workers runtime locally (closer to production):

npm run preview

Uses .dev.vars for secrets (copy from .dev.vars.example).

Production Stack

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

Environment Variables

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)

How the Math Works

  • 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

Deployment (Cloudflare)

Notes:

  • Free tier: Workers are limited to 3 MiB. A scripts/replace-og-for-cf.mjs step swaps @vercel/og for a stub (~2.1 MB saved) to stay under the limit.
  • Windows: Deploying locally can fail with resvg.wasm?module path errors. Use GitHub Actions (recommended) or WSL.

Option A: GitHub Actions (recommended)

  1. Push your repo to GitHub.
  2. 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 ID
    • AUTH_SECRET, AUTH_URL, DATABASE_URL, DIRECT_URL, AUTH_RESEND_KEY, AUTH_RESEND_FROM
  3. Push to main – the workflow deploys automatically.

Option B: Deploy from terminal with production vars (WSL or Mac/Linux)

  1. 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
  2. Run npm run deploy:prod – loads vars, uploads secrets to Cloudflare, then builds and deploys.
    • Use npm run deploy:prod -- --no-secrets to skip uploading secrets (e.g. if already set in the dashboard).

(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
# ... etc

Option C: Cloudflare Workers Build (connect Git)

Important: Use Workers (not Pages). Create → Workers & Pages → Workers → Create Worker → Connect to Git.

  1. Build command: npm run build:workers (or npx opennextjs-cloudflare build && node scripts/replace-og-for-cf.mjs)
  2. Deploy command: npx wrangler deploy (default)
  3. Framework preset: None (or override if it defaults to Next.js)
  4. Build variables: Add AUTH_SECRET, AUTH_URL, DATABASE_URL, DIRECT_URL, AUTH_RESEND_KEY, AUTH_RESEND_FROM
  5. 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.

Troubleshooting: "Output directory .vercel/output/static not found"

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:

  1. Go to Workers & Pages
  2. Click CreateWorker (not "Pages")
  3. Choose Connect to Git → select your repo
  4. Set Build command: npm ci && npx opennextjs-cloudflare build && node scripts/replace-og-for-cf.mjs
  5. Set Deploy command: npx wrangler deploy (or leave default)
  6. Add build variables (secrets) for AUTH_SECRET, AUTH_URL, DATABASE_URL, DIRECT_URL, AUTH_RESEND_KEY, AUTH_RESEND_FROM
  7. Save. You can delete or ignore the old Pages project.

Troubleshooting: "Could not find compiled Open Next config"

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).

Troubleshooting: "Application error" when sending magic link

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_URL must 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.production and uploads secrets) or set them once: npx wrangler secret put AUTH_SECRET, etc.

Scripts

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

Project Structure

.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

Security

  • Zod validation on all input
  • Rate limiting on /api/save and /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.

Contributing

Contributions are welcome! See CONTRIBUTING.md for guidelines and CODE_OF_CONDUCT.md for community standards.

Changelog

See CHANGELOG.md for version history.

License

MIT


About

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.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors