Skip to content

Per-poll Pro upgrade (10 DKK) — creation stays free #25

Description

@malpou

Split out from #19. Rescoped 2026-07-03 — the original pay-to-create gate is superseded: the poll tool is a free lead magnet for metsa.app, and gating creation would kill the viral loop (participants seeing "create your own, free"). Full artifacts live in openspec/changes/pro-poll-upgrade/.

What

Creation stays free and instant. Each poll gets an optional one-time Pro upgrade (10 DKK Stripe Checkout) from the organizer dashboard:

  • New nullable events.pro_at (UTC ISO text; NULL = free). No backfill — existing events are correctly free.
  • Free polls' participant pages (/r, /s) show a discreet "made with — create your own, free" badge in the poll's language; Pro removes it (launch Pro value).
  • Further Pro features ship as separate changes flipping on the same flag: email notify when everyone answered, deadline/auto-close + reminders, ICS invite on close. No free-tier limits, ever — "free without limits" is the positioning against Doodle.
  • Metsa members will eventually get Pro free (Zitadel OIDC) — deferred, separate issue.

Technical notes that carry over from the original plan

  • Stripe webhook is the source of truth, not the browser redirect: checkout.session.completed → idempotent UPDATE events SET pro_at = ? WHERE id = ? AND pro_at IS NULL, then purge the event's edge-cache entries (badge visibility flips).
  • Workers needs the fetch HTTP client + constructEventAsync with createSubtleCryptoProvider() (no sync Node crypto).
  • Tokens stay out of Stripe: success_url/cancel_url point at a /paid?session_id=… endpoint that resolves the organizer token server-side from metadata.event_id.
  • E2E: STRIPE_STUB flag (e2e wrangler config only) fakes the checkout round trip through real routes; unsigned webhook POSTs must change nothing.
  • Fee caveat accepted: Stripe's fixed fee eats ~20% of 10 DKK — the microtransaction is a funnel signal (and a metsa pitch surface), not the revenue model.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions