Lib Directory
Location: src/lib/
Purpose: Shared utility libraries — Supabase client setup, permission helpers, static data, and small pure helpers. This is the only place where service-role / edge-side primitives are defined.
Structure
lib/
├── acessControl/ # (Legacy) feature-access checking
│ └── canAccessFeature.ts
│
├── constants/
│ └── superAdmin.ts # SUPER_ADMIN_TEAM_ID (server-only constant, hydrated to TeamsContext)
│
├── data/ # Static reference data
│ ├── california-counties.ts
│ ├── jurisdictionType.ts
│ ├── permissions/
│ │ ├── campaign-sub-groups.ts
│ │ ├── primary-groups.ts
│ │ └── standard-permissions.ts
│ ├── us-states.ts
│ └── usTimeZones.ts
│
├── email/ # Server-only email helpers
│ ├── invitation-email-templates.ts # HTML templates for team / campaign invites
│ └── send-invite-email.ts # Wraps the `send-email` Supabase Edge Function
│
├── permissions/
│ └── fetchPermissionsSnapshot.ts # Edge-safe `fetch` against get-permissions-snapshot (Next.js fetch cache + tags)
│
├── supabase/ # Supabase clients + session middleware
│ ├── check-env-vars.ts # Validates required env vars at startup
│ ├── client.ts # Browser client (anon key)
│ ├── server.ts # SSR client (anon key, cookie-aware)
│ ├── specialServer.ts # Service-role client (server-only)
│ └── updateSession.ts # Edge middleware logic — session sync + permissions cache invalidation
│
├── chartUtils.ts # Helpers consumed by recharts wrappers
├── cn.ts # `cn(...)` clsx + tailwind-merge
├── date-utils.ts # Date formatting / coercion
├── extractIdsFromPath.ts # Pulls teamId / campaignId out of a URL pathname
├── formatNumber.ts # Locale-aware number formatting
├── getFilterPetColumns.ts # Petition table column selectors
├── getPetitionContextData.ts # Hydrates the petition context for a route
├── getRedirectUrl.ts # Cleans / normalizes the post-login redirect URL
├── getUtcMidnight.ts # Helper for `created_at`-based date filters
├── petition-utils.ts # Petition-specific helpers
├── redis.ts # Singleton Upstash Redis connection + signer set helpers
├── server-utils.ts # `createSuccessResponse` / `createErrorResponse` for FormState
├── team-member-hierarchy.ts # `roles.hierarchy_level` lookups + `canActOnHierarchyLevel`
├── use-forwarded-ref.tsx # Compose forwarded refs
├── utils.ts # `encodedRedirect`, contrast color, percentage format, keyboard helpers, etc.
└── validateDateInput.ts # Date input field validators
Highlights
Supabase clients
supabase/client.ts— browser-side, anon key. Use in client components only.supabase/server.ts— RSC / Route Handler client, anon key, cookie-aware via@supabase/ssr. Use in Server Components, Server Actions, and Route Handlers.supabase/specialServer.ts— service-role client. Server-only. Used byapp/api/charts/[id]/route.tsand any internal job that must bypass RLS.supabase/updateSession.ts— invoked by the edge middleware. Refreshes Supabase cookies (getClaims()to avoid a network call), redirects unauthenticated requests to/auth/sign-in, and on a real browser refresh hits/api/permissions/revalidateto drop the cached permissions snapshot.
Permissions
lib/permissions/fetchPermissionsSnapshot.ts— edge-safe loader. Hits theget-permissions-snapshotSupabase Edge Function viafetch(...)with Next.js fetch caching (revalidate: 3600,tags: [permissions-${userId}]). Safe to import from middleware, route handlers, server actions and RSC.lib/constants/superAdmin.ts— definesSUPER_ADMIN_TEAM_ID. Server-only. Client code reads it throughTeamsContext.superAdminTeamId.
Redis
lib/redis.ts lazily creates a TLS connection to Upstash and exposes:
getRedisConnection()/resetRedisConnection()— singleton management with reconnect onECONNRESET/Connection is closed.addSignerToCampaignRedis(campaignId, voterId)/removeSignerFromCampaignRedis(...)— operate on thecampaign:{id}:signersset.- Process-level
SIGTERM/SIGINThandlers gracefullyquit()the client.
Hierarchy
lib/team-member-hierarchy.ts is the canonical place to read roles.hierarchy_level for a given user/team. canActOnHierarchyLevel(actor, target, isSuperAdminPrimary) is used by all member-management actions to forbid sideways or upward role changes. See complex-logic/role-hierarchy.
Email
lib/email/invitation-email-templates.ts— HTML templates for team / sub-team invites.lib/email/send-invite-email.ts— thin wrapper aroundsupabase.functions.invoke("send-email", ...).