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.
8.3 KiB
Launch Readiness
Status as of 2026-04-30. Cutover has not happened yet. Code is on local main; deploy steps below still need to execute.
Pre-cutover deploy checklist is the live content on this page. Everything else (post-launch work, bylaws decoupling, deferred features, simplify follow-ups, a11y) lives in BACKLOG.md. Completed launch-blocker items are archived — see ~/.claude/projects/-Users-jennie-Sites-ghostguild-org/memory/project_launch_readiness_archive.md.
Current state
- Vitest snapshot 2026-04-25 ~18:23 local: 703 passing / 8 failing / 2 skipped (713 total). The previously-flagged 6 helcim-payment failures are now green. The 8 current failures are in
tests/server/api/auth-verify.test.jsandtests/server/api/cancel-subscription.smoke.test.js, both belonging to in-flight Phase 5 fixes (#10 and #9) being landed by parallel impl subagents — they will resolve as those branches merge. - All launch code is on local
main: Helcim plan consolidation, contribution-amount redesign, cadence UX unification, and receipts Phase 1. Not pushed — site is not on Netlify yet. - Helcim plan consolidation migration ran against prod 2026-04-18 (Monthly plan id
50302, Annual plan id50303). - Contribution-amount migration has NOT yet been run against prod.
- Receipts Phase 1 code is shipped; remaining work is deploy-time only (see Deploy checklist).
P0 — Must fix before launch
None outstanding.
P1 — Strongly preferred before launch
None outstanding.
Deploy checklist
Applies when the app is deployed to Dokploy on Hetzner. Build is via the in-repo Dockerfile (node:20-alpine, runs node .output/server/index.mjs on port 3000); Dokploy autodetects it. Traefik (Dokploy's reverse proxy) handles SSL; oidc-provider.ts:194 and the rate-limit middleware already trust X-Forwarded-Proto / X-Forwarded-For.
One-time host setup
- Provision the Dokploy app pointing at this repo. Build context: repo root. Default Dockerfile. Container port:
3000. - Set env vars in the Dokploy UI (full list below). The
validate-env.jsNitro plugin fails fast at boot ifMONGODB_URI/JWT_SECRET/RESEND_API_KEY/HELCIM_API_TOKENare missing — container refuses to start, so misconfig surfaces immediately in logs. BASE_URLmust exactly match the public origin (e.g.https://ghostguild.org, no trailing slash). The/api/helcim/customerorigin check atserver/api/helcim/customer.post.js:11-15does exact-match comparison against theOriginheader — ifBASE_URLis wrong or unset, signup 403s.NODE_ENV=productionmust be set. Without it:Securecookie flag, HSTS, and CSP all silently no-op.- Add a Dokploy Scheduled Task for daily reconciliation. Command:
Schedule:curl -fsS -X POST "$BASE_URL/api/internal/reconcile-payments" -H "X-Reconcile-Token: $NUXT_RECONCILE_TOKEN"0 4 * * *(or any time of day). The Nitro route does the heavy lifting (Mongo iteration, Helcim API, retries) — the scheduler just wakes it up.
Cutover
- Push local
maintoorigin/main. - Run
node scripts/migrate-contribution-amount.cjs --applyagainst prod Mongo BEFORE the new code serves traffic. Idempotent; dry-run on local counted 34 members. RequiresMONGODB_URIin env. The script writescontributionAmount(Number) derived from existingcontributionTier(String) on every Member doc; the old field is left intact for a window. - Set
NUXT_HELCIM_MONTHLY_PLAN_ID=50302in Dokploy env. - Set
NUXT_HELCIM_ANNUAL_PLAN_ID=50303in Dokploy env. - Set
NUXT_RECONCILE_TOKENto any 32+ char random string. Shared secret between the Dokploy scheduled task and/api/internal/reconcile-payments. - Deploy.
- Run
node scripts/reconcile-helcim-payments.mjs --applyagainst prod Mongo AFTER the new code serves traffic to backfill Payment records for pre-existing members. Idempotent (uniquehelcimTransactionId); the daily Dokploy cron picks it up from there. - Prod audit for pre-fix series-pass bypass registrations. Fixed in
f34b062+4e1888a(2026-04-20). Before that, child events of pass-only series (tickets.requiresSeriesTicket=true && tickets.allowIndividualEventTickets=false) accepted drop-in registrations from non-pass-holders. For every such series, list its child-eventregistrationswhere the registrant is not in the parent series' pass-holder list, filter toregisteredAt < 2026-04-20, and decide per-case: grandfather (keep + notify), refund + unregister, or silently unregister. Local Mongo was scrubbed of 2 such rows on 2026-04-20; prod was intentionally untouched. - Helcim dashboard: disable the default payment-confirmation email for plans 50302 + 50303. We send our own CRA-safe confirmation via Resend (
server/emails/paymentConfirmation.js) triggered fromupsertPaymentFromHelcim; leaving Helcim's default on = duplicate emails. - Run one real test charge against the deployed app and verify (a) a Payment doc in Mongo with
amount,paymentType,status: 'success', and (b) exactly one CRA-compliant confirmation email (charity name + "not an official donation receipt" disclaimer; no banned assertive phrasing). - Rotate HELCIM_API_TOKEN in the Helcim merchant portal and update the Dokploy env var. The token was previously exposed in
window.__NUXT__payload until commit208638e. - Trigger the daily reconcile task once manually in Dokploy to confirm scheduled task + token are wired correctly. Expect a
[reconcile] done {...}log line.
Env vars required in Dokploy (reference):
NODE_ENV=productionBASE_URL(exact public origin, no trailing slash)MONGODB_URIJWT_SECRET(orNUXT_JWT_SECRET— theNUXT_variant wins)RESEND_API_KEYHELCIM_API_TOKENNUXT_HELCIM_MONTHLY_PLAN_ID=50302NUXT_HELCIM_ANNUAL_PLAN_ID=50303NUXT_PUBLIC_HELCIM_PORTAL_URLNUXT_RECONCILE_TOKEN(32+ char random string)SLACK_BOT_TOKENOIDC_COOKIE_SECRET
Fixed 2026-04-25
Day-of-launch security and correctness audit. All commit shas TBD until Phase 5.
CRITICAL (security)
- Fix #1 —
HELCIM_API_TOKENremoved from public runtime config + deaduseHelcim.jsdeleted. Token must be rotated post-deploy (was previously exposed viawindow.__NUXT__). - Fix #2 —
/api/helcim/customergated with origin check + per-IP/email rate limit + magic-link email verification (replaces unauthenticatedsetAuthCookie). - Fix #3 —
/api/events/[id]/paymentdeleted (dead code with auth bypass).processHelcimPaymentstub +eventPaymentSchemaremoved. - Fix #4 —
/api/helcim/initialize-paymentre-derives ticket amount server-side viacalculateTicketPrice; newseries_ticketmetadata type. - Fix #5 —
/api/helcim/customerupgrades existingstatus:guestmembers in place rather than rejecting with 409.
HIGH (correctness)
- Fix #6 — Recurring reconciliation: Netlify scheduled function calls
/api/internal/reconcile-paymentsdaily. RequiresNUXT_RECONCILE_TOKENenv var. - Fix #7 —
validateBeforeSave: falseadded to event subdoc saves (waitlist endpoints) to dodge legacy location validators. - Fix #8 — Series-pass purchase always creates a guest Member when caller is unauthenticated, mirroring event-ticket flow.
- Fix #9 —
cancel-subscriptionleaves statusactive(per ratified bylaws); addslastCancelledAtaudit field. - Fix #10 —
/api/auth/verifyusesvalidateBodywith.strict()Zod schema. - Fix #11 — Added 8 vitest cases for
cancel-subscription.post.js(was uncovered).
Side-quests
- Visual audit Phase 4 changes (events/series surface)
- Per-fix branch verification: see
docs/superpowers/specs/2026-04-25-fix-*.md
Manual browser tests still needed
None outstanding. All launch-blocking flows verified via local dev or cloudflared tunnel with real Helcim test card + real email (see archive for the full log). The one remaining browser verification is the staging test charge bundled into the Deploy checklist above.
Post-launch & deferred work
Bylaws decoupling, post-launch a11y, ASVS Phase 4, deferred features, simplify-pass follow-ups, known gotchas, wave-Slack pilot follow-ups — everything that isn't a deploy step has moved to BACKLOG.md.