Context
Aaron's call (2026-05-04): move away from Substack as the primary organizing platform; let people subscribe to Parachute directly via parachute.computer. Goal: "this becomes a way to move people from interested to actual user more effectively."
Same pattern shipped on LVB (interest list V1, then linked to users) and RegenHub (interest list V1, then linked to members). Parachute is the third site to join the architecture.
Stack choice
Aaron's pick: Cloudflare Workers + D1, no Resend yet (V2).
Practical instantiation: Cloudflare Pages + Pages Functions + D1. Pages Functions ARE Workers — just integrated with the static-site deploy. Single deploy target, same-origin POST, no CORS.
This means migrating parachute.computer from GitHub Pages → Cloudflare Pages. 11ty build runs on Pages CI (the existing npx @11ty/eleventy command); the static site behavior is unchanged.
Schema (D1 / SQLite)
CREATE TABLE interests (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT NOT NULL,
name TEXT,
source_path TEXT, -- which page they signed up from
user_id INTEGER, -- NULL for V1; reserved for future identity-linking when Parachute has user accounts
resend_contact_id TEXT, -- NULL for V1; reserved for V2 Resend sync
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX idx_interests_email ON interests(email);
Schema matches LVB's interests table (after #44's user_id addition). Two reserved columns intentionally — we know V2 wants them, and a fresh table is cheaper than a future migration.
UI scope
Inline email form on the homepage (index.njk):
- Single email input + button
- Posts to
/api/subscribe (same-origin Pages Function)
- Mirror the visual rhythm of the existing hero — fits naturally below the value prop
/subscribe/thanks/ success page (or success state inline; whichever feels more 11ty-natural)
Defer admin UI to V2 — for V1, query D1 via wrangler d1 execute when Aaron wants to see the list. Keeps surface area small.
Backend scope
functions/api/subscribe.ts (Pages Function):
- POST handler — validates email regex, inserts to D1, returns redirect to /subscribe/thanks/
- Lowercases + trims email before insert
- Captures
source_path from Referer header
- No de-dup constraint on email (matches LVB/RegenHub V1 — multiple signups from same email are tolerated, signal preserved)
Wrangler config for Pages — wrangler.toml or equivalent declaring the D1 binding name (e.g. DB).
Acceptance
What Aaron handles directly
- Cloudflare Pages project setup (browser-based dashboard work)
- D1 database creation
- Binding configuration
- DNS update from GH Pages → CF Pages
- (Eventually) Cloudflare API token if we want CI-driven migrations later
What the tentacle handles
- All code: form on
index.njk, Pages Function, migration SQL, wrangler config
- Local testing with
wrangler pages dev
- Documentation (CLAUDE.md update, README note about the new setup)
Sequence
- Tentacle writes code + drafts wrangler config + migration SQL → opens PR
- Aaron does the Cloudflare Pages setup + D1 creation + DNS swap (one-time setup)
- Migration applied, deploy triggers, smoke-test from the live URL
Out of scope (for V1)
- Resend integration (V2)
- Admin UI (V2 — for now, query D1 directly)
- Identity linking to a future Parachute user store (V3, when accounts exist)
- Any Substack export / migration of existing subscribers (Aaron's call on whether to even bother)
Context
Aaron's call (2026-05-04): move away from Substack as the primary organizing platform; let people subscribe to Parachute directly via parachute.computer. Goal: "this becomes a way to move people from interested to actual user more effectively."
Same pattern shipped on LVB (interest list V1, then linked to users) and RegenHub (interest list V1, then linked to members). Parachute is the third site to join the architecture.
Stack choice
Aaron's pick: Cloudflare Workers + D1, no Resend yet (V2).
Practical instantiation: Cloudflare Pages + Pages Functions + D1. Pages Functions ARE Workers — just integrated with the static-site deploy. Single deploy target, same-origin POST, no CORS.
This means migrating parachute.computer from GitHub Pages → Cloudflare Pages. 11ty build runs on Pages CI (the existing
npx @11ty/eleventycommand); the static site behavior is unchanged.Schema (D1 / SQLite)
Schema matches LVB's interests table (after #44's user_id addition). Two reserved columns intentionally — we know V2 wants them, and a fresh table is cheaper than a future migration.
UI scope
Inline email form on the homepage (
index.njk):/api/subscribe(same-origin Pages Function)/subscribe/thanks/success page (or success state inline; whichever feels more 11ty-natural)Defer admin UI to V2 — for V1, query D1 via
wrangler d1 executewhen Aaron wants to see the list. Keeps surface area small.Backend scope
functions/api/subscribe.ts(Pages Function):source_pathfrom Referer headerWrangler config for Pages —
wrangler.tomlor equivalent declaring the D1 binding name (e.g.DB).Acceptance
npx @11ty/eleventy, output =_site)parachute-dbor similar) and migration appliedfunctions/api/subscribe.tsPages Function written, accepting POST and writing to D1/subscribe/thanks/success page existsWhat Aaron handles directly
What the tentacle handles
index.njk, Pages Function, migration SQL, wrangler configwrangler pages devSequence
Out of scope (for V1)