1 The model: one door, one identity
One login screen. /login is the ONLY place anyone signs in or creates an account (email + password or magic link). Home-page "Login" and "Join Free" both point here.
The Gate steps out of the way. /gate stops being a sign-in step. It becomes only two things: the bouncer that catches a signed-out visitor who deep-links a locked page (and sends them to /login), and the VIP-code door for invited guests. A signed-in member never sees it. This is what kills the "sign in twice" wall you hit.
One source of truth for who you are. Your Supabase profiles.role field. One value per user. Everything — where you land, what you can open — reads from that single field.
2 The six roles → what the database calls them → where they land
| Role | DB value (profiles.role) | How they get it | Lands on |
|---|---|---|---|
| Basic Free User | member | Self-serve free sign-up (default for everyone) | Member Home — /network-overview/ |
| Ambassador | ambassador | Stripe $49/yr · invite code · admin grant | Ambassador Home — /for-ambassadors/ + Share-It kit |
| Group Leader | group_leader | Stripe $99/yr · invite code · admin grant | Group dashboard — /for-community-leaders/ |
| Regional Chamber Director | director | Estimate → contract · invite code · admin grant | Director Console — /chamber-director-console/ (region, CRM pre-loaded) |
| State Chamber Director | state_director | Estimate → contract · invite code · admin grant | Director Console — state rollup view of the regions under them |
| Advisor | advisor (NEW) | Admin invite only — not self-serve | Advisory library — /leadership-and-advisory/ |
| Super Admin (you + Dr. Rob) | super_admin | Permanent allowlist | Demo Dashboard w/ role switcher — /demo-dashboard/ |
| Reviewer / VIP guest | reviewer | VIP code at the Gate | Network overview (coach experience) |
Regional vs State: both use the same Console page; the difference is scope — a State Director sees the regional directors beneath them. (Your DB also has community_director, school_district, and healthcare_workforce tiers already defined — room to grow without schema changes.)
3 The flow, start to finish
Arrive
Home "Join Free" / "Login" — or a locked page bounces a signed-out visitor. Every path lands on /login, carrying ?next= if they were headed somewhere specific.
Authenticate
New user → Create Account (password or magic link) → Supabase creates the user + a profiles row defaulting to role = member. Returning user → Sign in.
First-timer? → Activation Journey
If the profile has no first name yet, route to /activation-journey/ — welcome → personalize-or-skip → "for myself vs as a leader" fork → optional plan. Finishing sets their name and (if they chose/paid) their tier.
Role router — the fix
Once authenticated with a completed profile, /login reads profiles.role and sends them straight to that role's home using one shared map. No detour through the Gate. This is the single change that makes it "butter smooth."
Upgrades
A free member becomes a paid role three ways: pays via Stripe (activation-journey plan step), redeems an invite code (redeem_invite_code RPC via /redeem/), or a Super Admin grants it. Next load, they're routed and gated as the new tier.
Every page enforces
role-gate.js reads profiles.role and: lets any signed-in role onto normal pages; restricts Director / State / Advisor consoles to those tiers (+ admin); keeps Super-Admin pages admin-only. You and Dr. Rob are allowlisted everywhere.
4 What must be wired to make this real
/login role router
After a successful sign-in, route by profiles.role instead of bouncing to the Gate. Also fixes the double-gate you're hitting now.
Teach role-gate.js the paid tiers
Right now ambassador / group_leader / director / state_director would be wrongly blocked on normal member pages — the gate only recognizes member/reviewer/super_admin. Add the five tiers + a rank so higher tiers inherit lower access. This is a live bug, not just a nicety.
Add the Advisor tier
One SQL line to add advisor to the invite-codes check + a code, and confirm Regional = director, State = state_director.
One shared role → home map
A single tiny file both /login and /gate read, so landing destinations never drift apart again.
Stripe products + webhook
Ambassador $49 / Group Leader $99 / Director estimate. Webhook sets profiles.role on payment. Until wired, invite codes mint every role — so testing doesn't wait on Stripe.
5 The test — role by role, runnable today
FFH-AMBASSADOR-2026, FFH-GROUP-2026, FFH-DIRECTOR-2026, FFH-STATE-DIR-2026, FFH-VIP-2026. Add: FFH-ADVISOR-2026 → advisor.
/gate/?reset=1 and sign out of Supabase so each role starts clean.1 · Basic Free User tap to open ▾
2 · Ambassador tap to open ▾
3 · Group Leader tap to open ▾
4 · Regional Chamber Director tap to open ▾
5 · State Chamber Director tap to open ▾
6 · Advisor tap to open ▾
7 · Super Admin (you) tap to open ▾
Tip: run tests in an incognito window so sessions don't bleed together. A failed row is a to-do, not a dead end — send me the row and I'll fix it.