Data Access Guide
Blue North is standardizing on Supabase/Postgres as the system of record. The database should hold accounts, campaigns, campaign memberships, voters, districts, turfs, contact history, schedules, admin audit logs, and related production data.
Rule Of Thumb
UI should not call Supabase all over the app. Prefer focused data-access modules owned by a feature.
Good:
features/campaigns/data/campaigns.repo.ts
features/voters/data/voters.repo.ts
features/turf/data/turfs.repo.ts
Avoid:
components/some-panel.tsx calls supabase.from("campaign_memberships") directly
components/another-card.tsx repeats the same query
Supabase Client Helpers
Client creation lives in:
platform/lib/supabase/client.ts
platform/lib/supabase/server.ts
platform/lib/supabase/middleware.ts
platform/proxy.ts
Use the browser client only in client components that truly need client-side auth or realtime behavior. Use the server client for server components, route handlers, and server actions.
Multi-Tenant Access
Production data is campaign-scoped. Most tables should include campaign_id, and queries should always be written with the active campaign in mind.
Database-level Row Level Security is the final safety net:
profiles
campaigns
campaign_memberships
voters
voter_lists
turfs
contact_attempts
audit_events
The app should still pass explicit campaign context for clarity and performance.
Repository Shape
Repository modules should expose named functions with business meaning:
export async function listCampaignsForCurrentUser()
export async function createCampaign(input)
export async function getVotersPage(input)
export async function saveTurf(input)
They should hide table names, Supabase query details, and mapping between database rows and UI models.
Migrations
All database schema changes belong in:
platform/supabase/migrations
Migration expectations:
- include indexes for common query paths
- enable RLS for campaign-owned data
- avoid destructive changes without a documented rollout plan
- prefer expand/backfill/contract for large tables
Current Transition State
The app still has legacy static-data and localStorage paths. That is expected during the transition.
When moving a surface to Supabase:
- Define the database table or migration.
- Add a feature-owned repository.
- Update UI to call the repository/server route.
- Keep sandbox fallback behavior explicit.
- Verify build and preview deploy.
Recommended first production migrations after auth:
- campaign creation and membership onboarding
- saved voter lists
- saved turfs and turf memberships
- contact attempts