Skip to main content

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

FieldValue
Project IDwrwkszmobuhvcfjipasi
Project URLhttps://wrwkszmobuhvcfjipasi.supabase.co
Region(managed by Supabase)
Auth providersEmail/password + Google OAuth (for SermonWise/ShareWiseAI and ITW)
MCP pluginmcp__plugin_supabase_supabase__execute_sql and related tools

How Used Per Product

ProductCodebaseSupabase Usage
ChurchWiseAI admin + APIschurchwiseai-webPremium church data, voice call logs, requests, chatbot config, team members, analytics
Voice agentchurchwiseai-web/voice-agent-livekit (Python)Church config lookup, call log writes, prayer/visitor/callback inserts, product knowledge reads
SermonWise AIchurchwiseai-webprofiles table, Supabase Auth for login/signup
ShareWiseAIchurchwiseai-webprofiles + social_subscriptions tables, Supabase Auth
PewSearch directorypewsearch/webChurch listings (churches), premium page data, congregation care, voice data
IllustrateTheWordsermon-illustrationsunified_rag_content (illustrations), profiles (Supabase Auth), dir_illustrations view
Chatbot + RAGchurchwiseai-webunified_rag_content (327K rows), product_knowledge, church_knowledge_base

Key Environment Variables

VariableScopeUsed By
NEXT_PUBLIC_SUPABASE_URLClient + ServerAll 3 Next.js codebases, middleware
NEXT_PUBLIC_SUPABASE_ANON_KEYClient + ServerAll 3 Next.js codebases — RLS-respecting queries, auth
SUPABASE_SERVICE_ROLE_KEYServer onlyAll 3 codebases — bypasses RLS for admin mutations
SUPABASE_URLPython envchurchwiseai-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

TableRowsOwnerPurpose
churches261K total (~218K visible)PewSearchChurch directory. Use directory_visible=true filter for public counts — NEVER use 261K as the public number
unified_rag_content~327KChurchWiseAI/ITWAll RAG content (illustrations, sermons, FAQs, knowledge). IRREPLACEABLE — never bulk delete
premium_churches4 (all test)PewSearch/ChurchWiseAIPremium subscriptions, plan tier, admin tokens, church customization data
church_voice_agentsvariesChurchWiseAIVoice agent config per church, Twilio number, greeting, features enabled
voice_call_logsvariesChurchWiseAICall transcripts, AI summaries, duration
voice_prayer_requestsvariesChurchWiseAIPrayer requests from voice AND chatbot (legacy name — shared channel)
voice_callback_requestsvariesChurchWiseAICallback requests from voice AND chatbot
voice_visitor_contactsvariesChurchWiseAIVisitor contact captures from voice AND chatbot
organization_settingsvariesChurchWiseAIChatbot config per church
profilesvariesChurchWiseAIUser profiles for Supabase Auth users (SermonWise, ShareWiseAI, ITW)
product_knowledgevariesChurchWiseAIRuntime Q&A injected into chatbot and voice agent system prompts
church_knowledge_basevariesChurchWiseAIUploaded documents for chatbot RAG
congregation_care_membersvariesPewSearchCare broadcast subscribers
church_team_membersvariesPewSearch/ChurchWiseAIRBAC team members with role-based access tokens
sai_theological_lenses18All17 theological traditions + universal lens
denominationsvariesPewSearchDenomination taxonomy with church counts
dir_illustrationsvariesITWRead-only view of unified_rag_content filtered to illustrations
contact_submissionsvariesPewSearchContact form submissions from Pro Website
social_subscriptionsvariesChurchWiseAIShareWiseAI 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.com is 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.ai and sharewiseai.com are 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

FailureSymptomRecovery
Missing env var on VercelBuild passes, runtime 500 errorsvercel env ls to check, `echo "val"
Service role key missing in Python agent"SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY not set" in Cartesia logsAdd env vars to Cartesia deployment environment
Bulk delete of unified_rag_contentCatastrophic data loss — 327K irreplaceable RAG recordsNEVER run DELETE on this table without explicit founder approval and a backup
RLS blocking a write403 or empty result from an expected writeSwitch to supabaseAdmin / service role key for that operation
Default 1000-row limit hitPagination returns incomplete results silentlyAlways use .range() or verify count matches expected
ITW signup brokenUsers cannot sign up on illustratetheword.comAdd 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_content rows and 261K churches rows 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 contracts
  • sermon-illustrations/internal/shared-database-contract.md — table ownership map