Skip to content

Interest list — direct subscribe, replacing Substack as the entry point #25

Description

@unforced

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

  • Cloudflare Pages project created for parachute.computer (Aaron does this in CF dashboard — connect GitHub repo, set build = npx @11ty/eleventy, output = _site)
  • D1 database created (parachute-db or similar) and migration applied
  • D1 binding configured on the Pages project
  • DNS: parachute.computer points at Cloudflare Pages instead of GitHub Pages (Aaron handles the DNS update; the existing CNAME file becomes irrelevant)
  • functions/api/subscribe.ts Pages Function written, accepting POST and writing to D1
  • Inline email form on homepage posts to it
  • /subscribe/thanks/ success page exists
  • Smoke-test: submit a real email, confirm row in D1
  • Existing GitHub Pages workflow archived (replaced by Pages auto-deploy)

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

  1. Tentacle writes code + drafts wrangler config + migration SQL → opens PR
  2. Aaron does the Cloudflare Pages setup + D1 creation + DNS swap (one-time setup)
  3. 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions