6.2 KiB
Launch Readiness
Status as of 2026-04-18. Target launch: before 2026-05-01.
Single source of truth for work that must happen before cutover. P0 blocks launch. P1 is strongly preferred but survivable. Completed items have been archived — see ~/.claude/projects/-Users-jennie-Sites-ghostguild-org/memory/project_launch_readiness_archive.md. Post-launch backlog lives in docs/TODO.md.
Current state
- Vitest: 577/577 passing.
- Helcim plan consolidation migration ran against prod 2026-04-18 (Monthly plan id
50302, Annual plan id50303). All six paid-flow manual tests pass via tunnel. - Remaining launch blockers: see lists below.
P0 — Must fix before launch
None outstanding. Privacy/Terms pages shipped, duplicate-customer bug fixed, pre-deploy migrations run.
P1 — Strongly preferred before launch
In-app billing management; demote Helcim portal to escape hatch
- Helcim's hosted portal requires a separate password the member never set during
/join. First-touch flow is "click link → see Helcim login → click Forgot password → wait for email → set password → sign in." Reads as broken. - Ship in-app equivalents for the 80% case:
- Past invoices / receipts list on
/member/account— new server route pulls from Helcim invoice API byhelcimCustomerId; render a simple list with date, amount, download/view link. - Change card — reuse
useHelcimPaycomposable to get a newcardToken, then new server route updates the customer's default payment method and the active subscription's payment method.
- Past invoices / receipts list on
- Keep the existing "Manage billing in Helcim →" link but relabel to something like "Advanced billing in Helcim →" so it reads as an escape hatch for disputes/edge cases, not the primary surface.
- Rough scope: 1–2 days. Two new
server/api/helcim/*routes + two new sections on/member/account.
Deploy checklist
Pre-deploy migrations have all been run. What's left:
- Merge
feature/helcim-plan-consolidationintomain. - Set
NUXT_HELCIM_MONTHLY_PLAN_ID=50302in Netlify production env. - Set
NUXT_HELCIM_ANNUAL_PLAN_ID=50303in Netlify production env.
Env vars required in production (reference):
MONGODB_URIJWT_SECRET(orNUXT_JWT_SECRET— theNUXT_variant wins)RESEND_API_KEYHELCIM_API_TOKENNUXT_HELCIM_MONTHLY_PLAN_IDNUXT_HELCIM_ANNUAL_PLAN_IDSLACK_BOT_TOKENBASE_URLOIDC_COOKIE_SECRETNUXT_PUBLIC_HELCIM_PORTAL_URL
Manual browser tests still needed
Cannot be verified by Vitest. All require a real browser + real Helcim test card + real email.
- Event ticket purchase with payment (HelcimPay.js iframe; use cloudflared tunnel or ngrok HTTPS).
- Pre-registrant invite → accept flow with paid tier (exercises Helcim customer creation during acceptance).
- Magic-link login including 15-min expiry and jti burn on reuse.
- Guest event signup — four branches: new email + consent, new email without consent, existing guest, existing active member. Confirms cookie only sets for new/guest, and confirmation email appends
/loginlink for real members. - Mobile responsive layout — sidebar hides ≤1024px, nav works on phone.
--text-dim/--text-faintWCAG AA contrast check.
Bylaws decoupling — follow-ups (added 2026-04-18)
Context: bylaws are being amended to remove automatic termination for nonpayment. Membership status will be fully decoupled from payment status; failed payments trigger committee outreach, not status change. Copy + UI access gates already aligned in useMemberStatus.js and account.vue (2026-04-18). Server-side status gating shipped as B2 (see archive). The behavioral changes below remain.
Not blocking launch — the amendment hasn't passed yet, and the user-visible copy/UI is already consistent. Pick up once the amendment is ratified.
B1. cancel-subscription flips status to pending_payment
server/api/members/cancel-subscription.post.js:31,48- When a member cancels their paid subscription, status is set to
pending_paymentand tier to'0'. Under the new model, cancelling a payment plan moves the member to the $0 tier — status should stayactive. - Fix: change
status: 'pending_payment'→status: 'active'in both thefindByIdAndUpdatepayload (line 31) and the response (line 48). Comment at line 26 also needs updating ("(not cancelled) so member can re-subscribe" → reflect new framing). - Add coverage in
tests/server/api/cancel-subscription.test.jsif it doesn't already exist.
B3. Vestigial pending_payment status
- Once payment is fully decoupled,
pending_paymentno longer gates anything and is functionally equivalent toactive. Consider removing it from the enum (server/models/member.js:38,server/utils/schemas.js:299) and treating new signups asactivefrom the moment of account creation. - Touches: signup flow (
helcim/customer.post.js:34,invite/accept.post.js:48), admin filter UI (app/pages/admin/members/index.vue:45,382,499,1145,[id].vue:69,286), admin alerts (server/utils/adminAlerts.js:22,100-116,server/models/adminAlertDismissal.js:6), and a data migration to flip existingpending_paymentrows toactive. - Larger refactor — break out into its own ticket once B1 lands.
B4. Admin "Pending Payment" filter label (cosmetic)
app/pages/admin/members/index.vue:45,499,[id].vue:69showpending_paymentas "Pending Payment". If B3 removes the status entirely, this disappears too. If we keeppending_paymentfor now, rename in admin UI to "Payment setup incomplete" so admins also stop conflating it with membership state.
Post-launch backlog
See docs/TODO.md for:
- Button minimum target size (WCAG AAA 2.5.5).
/oidc/interaction/[uid]routing quirk.- Admin layout migration from
guild-*tokens to zine spec. - Admin dashboard quick-action button contrast.
- Members table NAME column clipping.
- OWASP ASVS L1 Phase 4 (file-upload validation pipeline, granular RBAC, credential encryption).
tickets/available.get.js:115memberSavingsblock reports$0 savedfor inactive members — cosmetic; suppress comparison block when!hasMemberAccess(member)if it ever surfaces in UI.