ForgeKitFORGEKIT

Build Log

Hearth: Phase 4 — Invite Flow

June 22, 2026

Courtney can now join the household. Prod DB split, schema pushed, invite flow live at home.forgekits.build.

HearthMulti-memberAuthDeployDB
1
new DB table
3
access helpers
5
new files
1
prod DB split

Timeline

Start
Ignition + orientation
Read Phase 3 retro, schema, access.ts, proxy.ts
20m
invites table + helpers
Schema addition, createInvite / getInvite / consumeInvite in access.ts
40m
Settings page + InviteSection
Server component with real members list, client invite UI with profile selector
55m
/invite/[token] accept page
Public route, Clerk redirect-back, AcceptInviteButton client component
1h
proxy.ts public route
Added /invite/(.*) to public routes — Clerk was blocking the accept page
1.1h
Prod DB decision + split
New Neon project for prod, Vercel env var updated
1.25h
Schema push + seed + backfill
db:push → db:seed → db:backfill against prod via inline DATABASE_URL
1.5h
Local test + Google OAuth fix
Google test user added, port mismatch (3000 vs 3001) resolved
1.75h
Commit + deploy
tsc clean, build clean, live at home.forgekits.build

What shipped

lib/db/schema.ts — invites table: token, householdId, role, profileId, expiresAt, status, acceptedByUserId

lib/access.ts — createInvite(): 32-byte hex token, 7-day expiry

lib/access.ts — getInvite(token): validates pending + not expired

lib/access.ts — consumeInvite(): creates householdMembers row, links profile, idempotent

app/(dashboard)/settings/actions.ts — generateInviteAction: auth bridge + createInvite + URL construction

app/(dashboard)/settings/page.tsx — real server component: auth, members list, InviteSection

components/settings/InviteSection.tsx — client: profile selector, generate button, copyable URL

app/invite/[token]/page.tsx — public accept page: invalid/expired state, sign-in redirect, join UI

app/invite/actions.ts — acceptInviteAction: Clerk displayName, consumeInvite, redirect /today

components/invite/AcceptInviteButton.tsx — client: pending state, error display

proxy.ts — /invite/(.*) added to public routes

Courtney can join now. The household is real.

Session close