ghostguild-org/docs/BACKLOG.md
Jennie Robinson Faber 33ba082b82
Some checks failed
Test / vitest (push) Successful in 11m7s
Test / playwright (push) Failing after 9m38s
Test / visual (push) Failing after 9m31s
Test / Notify on failure (push) Successful in 2s
docs: consolidate open issues into BACKLOG.md
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.
2026-04-30 15:37:26 +01:00

100 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Ghost Guild — Open Backlog
_Last consolidated: 2026-04-30. Single source of truth for every open issue across the codebase. Pulls from `LAUNCH_READINESS.md`, `TODO.md`, the post-launch backlog memory, and a fresh sweep of in-code TODO/FIXME comments._
Cutover has not happened yet. Deploy steps live separately in [`LAUNCH_READINESS.md`](./LAUNCH_READINESS.md).
---
## Pre-cutover (do once)
Operational steps that have to run during cutover. Full details + env-var list in [`LAUNCH_READINESS.md`](./LAUNCH_READINESS.md).
- [ ] Provision the Dokploy app, set env vars (full list in LAUNCH_READINESS.md), confirm `BASE_URL` exact-matches the public origin and `NODE_ENV=production`.
- [ ] Add the daily Dokploy Scheduled Task that POSTs to `/api/internal/reconcile-payments` with `X-Reconcile-Token`.
- [ ] **Run `node scripts/migrate-contribution-amount.cjs --apply` against prod Mongo BEFORE the new code serves traffic.**
- [ ] Set `NUXT_HELCIM_MONTHLY_PLAN_ID=50302` and `NUXT_HELCIM_ANNUAL_PLAN_ID=50303` in Dokploy.
- [ ] Set `NUXT_RECONCILE_TOKEN` to a 32+ char random string.
- [ ] Push local `main` to `origin/main`.
- [ ] Deploy.
- [ ] **Run `node scripts/reconcile-helcim-payments.mjs --apply` against prod Mongo AFTER the new code serves traffic.**
- [ ] Audit prod for pre-fix series-pass bypass registrations (registrations on pass-only series children with `registeredAt < 2026-04-20` from non-pass-holders). Decide per case.
- [ ] In Helcim dashboard: disable the default payment-confirmation email for plans 50302 + 50303 (we send our own CRA-safe version via Resend).
- [ ] Run one real test charge and verify (a) Payment doc in Mongo and (b) exactly one CRA-compliant confirmation email.
- [ ] Rotate `HELCIM_API_TOKEN` in the Helcim merchant portal and update the Dokploy env var.
- [ ] Trigger the daily reconcile task once manually in Dokploy to confirm it's wired correctly.
## Pilot smoke walks (before first wave)
Once cutover lands, before the first Slack onboarding wave goes out:
- [ ] **Pilot smoke walk for Slack-invited workflow.** One admin manually clicks "Mark as Slack invited" against a real test member in production, confirms the row updates in place, and confirms the dashboard "Slack coming" note disappears for that member. Unit tests cover the pieces; nothing covers the live admin-to-member round-trip.
---
## Bylaws-decoupling (waiting on amendment ratification)
Membership status is being decoupled from payment status. Copy + UI gates already align; behavioral changes below remain.
- [ ] **B1.** `server/api/members/cancel-subscription.post.js:31,48` flips status to `pending_payment` on cancel. Under the new bylaws, cancellation should keep status `active` (just zero contribution). Update the `findByIdAndUpdate` payload + response, the comment at line 26, and add coverage in `tests/server/api/cancel-subscription.test.js`.
- ~~B3 cancelled.~~ `pending_payment` stays.
- ~~B4 admin "Pending Payment" → "Payment setup incomplete"~~ shipped 2026-04-29 (`59d2be2`).
---
## Known gotchas (post-launch)
- **Admin edit does not sync Helcim `recurringAmount`.** `/admin/members/[id]` PUT writes `contributionAmount` direct to Mongo by design. Admins must PATCH Helcim manually. The admin form already shows an `--ember`-bordered notice (commit `e756170`); a real sync flow is a future enhancement.
- **Cadence switch rejected on active subscriptions.** `server/api/members/update-contribution.post.js:206` refuses cadence changes mid-subscription with a TODO comment pointing here. No UI toggle exists on `/member/account`. Adding cadence switch requires a Helcim subscription replacement flow, not a plain update.
- **S2 test fixture id/slug mismatch (local dev only).** Seeded S2 series has `id: 'test-s2-drop-in-allowed'` but `slug: 'test-s2-drop-in-allowed-series'`. Doesn't affect prod — fix the seed script if anyone re-runs fixtures.
---
## Accessibility / a11y
- [ ] **Button minimum target size.** Site-wide `.btn` renders ~35px tall. WCAG AA 2.5.8 (24×24) passes; AAA 2.5.5 (44×44) fails. Bumping padding affects every button — design call, not a drop-in fix. Flagged 2026-04-11.
---
## Deferred features (own session each)
- [ ] **Email automation system.** Patterned after Tranzac's implementation (separate project, already built). HTML email bodies with template management and drip sequences. Deferred 2026-04-20 — ruled wasted work given the larger system is designed elsewhere. Current transactional email lives in `server/utils/resend.js` + inline in `server/api/auth/login.post.js`, `server/routes/oidc/interaction/login.post.ts`, `server/api/admin/{members,pre-registrants}/invite.post.js`. Copy dump at `docs/email-copy-dump.md`. See memory: `project_email_automation_future`.
- [ ] **Receipts for event ticket purchases (Phase 2).** Phase 1 receipts only cover membership payments. Event tickets — especially guest purchases without member accounts — need a receipt flow. Likely an emailed PDF/HTML receipt at purchase time. Build target: JuneOct 2026, live Jan 2027. See memory: `project_receipts`.
- [ ] **Series/event waitlist.** Admin can configure `tickets.waitlist.enabled` and `maxSize`; `server/utils/tickets.js` returns `waitlistAvailable: true` when full; `app/components/SeriesPassPurchase.vue:341` and `EventTicketPurchase.vue` have stub `handleJoinWaitlist` that toasts "Waitlist Coming Soon." No server endpoint, no confirmation email, no `event_waitlisted` activity hook. Either implement end-to-end or hide the button by removing the `v-if="availability?.waitlistAvailable"` branches in `EventSeriesTicketCard.vue:175` and `EventTicketCard.vue:73`.
- [ ] **ASVS Phase 4.** File-upload validation pipeline, granular RBAC, credential encryption.
---
## Wave-Slack pilot follow-ups
- [ ] **E2E coverage for `e2e/wave-slack-onboarding.spec.js`.** 16 scaffolded tests, all `.skip`ed with TODOs. Filling them in needs fixture work the spec didn't scope. Test 7.8 (final copy match) and 6.9 (sortable column / "no Slack yet" filter) gated on Open Questions in the test plan. Defer until pilot wraps unless a regression surfaces.
- [ ] **Pilot exit decision (~8 weeks post-launch).** Either restore `server/_archive/utils/checkSlackJoins.js` + its plugin if polling is needed, or delete the archive permanently. Driven by whether the manual-invite cadence is sustainable post-pilot.
- [ ] **`slack_invite_failed` enum slug cleanup.** Detector and alert removed in `d15458b`, but the slug remains in `server/models/adminAlertDismissal.js` enum so historical dismissal rows continue to validate. Full removal needs a one-shot cleanup of stale dismissal rows in the DB. Roll into a future schema-tidy pass.
---
## Simplify-pass follow-ups (still open)
Items surfaced during the 2026-04-29 /simplify review. The 2026-04-30 small-wins batch shipped 3 items (STATUS_LABELS dedup, ImageUpload focus, signupBridge rename). Remaining:
- [ ] **Extract `.tint-candle` / `.tint-ember` utility classes.** The `color-mix(in srgb, var(--candle) 15%, transparent)` + matching border pattern is now inlined as `style=""` in ~9 sites across `EventSeriesTicketCard.vue`, `SeriesPassPurchase.vue`, `NaturalDateInput.vue`, `ImageUpload.vue`. Promote to utility classes in `app/assets/css/main.css` so future tints don't keep multiplying inline styles (and so `:hover` / `:focus` variants are reachable).
- [ ] **Audit `member &&` truthy checks in sibling ticket/subscription routes.** Commit `f66455e` fixed `server/api/events/[id]/tickets/available.get.js:115` to use `hasMemberAccess(member)`. Same anti-pattern likely exists in adjacent routes (`tickets/purchase.post.js`, subscription endpoints). Guests/suspended/cancelled members would currently look like full members for any feature gated on truthiness alone.
---
## Optional / low-priority
- [ ] **Welcome-email Slack-timing mention.** Currently the welcome email doesn't mention Slack timing — the dashboard carries that note. Could add a one-line "Slack invitation comes in monthly waves — there may be a short wait" if the dashboard turns out not to be enough signal.
---
## Deeplink memories
- `project_post_launch_backlog.md` — high-level digest of this file
- `project_launch_readiness.md` — cutover status (NOT YET happened)
- `project_launch_flow_map.md` — onboarding flow + Slack wave model
- `project_pre_registrants.md` — invitation system + pre-reg lifecycle
- `project_helcim_plan_model.md` — cadence-keyed plan model
- `project_contribution_amount_redesign.md` — arbitrary $ amount + guidance presets
- `project_receipts.md` — Phase 1 done, Phase 2 pending
- `project_email_automation_future.md` — Tranzac reference for full system