Follow-up to 51230e5. /simplify review surfaced residual duplication
and a timer leak.
- useHelcimPay: extract _initializeTicket(metadata, errorPrefix) to
collapse initializeTicketPayment + initializeSeriesTicketPayment
(95% identical bodies). Drop the dead `amount` arg from initialize-
TicketPayment — server re-derives ticket amounts in initialize-
payment.post.js and never reads body.amount for ticket types.
Capture timer ids and clearTimeout on resolve/reject so the 10-min
payment timer and 5-second observer timer stop leaking after every
payment.
- EventTicketPurchase: caller updated for the dropped arg.
- verify.post.js: replace inline jwt.sign + setCookie block with the
setAuthCookie(event, member) helper. verify was the last hand-rolled
caller after the helper was extracted in 208638e.
- LAUNCH_READINESS: add simplify-pass-followups bullet pointing to the
six deferred items in docs/TODO.md.
Tests: 758 passing, 2 skipped, 0 failing.
Day-of-launch deep-dive audit and remediation. 11 issues fixed across
security, correctness, and reliability. Tests: 698 → 758 passing
(+60), 0 failing, 2 skipped.
CRITICAL (security)
Fix#1 — HELCIM_API_TOKEN removed from runtimeConfig.public; dead
useHelcim.js deleted. Production token MUST BE ROTATED post-deploy
(was previously exposed in window.__NUXT__ payload).
Fix#2 — /api/helcim/customer gated with origin check + per-IP/email
rate limit + magic-link email verification (replaces unauthenticated
setAuthCookie). Adds payment-bridge token for paid-tier signup so
users can complete Helcim checkout before email verify. New utils:
server/utils/{magicLink,rateLimit}.js. UX: signup success copy now
prompts user to check email.
Fix#3 — /api/events/[id]/payment deleted (dead code with unauth
member-spoof bypass — processHelcimPayment was a permanent stub).
Removes processHelcimPayment export and eventPaymentSchema.
Fix#4 — /api/helcim/initialize-payment re-derives ticket amount
server-side via calculateTicketPrice and calculateSeriesTicketPrice.
Adds new series_ticket metadata type (was being shoved through
event_ticket with seriesId in metadata.eventId).
Fix#5 — /api/helcim/customer upgrades existing status:guest members
in place rather than rejecting with 409. Lowercases email at lookup;
preserves _id so prior event registrations stay linked.
HIGH (correctness / reliability)
Fix#6 — Daily reconciliation cron via Netlify scheduled function
(@daily). New: netlify.toml, netlify/functions/reconcile-payments.mjs,
server/api/internal/reconcile-payments.post.js. Shared-secret auth
via NUXT_RECONCILE_TOKEN env var. Inline 3-retry exponential backoff
on Helcim transactions API.
Fix#7 — validateBeforeSave: false on event subdoc saves (waitlist
endpoints) to dodge legacy location validators.
Fix#8 — /api/series/[id]/tickets/purchase always upserts a guest
Member when caller is unauthenticated, mirrors event-ticket flow
byte-for-byte. SeriesPassPurchase.vue adds guest-account hint and
client auth refresh on signedIn:true response.
Fix#9 — /api/members/cancel-subscription leaves status active per
ratified bylaws (was pending_payment). Adds lastCancelledAt audit
field on Member model. Indirectly fixes false-positive
detectStuckPendingPayment admin alert for cancelled members.
Fix#10 — /api/auth/verify uses validateBody with strict() Zod schema
(verifyMagicLinkSchema, max 2000 chars).
Fix#11 — 8 vitest cases for cancel-subscription handler (was
uncovered).
Specs and audit at docs/superpowers/specs/2026-04-25-fix-*.md and
docs/superpowers/plans/2026-04-25-launch-readiness-fixes.md.
LAUNCH_READINESS.md updated with new test count, 3 deploy-time
tasks (rotate Helcim token, set NUXT_RECONCILE_TOKEN, verify
Netlify scheduled function), and Fixed-2026-04-25 fix log.
Pre-fix (before f34b062 / 4e1888a) prod may contain drop-in
registrations on pass-only series events. Defer audit + remediation
until deploy time; local was scrubbed separately on 2026-04-20.
Collapse completed launch sections (receipts Phase 1, cadence UX,
contribution-amount manual tests) into one-liners; move them to the
archive memory. Move the three known post-launch gotchas to their own
subsection. Ignore the local one-off preregistration dump script.
Flips the P1 section from 'none of it is implemented' to a shipped/remaining
breakdown citing commits bf5a333..91711aa, and adds a one-line current-state
bullet pointing at the unmerged feature branch.
Captures the three post-Phase-1 deploy steps: run
reconcile-helcim-payments.mjs against prod Mongo after the new code
is serving, disable the default Helcim confirmation email for plans
50302 + 50303 (Branch B — we send our own via Resend), and run a
real staging test charge to verify the Payment doc + single
CRA-compliant confirmation email.
Three related changes on /member/account:
1. Payment History section now renders when contributionAmount > 0 OR
past payments exist. Previously a paid member who switched to $0 lost
visibility of their own past charges.
2. New "Next charge: $X on DATE" row renders above the transaction list
when nextPaymentDate is available, using --candle dashed border.
3. server/api/helcim/subscription.get.js now reads dateBilling from
Helcim's GET response and handles data as either object or array.
Helcim's real shape is {data: {id, dateBilling, ...}} — the old code
expected {data: [{nextBillingDate}]} and returned empty strings, so
the Membership-card "Next payment" row never rendered for members
whose cached date was missing. subscription.post.js and
update-contribution.post.js have the same wrong field name in their
CREATE flows; left for a follow-up — the GET refresh masks it.
Manual edit-flow and admin-flow tests also recorded in
docs/LAUNCH_READINESS.md.
Extract shared SignupFlowOverlay component. Static "Monthly Contribution"
label on all three contribution inputs (was misleadingly dynamic).
"Per Year"/"Per Month" toggle copy; Per Year default on accept-invite,
Per Month default on join. Live billing-summary card on both signup
flows. Welcome-heading on dashboard via ?welcome=1 for new signups.
$0-member polish on account page (hide payment-history + Solidarity
Fund prompts). State-aware contribution-change hint. Invite accept now
creates Helcim customer and sets auth cookie server-side for both free
and paid branches. Pre-registrant invite + /join signup flows manually
verified against Cleo Nguyen preReg and $0-$50 variants.
Branch merges and 7/9 manual tests are done — moved to archive. Live
doc now only carries open work: charitable receipts Phase 1, prod
contribution-amount migration + Helcim plan env vars, and two manual
tests (pre-registrant invite, contribution-amount end-to-end). Both
remaining tests now include setup, test steps, assertions, and the
file references needed to complete them without additional context.
Un-defer pre-registrant invite manual test (refactor landed), add
contribution-amount end-to-end manual test, and list the cosmetic
cleanup items (admin column, dead TierPicker, stale comments) in the
post-launch backlog.
Guest signup, mobile responsive, WCAG contrast, and in-app payment
history all verified via tunnel. Payment history's per-row receipt
link requirement accepted as satisfied by the 'Advanced billing in
Helcim' escape hatch (Helcim's card-transactions API doesn't expose
per-row receipt URLs). Also corrects the mobile breakpoint note —
chrome sidebar hides at 768px, in-page columns collapse at 1024px.