Single source of truth for every open issue across the codebase. Pulls
from LAUNCH_READINESS.md (post-launch sections), TODO.md (deferred
features + simplify follow-ups + wave-Slack pilot), and a fresh sweep
of in-code TODO/FIXME comments.
LAUNCH_READINESS.md now keeps only the pre-cutover deploy checklist and
points to BACKLOG.md for everything else. Cutover note corrected — it
has not happened yet.
Force-added BACKLOG.md despite the /docs/ gitignore rule because
LAUNCH_READINESS.md is tracked and now references it.
Verified clean 2026-04-29: grep for guild-[0-9]|candlelight-[0-9]|ember-[0-9]
across app/layouts/, app/pages/admin/, and app/components/admin/ returns zero
matches. All admin surfaces already use design tokens.
TierPicker.vue is a 5-tier preset picker from before the arbitrary-
amount contribution redesign. Zero imports across app/ and server/ —
purely dead code (99 lines).
Strike two LAUNCH_READINESS bullets that describe already-fixed
issues: the "stale tier comment" in useMemberPayment.js (no `tier`
references remain in that file), and the SeriesPassPurchase auto-
refresh gotcha (fetchPassInfo() already runs after the success path
at line 318).
Nuxt UI 4's Toast component reads `duration` (default 5000ms), not
`timeout` — the property was silently ignored. Behavior unchanged
since 5000ms matched the default. Fix the call site to be honest.
Strike the now-resolved gotcha from LAUNCH_READINESS.md.
Helcim returns next-charge as `dateBilling` on POST /subscriptions, but the
two CREATE sites were reading `subscription.nextBillingDate`, leaving
`member.nextBillingDate` empty after every signup and free→paid upgrade.
The lazy refresh in subscription.get.js (which already accepts both shapes)
masked it on next account-page load, so renders eventually populated — but
the success response we returned to the client also had `nextBillingDate:
undefined`. Mirror the GET-side resolution at both CREATE sites: prefer
`dateBilling`, fall back to `nextBillingDate`. Existing Number.isNaN guard
unchanged; defensively rejects malformed strings from either field.
Production hosting is Dokploy on Hetzner, not Netlify. The Nitro app
itself is host-agnostic — Dockerfile + Traefik-aware OIDC + xff-aware
rate limiting were already in place — but the Deploy checklist and the
daily reconcile cron were Netlify-specific.
- LAUNCH_READINESS.md: split Deploy checklist into one-time host setup
+ cutover; replace "Netlify scheduled function" with a Dokploy
Scheduled Task (curl + X-Reconcile-Token); call out the BASE_URL
exact-match origin gotcha at customer.post.js:11-15 and the
NODE_ENV=production requirement.
- Delete netlify.toml and netlify/functions/reconcile-payments.mjs.
The Nitro route at server/api/internal/reconcile-payments.post.js
stays — it's host-agnostic; only the trigger moves into Dokploy.
No code changes. validate-env.js still hard-fails on missing
MONGODB_URI / JWT_SECRET / RESEND_API_KEY / HELCIM_API_TOKEN at boot.
Tests: 758 passing, 2 skipped, 0 failing.
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.
Adds schema-based input validation across helcim, events, members,
series, admin, and updates API endpoints. Removes the peer-support
debug test endpoint. Adds validation test coverage.
Set up Vitest with server (node) and client (jsdom) test projects.
79 tests across 8 files verify all Phase 0-1 security controls:
escapeHtml sanitization, DOMPurify markdown XSS prevention, CSRF
enforcement, security headers, rate limiting, auth guards, profile
field allowlist, and login anti-enumeration. Updated SECURITY_EVALUATION.md
with remediation status, implementation summary, and automated test
coverage details.