Knowledge > Integrations > Supabase
Supabase Integration
Supabase is the single shared database for the entire ChurchWiseAI portfolio. All three codebases and the voice agent Python service connect to the same Supabase project. There is no staging database and no local development database — every query in every environment hits production data directly.
Account Info
| Field | Value |
|---|---|
| Project ID | wrwkszmobuhvcfjipasi |
| Project URL | https://wrwkszmobuhvcfjipasi.supabase.co |
| Region | (managed by Supabase) |
| Auth providers | Email/password + Google OAuth (for SermonWise/ShareWiseAI and ITW) |
| MCP plugin | mcp__plugin_supabase_supabase__execute_sql and related tools |
How Used Per Product
| Product | Codebase | Supabase Usage |
|---|---|---|
| ChurchWiseAI admin + APIs | churchwiseai-web | Premium church data, voice call logs, requests, chatbot config, team members, analytics |
| Voice agent | churchwiseai-web/voice-agent-livekit (Python) | Church config lookup, call log writes, prayer/visitor/callback inserts, product knowledge reads |
| SermonWise AI | churchwiseai-web | profiles table, Supabase Auth for login/signup |
| ShareWiseAI | churchwiseai-web | profiles + social_subscriptions tables, Supabase Auth |
| PewSearch directory | pewsearch/web | Church listings (churches), premium page data, congregation care, voice data |
| IllustrateTheWord | sermon-illustrations | unified_rag_content (illustrations), profiles (Supabase Auth), dir_illustrations view |
| Chatbot + RAG | churchwiseai-web | unified_rag_content (327K rows), product_knowledge, church_knowledge_base |
Key Environment Variables
| Variable | Scope | Used By |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL | Client + Server | All 3 Next.js codebases, middleware |
NEXT_PUBLIC_SUPABASE_ANON_KEY | Client + Server | All 3 Next.js codebases — RLS-respecting queries, auth |
SUPABASE_SERVICE_ROLE_KEY | Server only | All 3 codebases — bypasses RLS for admin mutations |
SUPABASE_URL | Python env | churchwiseai-web/voice-agent-livekit — Python client init |
Note: The Python voice agent uses SUPABASE_URL (without NEXT_PUBLIC_ prefix) and SUPABASE_SERVICE_ROLE_KEY.
Key Tables
| Table | Rows | Owner | Purpose |
|---|---|---|---|
churches | 261K total (~218K visible) | PewSearch | Church directory. Use directory_visible=true filter for public counts — NEVER use 261K as the public number |
unified_rag_content | ~327K | ChurchWiseAI/ITW | All RAG content (illustrations, sermons, FAQs, knowledge). IRREPLACEABLE — never bulk delete |
premium_churches | 4 (all test) | PewSearch/ChurchWiseAI | Premium subscriptions, plan tier, admin tokens, church customization data |
church_voice_agents | varies | ChurchWiseAI | Voice agent config per church, Twilio number, greeting, features enabled |
voice_call_logs | varies | ChurchWiseAI | Call transcripts, AI summaries, duration |
voice_prayer_requests | varies | ChurchWiseAI | Prayer requests from voice AND chatbot (legacy name — shared channel) |
voice_callback_requests | varies | ChurchWiseAI | Callback requests from voice AND chatbot |
voice_visitor_contacts | varies | ChurchWiseAI | Visitor contact captures from voice AND chatbot |
organization_settings | varies | ChurchWiseAI | Chatbot config per church |
profiles | varies | ChurchWiseAI | User profiles for Supabase Auth users (SermonWise, ShareWiseAI, ITW) |
product_knowledge | varies | ChurchWiseAI | Runtime Q&A injected into chatbot and voice agent system prompts |
church_knowledge_base | varies | ChurchWiseAI | Uploaded documents for chatbot RAG |
congregation_care_members | varies | PewSearch | Care broadcast subscribers |
church_team_members | varies | PewSearch/ChurchWiseAI | RBAC team members with role-based access tokens |
sai_theological_lenses | 18 | All | 17 theological traditions + universal lens |
denominations | varies | PewSearch | Denomination taxonomy with church counts |
dir_illustrations | varies | ITW | Read-only view of unified_rag_content filtered to illustrations |
contact_submissions | varies | PewSearch | Contact form submissions from Pro Website |
social_subscriptions | varies | ChurchWiseAI | ShareWiseAI subscription records |
Client Usage Patterns
TypeScript / Next.js (churchwiseai-web)
Two clients with different privilege levels:
// Server-only — service role bypasses RLS. Import from '@/lib/supabase'
import { supabase } from '@/lib/supabase';
// Middleware — uses anon key with SSR cookie handling
import { createServerClient } from '@supabase/ssr';
The supabase export in churchwiseai-web/src/lib/supabase.ts uses the service role key and is marked server-only. Never import it from a 'use client' component.
TypeScript / Next.js (pewsearch/web)
PewSearch has two named exports:
// supabase — anon key, respects RLS
// supabaseAdmin — service role key, bypasses RLS
import { supabase, supabaseAdmin } from '@/lib/supabase';
Python (voice agent)
from supabase import acreate_client # async client
url = os.environ.get("SUPABASE_URL", "")
key = os.environ.get("SUPABASE_SERVICE_ROLE_KEY", "")
supabase = await acreate_client(url, key)
The voice agent uses an async Supabase client (acreate_client) and maintains a singleton via get_supabase() in session.py. The client is lazily initialized on first call.
CLI Patterns & Gotchas
Default 1000-Row Limit
Supabase PostgREST returns at most 1000 rows by default. Always paginate for large tables:
// Paginate with .range()
const { data } = await supabase
.from('churches')
.select('id, name')
.range(0, 999); // page 1
// Or use count to check total
const { count } = await supabase
.from('churches')
.select('*', { count: 'exact', head: true })
.eq('directory_visible', true);
Church Count
Always query with directory_visible=true filter. The raw row count (~261K) includes hidden entries. The public-facing number is ~218K (directory_visible churches). Agents repeatedly get this wrong — always query the DB rather than using hardcoded numbers.
Demo Church for Testing
Use the demo church UUID for any write operations during development:
00000000-0000-4000-a000-000000000001 (Grace Community — Protestant demo)
00000000-0000-4000-a000-000000000002 (St. Joseph Catholic Parish demo / SALES_SENTINEL)
NEVER write junk test data to other churches — this is production.
Auth Redirect URL Gaps (Known Issues)
- FA-008 (P0):
illustratetheword.comis NOT in Supabase Auth allowed redirect URLs. ITW signup is blocked until this is added in the Supabase dashboard under Authentication > URL Configuration. - FA-009 (P1):
sermonwise.aiandsharewiseai.comare not yet in redirect URLs. Add when going live with these domains.
Middleware Auth (churchwiseai-web)
The Next.js middleware in churchwiseai-web uses createServerClient with the ANON key for Supabase Auth validation (SermonWise and ShareWise app routes). It also performs manual REST calls to validate admin session tokens (for ChurchWiseAI church admin dashboard). These are separate auth systems sharing the same Supabase instance.
Python Voice Agent Cache
The voice agent maintains an in-memory TTL cache (session.py) to avoid hammering Supabase on every call. Church configs, product knowledge, and repeat caller history are cached. The cache uses time.monotonic() for precision. It clears naturally on process restart.
Failure Modes & Recovery
| Failure | Symptom | Recovery |
|---|---|---|
| Missing env var on Vercel | Build passes, runtime 500 errors | vercel env ls to check, `echo "val" |
| Service role key missing in Python agent | "SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY not set" in Cartesia logs | Add env vars to Cartesia deployment environment |
Bulk delete of unified_rag_content | Catastrophic data loss — 327K irreplaceable RAG records | NEVER run DELETE on this table without explicit founder approval and a backup |
| RLS blocking a write | 403 or empty result from an expected write | Switch to supabaseAdmin / service role key for that operation |
| Default 1000-row limit hit | Pagination returns incomplete results silently | Always use .range() or verify count matches expected |
| ITW signup broken | Users cannot sign up on illustratetheword.com | Add illustratetheword.com to Supabase Auth redirect URLs (FA-008) |
Cost Model / Usage Limits
- Single Supabase project on a paid plan (exact tier visible in Supabase dashboard).
- Database requests, auth MAUs, and storage are metered.
- At current scale (3 Stripe subscriptions, 13 premium_churches records), costs are minimal.
- The 327K
unified_rag_contentrows and 261Kchurchesrows are the largest cost drivers for DB storage and query throughput. - No connection pooling configured — each serverless function opens connections directly. Consider PgBouncer/Supavisor if connection counts spike.
See Also
- Stripe — subscription state written to Supabase via webhook
- Cartesia — voice agent reads/writes Supabase at call time
- Vercel — all Next.js serverless functions connect to Supabase
C:\dev\CLAUDE.md— table ownership rules and cross-project data contractssermon-illustrations/internal/shared-database-contract.md— table ownership map