ForgeKitFORGEKIT

Build Log

MedinaCHF — Onboarding Simplification, a Self-Hosted Invite Email, and a Live Production Outage Fixed

August 28, 2026

Courtney's live-member-test brief asked for less friction between invitation and Member Home. Building it surfaced that Clerk's invitation email needs a paid plan to customize, which led to a bigger decision (create Clerk accounts directly, send our own email) that a real account-deletion bug and a Crucible council review both caught and fixed before it shipped. A live production 500 (a missing table from an unrelated prior session) was found and fixed mid-session using the same evidence discipline. Two smaller features (RSVP manual correction, membership-progress event list) and two small bug fixes closed out the session.

MedinaCHFOnboardingClerkCrucibleProduction Incident
2
real bugs found and fixed in the new account-creation logic before deploy (one could have deleted a real member's Clerk account)
1
live production outage found via real Vercel logs and fixed (missing admin_intents table, unrelated to this session's own changes)
4
separate feature/fix threads shipped and deployed: onboarding simplification, self-hosted invite email, RSVP manual correction, and two small UI bug fixes

Timeline

Start
Charge received from Courtney via Zeb: simplify onboarding after a live member test
Remove the /welcome install-choice screen and the first-login Getting Started card; route straight to Member Home
Build
Removed /welcome and GettingStartedCard, relocated Add-to-Phone into Help
Verified via real tsc + production build + live curl checks against the deployed routes
Scope growth
Zeb asked whether the invitation email could be customized — Clerk's template requires a paid plan
Investigated, then Zeb chose to create Clerk accounts directly and send ForgeKit's own email instead of upgrading Clerk
Bug found
A real Clerk account created with the notification email held back has no adults.clerkUserId until the member signs in
An earlier version of the shared helper treated that null as 'no account exists' and would have called the orphan-cleanup function, deleting the real account on a later retry
Crucible
Ran crucible:council (architect + qe) on the account-creation design before deploying
Council flagged the same fail-open pattern recurring in a second function (updateMemberOnboardingStatus) and called for one shared, fail-closed Clerk-lookup helper
Fix + deploy
Centralized the Clerk-existence check into resolveClerkAccountForEmail, fails closed on API uncertainty
tsc + production build re-verified clean, deployed to medinachf.forgekits.build
Live incident
Zeb reported /coordinator/settings throwing a live error mid-session
Pulled real Vercel production logs first — found relation "admin_intents" does not exist, a table defined in schema.ts by a prior session but never pushed to production
Fixed + verified
Pushed the missing table to production, independently confirmed via information_schema, confirmed the live page recovers
Root cause predates this session entirely — surfaced only because Courtney/Zeb happened to load that page
Feature
Added coordinator RSVP manual add/remove, mirroring the existing attendance-correction pattern
Mainly for correcting completed-event records — coordinator-only, org+event scoped
Close
Two small bug fixes along the way (a mislabeled button, the Add Member panel's width/required-field visibility)
All four feature threads verified and deployed to production before this retro was written

What shipped

products/medinaCHF/app/member/layout.tsx, app/member/page.tsx — removed the /welcome redirect and the Getting Started card; a newly onboarded member lands directly on normal Member Home

products/medinaCHF/app/welcome/page.tsx, components/GettingStartedCard.tsx — deleted entirely

products/medinaCHF/app/member/help/page.tsx — relocated AddToPhoneButton here as an optional resource

products/medinaCHF/lib/emails/member-account-ready.ts — new self-hosted HTML/text invitation email matching Courtney's copy

products/medinaCHF/lib/email.ts — added sendHtmlEmail

products/medinaCHF/lib/actions/member-management.ts — createMemberAccountDirect, createClerkAccountForAdult, resolveClerkAccountForEmail, updateMemberOnboardingStatus; createMemberManually now always creates the Clerk account inline with an optional sendAccountEmail flag

products/medinaCHF/components/coordinator/AddMemberButton.tsx — 'Send account email now' checkbox, wider panel, visible required-field markers

products/medinaCHF/components/coordinator/MemberDetailPanel.tsx — 'Send Account Email (ForgeKit)' button, manual onboarding-status override control

products/medinaCHF/tests/e2e/armory/coordinator-member-management.spec.ts — updated for the new Add Member button label/checkbox, added a held-back-email regression test

products/medinaCHF/lib/db/schema.ts — admin_intents table pushed to production (fix for a live outage; schema itself predates this session)

products/medinaCHF/lib/actions/rsvp.ts — recordRsvpForFamily, removeRsvpRecord

products/medinaCHF/components/coordinator/RsvpEditor.tsx — new coordinator RSVP add/remove UI

products/medinaCHF/app/coordinator/events/[id]/page.tsx — wired in RSVP add/remove, removed dead RSVP_LABEL constant

products/medinaCHF/lib/queries/attendance.ts — listCountedAttendanceEventsForFamily

products/medinaCHF/components/CountedEventsSection.tsx — 'Events That Counted This Year' on Plan Something

products/medinaCHF/app/member/planning-board/page.tsx, app/member/page.tsx — wired in the counted-events list and its Home deep-link; fixed 'View My Membership' button label to 'View My Profile'

what the fuck. just delete it already. you have my permission.

Zeb, mid-session, after a self-inflicted concurrency-tooling deadlock (s1) that turned out to require no file deletion at all — resolved by dropping a shell habit (`cd ... &&`), not by touching the file in question