Skip to content

Cancer50Pledge.ca — Phase B

Date: 2026-04-08

The Cancer50Pledge scaffold is already live at https://cancer50pledge.pages.dev. It was built in Phase A with SvelteKit + Cloudflare Pages. All routes exist: / (homepage), /pledge (pledge form), /about, /impact.

The /pledge page currently has Google Form placeholder links instead of a real backend. Phase B connects the pledge form to real infrastructure, adds the Founding Pledgers wall, shareable certificate, Fathom analytics, and activates the custom domain (cancer50pledge.ca).

This is a Claude Code task, to be run after Tasks 1, 2, 3, and 4 are complete.

Code location: /home/ta/projects/mbr/cancer50pledge/ Current deploy: https://cancer50pledge.pages.dev Target domain: cancer50pledge.ca

cancer50pledge/
├── src/routes/
│ ├── +layout.svelte
│ ├── +layout.ts
│ ├── +page.svelte # Homepage — complete, good quality
│ ├── about/+page.svelte # Story page
│ ├── impact/+page.svelte # Impact page
│ └── pledge/+page.svelte # Pledge form — Google Form placeholders to replace
├── static/
├── svelte.config.js
└── package.json (uses npm — MUST migrate to pnpm)

Note: package.json shows npm scripts. Per GlobalDevRules, migrate to pnpm as part of this task.

  • Remove node_modules/, package-lock.json
  • Install dependencies with pnpm install
  • Update any scripts that reference npm run to pnpm run
  • Verify pnpm build and pnpm dev work correctly

2. Real Pledge Form Backend (Cloudflare Worker)

Section titled “2. Real Pledge Form Backend (Cloudflare Worker)”

Replace Google Form placeholders in /pledge/+page.svelte with a real form that submits to a Cloudflare Worker.

Individual Pledge form fields:

  • Name (required)
  • Email (required)
  • Message (optional, max 200 chars): “Why do you stand with the Cancer50Pledge?”
  • Consent checkbox: “I agree to be listed on the public pledger wall” (default checked)
  • Hidden field: pledge_type: "individual"

Corporate Pledge form fields:

  • Organization name (required)
  • Contact name (required)
  • Contact email (required)
  • Pledge percentage (required, e.g. “5% of annual net profit”)
  • Message (optional)
  • Consent checkbox: “I agree to be listed on the public Founding Pledgers wall”
  • Hidden field: pledge_type: "corporate", founding_pledger: true (first 50)

Cloudflare Worker (cancer50pledge/worker/pledge-handler.js):

  1. Accept POST from form
  2. Validate required fields, basic email format
  3. Append row to Google Sheets via Sheets API (or Airtable — use whichever was chosen for the MBR website waitlist in Task 3 for consistency)
  4. Assign Founding Pledger number if pledge_type === "corporate" and counter < 50 (store counter in Cloudflare KV)
  5. Return: { success: true, founding_pledger_number: N | null, message: "..." }

Post-submission UX:

  • Show confirmation inline (no page redirect)
  • Individual: “You’re signed. Share this with someone who should join.”
  • Corporate Founding Pledger: “You’re Founding Pledger #N. Your certificate is being prepared.”

Add a section to the homepage / showing the first Founding Pledgers.

Implementation:

  • Add a data/founding-pledgers.json static file to the repo (seeded manually by Talbot with first pledgers)
  • On the homepage, render: numbered list of pledgers (#1, #2, …), org name, pledge %, date signed
  • Individual pledgers shown separately below Corporate Founding Pledgers
  • “Join the next [N] open spots” CTA linking to /pledge#corporate

Static data structure:

{
"founding_pledgers": [
{
"number": 1,
"name": "MyBetterRates",
"type": "corporate",
"pledge_pct": 50,
"signed_date": "2026-04-08",
"public": true
}
],
"individual_pledgers": []
}

Note: Talbot will populate the first entry (MBR itself is Founding Pledger #1). Leave the data file as a stub — do not invent pledgers.

Add a /certificate/[id] route that generates a shareable pledge certificate.

Certificate design:

  • Full-page layout (printable / screenshot-friendly)
  • Includes: Cancer50Pledge logo, pledger name/org, pledge percentage, date signed, Founding Pledger number (if applicable)
  • “Download as PNG” button — use HTML Canvas or a simple SVG-to-PNG approach
  • LinkedIn share button with pre-filled text: “I just signed the #Cancer50Pledge. [org] commits [X]% of profits to cancer research. Join the movement at cancer50pledge.ca”
  • OG meta tags on the certificate page for social sharing previews

For Phase B, keep certificate generation client-side (no server-side image rendering). A styled HTML page that screenshots well is sufficient.

Add Fathom analytics (privacy-first, no GDPR cookie banner needed).

  • Add Fathom script to +layout.svelte
  • Configure site ID in environment variable (PUBLIC_FATHOM_SITE_ID)
  • Track custom goals:
    • individual-pledge-submitted
    • corporate-pledge-submitted
    • certificate-downloaded
  • Do NOT add Google Analytics or any cookie-requiring tracker

Connect cancer50pledge.ca to the Cloudflare Pages project.

  • Verify the domain is already registered (check with Talbot if unclear)
  • Add custom domain in Cloudflare Pages dashboard (this is a manual step — document the exact steps in a DEPLOY.md file in the project root so Talbot can do this without needing Claude)
  • Update all internal links that reference cancer50pledge.pages.dev to use relative paths (so they work on both domains)
  • Update OG/meta tags to use https://cancer50pledge.ca as canonical URL

Before completing, review all existing pages against the F.A.S.T. Standard:

  • Frictionless: Can a first-time visitor understand what to do in 10 seconds?
  • Adaptive: Does it look good on mobile (390px)?
  • Simple: No unnecessary complexity or jargon
  • Tailored: Does the tone match the Cancer50Pledge brand (serious, survivor-led, not corporate)?

Fix any obvious issues found. Do not redesign — only fix clear problems.

Testing Requirements (MANDATORY before reporting complete)

Section titled “Testing Requirements (MANDATORY before reporting complete)”
  • pnpm build — zero errors
  • pnpm dev — all pages render, no console errors
  • Individual pledge form submits → row appears in Google Sheets/Airtable → confirmation shown in UI
  • Corporate pledge form submits → Founding Pledger number assigned → confirmation shown
  • Founding Pledgers wall renders with at least the seed data (MBR as #1)
  • Certificate page loads and displays correctly for a test pledger
  • “Download as PNG” button produces a usable image
  • Fathom goals fire on form submission (verify in Fathom dashboard or browser network tab)
  • Mobile responsive at 390px — no horizontal overflow
  • All internal cancer50pledge.pages.dev references replaced with relative paths
  • pnpm only (migrate from npm first)
  • SvelteKit + adapter-static
  • Tailwind CSS v3
  • No hardcoded credentials — all secrets in .env, .env.example with placeholders only

The brief says “Google Sheets or Airtable” — this is superseded. Use Cloudflare D1 (same decision as the MBR website waitlist, made 2026-04-09). Keeps all data on CF edge infrastructure, ~1ms, no external API keys.

PathStatus
Project code/home/ta/projects/mbr/cancer50pledge/ — verified exists
Current deployhttps://cancer50pledge.pages.dev — live
Brand reference/mnt/d/FSS/KB/MBR/02_Strategy/Brand.md — verified exists
Target domaincancer50pledge.ca — registration status unknown, do NOT configure DNS
  • Tailwind CSS v4 already installed (v4.2.2) — do NOT downgrade to v3 (GlobalDevRules says v3 but project has v4; work with what’s there)
  • npm scripts currently in use → migrate to pnpm as Task 1 (remove node_modules/, no package-lock.json exists, run pnpm install)
  • Routes already exist: /, /pledge, /about, /impact — do not delete any
  • SvelteKit + adapter-static + Cloudflare Pages — established and working

Create: wrangler d1 create cancer50pledge-pledges

Schema:

CREATE TABLE individual_pledges (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL,
message TEXT,
consent INTEGER NOT NULL DEFAULT 1,
created_at TEXT NOT NULL
);
CREATE TABLE corporate_pledges (
id INTEGER PRIMARY KEY AUTOINCREMENT,
org_name TEXT NOT NULL,
contact_name TEXT NOT NULL,
contact_email TEXT NOT NULL,
pledge_pct TEXT NOT NULL,
message TEXT,
consent INTEGER NOT NULL DEFAULT 1,
founding_pledger_number INTEGER,
created_at TEXT NOT NULL
);

Founding Pledger counter: Cloudflare KV binding CANCER50_KV, key founding_pledger_counter.

Worker file: cancer50pledge/worker/pledge-handler.js

  • Logo: mBR mark with Pledge Rose dot (#E8627A) instead of Wealth Gold
  • Primary: Treasury Emerald #004425
  • Accent: Pledge Rose #E8627A
  • Background: #f5f5f0
  • Font: Inter (variable)
  • Tone: serious, survivor-led, not corporate — authentic and direct
  • PUBLIC_FATHOM_SITE_ID env var — Talbot must provide from Fathom dashboard
  • Site must build and run without this var set (conditional include only)
  • Custom goals: individual-pledge-submitted, corporate-pledge-submitted, certificate-downloaded

Do NOT configure DNS or custom domain in Cloudflare Pages dashboard. Instead:

  • Use relative paths for all internal links (not cancer50pledge.pages.dev hardcoded)
  • Create DEPLOY.md with exact steps for Talbot to connect cancer50pledge.ca

Do NOT invent pledgers. Leave data/founding-pledgers.json as a stub — MBR is Founding Pledger #1, but Talbot populates this manually:

{
"founding_pledgers": [],
"individual_pledgers": []
}
  • Cloudflare D1: create new DB as part of this task
  • Cloudflare KV: create namespace for founding pledger counter
  • Fathom: Talbot provides PUBLIC_FATHOM_SITE_ID (site builds without it)
  • No dependency on MBR website task — this task is fully independent
  • Model recommendation: Sonnet (SvelteKit component + Cloudflare Worker)
  • Assignee: Cursor / Claude Code (fresh session)
  • Key constraints:
    1. Backend = Cloudflare D1 — ignore “Google Sheets or Airtable” in brief
    2. Tailwind v4 is installed — do NOT change to v3
    3. pnpm migration is Task 1 — do it before anything else
    4. Do NOT populate founding-pledgers.json with invented data
    5. Domain DNS = Talbot’s job — document in DEPLOY.md, do not configure
    6. pnpm build zero errors before reporting complete
    7. Test D1 write end-to-end before reporting complete