Julian's admin operating system for shepherding Life Group Leaders and planning group launches. A web app for the ministry's oversight tiers — and, with the 2026-06 pivot, the Leaders they care for (ADR 0017). Built with Next.js (App Router) + TypeScript + Tailwind on top of Supabase (Auth + Postgres + RLS).
🌐 Live app: https://fvclifegroups.vercel.app/
✅ The pivot has landed (2026-06). The app is re-scoped to three areas — Care · Plan · Multiply (ADR 0016): that is the navigation spine, with the old number/assignment surfaces turned off behind Super-Admin nav flags (turned off, not deleted — their routes still resolve by direct URL). The decisions are recorded in ADR 0016–0021; the spec was PRD #371 (now closed), delivered across slices #372–#382. ADR 0024 then amended two defaults: the Groups and People management tabs are back in the admin nav (seeded on; the console can re-hide them), and Leader login is live — the verified
leader_surfaceflag now defaults on (ADR 0009's verify-before-flip checkpoint landed in #376/#382). The prior "three jobs" framing (Care, Launch Planning, Group Health) is superseded by ADR 0016; the original Q1–Q12 record lives on indocs/julian-inputs/SYSTEMS_CONVERSATION.md.
Julian (the Ministry Admin) oversees 60+ Life Group Leaders. The app's north star is three areas (ADR 0016) — each the focus of one job:
- Care — how my Leaders (and their members) are doing: an Over-Shepherd accordion, Leader Care Status, configurable A–F Group- and Leader-Health grades, and author-private Care Notes + Prayer Requests.
- Plan — the Interest Funnel: people interested in joining a group move Interested → Matched → Joined (or park as Not at this time), each with a Next Step and armed (provider-deferred) follow-ups.
- Multiply — whether to launch another group of a type (Men's / Women's / Mixed), read from four pillars (Capacity · Interest · Group Health · Leader Health) and a Julian-owned trigger.
Over-Shepherds log in to their own slice of Care, and Leaders log in to their
group-scoped care space (leader_surface defaults on per ADR 0024; the
Super-Admin console keeps the off-switch). The Groups and People
management tabs are back in the admin nav by default (ADR 0024); the remaining
pre-pivot surfaces (Planning, master calendar, guests, check-ins, …) stay
hidden behind Super-Admin nav flags — turned off, not deleted (ADR 0016).
"Done" is outcome-based, not a feature checklist: the app is done when it does Julian's three jobs reliably — now framed as the three areas. The pivot has landed (PRD #371, delivered across #372–#382); the table below records what each area delivers and what is live today.
| Area | What it delivers | Live today |
|---|---|---|
| Care | One Over-Shepherd accordion consolidating Leader-care + coverage + health grading; configurable A–F Group- and Leader-Health rubrics; author-private Care Notes + Prayer Requests; Leader/OS logins. | Live. The Over-Shepherd accordion, configurable A–F Group- and Leader-Health rubrics, author-private Care Notes + Prayer Requests (admins author too, ADR 0023), the aggregate Notes tab, and Leader/OS logins (ADR 0024) have all shipped. |
| Plan | The Interest Funnel — Prospects moving Interested → Matched → Joined / Not at this time — with a Next Step and armed follow-ups; replaces the Guests pipeline. | Live. The Interest Funnel has shipped at /admin/plan (over prospects), replacing the Guests pipeline (the legacy guests surface stays self-contained and off-nav, ADR 0033). Follow-ups are armed (shown as due tasks); actually sending one still awaits a provider (deliberately out of scope, #371). |
| Multiply | Multiplication by group type — pillars (Interest · Capacity · Group/Leader Health) + a Julian-owned trigger — instead of by individual group. | Live. Multiplication by group type — per-type pillars and a global → per-type readiness trigger — has shipped (#380, ADR 0019/0021 as collapsed by ADR 0034). |
In one line: the three jobs are unchanged in spirit but re-shaped into Care · Plan · Multiply (ADR 0016), with Over-Shepherds and Leaders logging in (ADR 0017, live by default per ADR 0024), configurable A–F health rubrics (ADR 0018), and multiplication by group type (ADR 0019/0021/0034). Delivered via PRD #371 and slices #372–#382; the old number/assignment surfaces are flagged off, not removed.
- 🔄 The pivot (current direction): ADRs
0016(Care/Plan/Multiply),0017(Leader/OS logins + Care Notes),0018(A–F rubrics),0019(multiplication by type),0020(Leader Care Note is group-scoped, amending 0017) — and PRD #371, sliced into #372–#382. CONTEXT.md— the domain glossary (Care Note, Prayer Request, Prospect, Over-Shepherd, Ministry Year, …). Use this vocabulary.docs/julian-inputs/SYSTEMS_CONVERSATION.md— ⭐ the original North Star: Julian's twelve questions. The pivot re-shapes these into Care/Plan/Multiply (ADR 0016); the Q&A remains the source of his words.docs/adr/0004-systems-conversation-architecture.md— the architecture decisions mapped to Q1–Q12 (pre-pivot).docs/README.md— the documentation index. Docs are limited to decision records (docs/adr/), the glossary, and navigation maps; everything point-in-time (plans, audits, reviews, the prior PRD) is retired to git history.
The app is an oversight operating system for the ministry's upper tiers. Roles form a strict downward-visibility ladder — each tier sees what the tier below sees, and more. There are two deliberate exceptions: the Ministry Admin's own Private Care Note (hidden even from the Super Admin; ADR 0002/0003) and the author-private Care Note (an OS's or Shepherd's note, readable by Julian only when he grants that person's transparency toggle; ADR 0017):
Super Admin ▸ Ministry Admin ▸ Over-Shepherd ▸ Shepherd
User-facing copy says Shepherd / Co-Shepherd (ADR 0025); the code
identity below — the leader / co_leader role enum values, leader_* RPCs,
and /leader routes — is deliberately unchanged. App-login roles live on
profiles.role (the user_role enum):
super_admin(Tom) — platform owner. Everything a Ministry Admin sees plus platform/account administration (/admin/super-admin). Bootstrapped manually (see Sign-in setup).ministry_admin(Julian) — all ministry/operational data. Lands on/admin. This is the primary persona.over_shepherd— a coach scoped to only the Shepherds they cover (viashepherd_coverage_assignments). Lands on/over-shepherd: a focused, coverage-scoped care surface, not/admin. Logs in today and writes author-private Care Notes + Prayer Requests about their Shepherds (ADR 0017, slice #381).leader/co_leader(shown to users as Shepherd / Co-Shepherd, ADR 0025) — re-opened (ADR 0017) and live by default (ADR 0024). A Shepherd logs in to a care surface over their group (group-scoped Care Notes + Prayer Requests + calendar, ADR 0020). The route + RLS re-audit landed with theleader_surfaceverified marker (verify-before-flip, ADR 0009, #376/#382); migration20260701020000seedsenabledon, so the surface is live. The Super-Admin console can switch it back off (Shepherds then land on/unauthorized); check-ins stay frozen behind their own gate.staff_viewer— deprecated. Retained in the SQL enum for backwards compatibility; routed to/unauthorized.
Two clarifications:
memberis not an app-login role. Members are non-auth participant records in thememberstable, linked to groups viagroup_memberships. They never sign in.group_memberships.roleis a separate enum (role_in_group:member | leader | co_leader) describing a person's role within a group, not their app-login role.
- Public:
/,/login,/forgot-password,/reset-password,/unauthorized. The landing page is a minimal sign-in entry point. - Protected (sign-in required), each with its own role gate via Supabase
Auth / RLS:
- Ministry/Super Admin — live nav spine (Home · Care · Plan · Multiply ·
Groups · People · Settings, the last two seeded on per ADR 0024):
/admin,/admin/care(+ the/admin/shepherd-care/**detail routes it links into),/admin/plan,/admin/multiply,/admin/groups(+/[groupId]and/[groupId]/calendar),/admin/people(+/[kind]/[personId]),/admin/settings./admin/super-adminis super_admin only; the rest acceptministry_adminandsuper_admin. - Ministry/Super Admin — off-nav, still resolve by direct URL (the
remaining pre-pivot surfaces, ADR 0016):
/admin/planning,/admin/launch-planning,/admin/leader-pipeline,/admin/follow-ups,/admin/guests,/admin/calendar,/admin/group-health. - Over-Shepherd —
/over-shepherd(+/[profileId]), scoped to covered Leaders. - Leader —
/leader(+/[groupId]/care,/[groupId]/calendar), live by default per ADR 0024 (the console can re-freeze it). - Frozen —
/admin/check-ins/**and/leader/[groupId]/checkin(check-ins stay behind their owncheck_insgate, reachable by direct URL, removed from nav).
- Ministry/Super Admin — live nav spine (Home · Care · Plan · Multiply ·
Groups · People · Settings, the last two seeded on per ADR 0024):
- Protected routes use a cookie-authenticated server client built with
@supabase/ssr. Every query runs through Row Level Security and is automatically scoped to the signed-in user. - Public preview routes always render typed fallback demo data; they do not call Supabase.
- When Supabase env vars are missing, protected routes redirect to
/loginand the preview routes still render demo data.
- No service role key in Next runtime code. All app-driven writes flow
through narrow
public.admin_*,public.leader_*, andpublic.super_admin_*SECURITY DEFINERRPCs, each writing a pairedaudit_eventsrow in the same transaction. The service role is confined to Supabase Edge Functions (invite-user,purge-profile-auth,redeem-invite,manage-test-auth-users). - No hard deletes outside RPC bodies in normal workflows; operational tables use soft-deactivation.
- Every table read uses explicit column allowlists — there are no
select("*")call sites. Shepherd-care,profiles, andmembersreads all select named columns (viaSESSION_PROFILE_COLUMNS,PROFILE_COLUMNS,MEMBER_COLUMNS, or inline column lists). The former broad-read debt is closed; keep it closed by adding only named-column reads. - Authorization is role-based — no Julian/Tom UUIDs or emails are hardcoded in code, migrations, or RLS.
- Install dependencies:
npm install
- (Optional) connect to a real Supabase project to see live data:
Without env vars, the app renders typed fallback demo data on every public preview page and redirects protected routes to
cp .env.example .env.local # then fill in NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY # (legacy NEXT_PUBLIC_SUPABASE_ANON_KEY is still accepted as a fallback)
/login. - Run the dev server:
npm run dev
npm run devnpm run lintnpm run typechecknpm run build
- Apply
supabase/migrations/20260517040000_phase2_schema.sql,supabase/seed/phase2_seed.sql, andsupabase/migrations/20260518000000_phase4_rls.sql(then later migrations in timestamp order). - Create one Supabase Auth user per seed profile email
(
avery.bennett@example.org,jordan.hayes@example.org,casey.morgan@example.org, etc.) with a development-only password. - Link each auth user to its profile row by following
supabase/dev/README.md. - Super admin bootstrap: create your own Supabase Auth user and link it to a
super_adminprofile by following the "Super admin bootstrap" section ofsupabase/dev/README.md. - Visit
/loginand sign in with the email + password you set.
Real users (e.g. Julian as ministry_admin, over-shepherds, additional leaders)
are invited from /admin/super-admin once a super_admin is signed in. (The
original walkthrough, SUPER_ADMIN_INVITE_USER_WORKFLOW.md, is retired; in git
history.)
- Schema migration:
supabase/migrations/20260517040000_phase2_schema.sql - RLS migration:
supabase/migrations/20260518000000_phase4_rls.sql - Seed file:
supabase/seed/phase2_seed.sql - Dev auth bootstrap:
supabase/dev/README.md - Schema docs:
docs/architecture/DATABASE_SCHEMA.md - Env vars are optional for build; required only for sign-in and live data.
Julian is the primary ministry_admin and operator persona used throughout
admin-facing copy. Tom holds the owner / super_admin account for bootstrap,
oversight, and emergency access.
Historical phase specs and verification logs have been retired to git history
(git log -- docs/archive) so this README stays focused on current state.