Skip to main content

Knowledge > Architecture > Database Schema > PewSearch Tables

Database Schema — PewSearch Directory

Overview

These tables form the PewSearch church directory — 261,139 total church records (218,369 directory_visible=true, 42,770 hidden) sourced primarily from Outscraper/Google Places. All tables live in the shared Supabase instance (wrwkszmobuhvcfjipasi). No staging environment exists — all queries hit production.

CRITICAL safety rules:

  • NEVER bulk delete from churches — this is the 218K+ directory that is the foundation of the entire business.
  • ALWAYS filter WHERE directory_visible = true when showing counts or listings to users. The raw row count (261K) includes hidden/suppressed records. The correct visible count is ~218K.
  • NEVER display or log lgbtq_inclusive or inclusivity_signals fields in user-facing UI without editorial review.

PewSearch Directory Enrichment


Category: Directory Core

churches (261,139 rows total; 218,369 directory_visible = true)

The central table. Every church listing in the PewSearch directory is a row here. Sourced primarily via Outscraper (Google Places), supplemented by website deep-crawls and manual corrections. This table is the irreplaceable core asset of the PewSearch product.

CRITICAL: The directory_visible column is the gating filter for all public queries. 42,770 rows are hidden (closed, duplicate, or inappropriate listings). ALWAYS filter WHERE directory_visible = true — never quote the raw row count of 261K as the directory size.

ColumnTypeNullableNotes
iduuid PKNOAuto-generated
nametextNOChurch display name
slugtextNOURL slug for /churches/[slug]
google_place_idtextYESGoogle Places ID (source of truth for deduplication)
addresstextYESFull formatted address
streettextYESStreet address component
citytextYESCity
statetextYESFull state name
state_codetextYESTwo-letter state abbreviation
zip_codetextYESZIP code
countrytextYESDefault: 'United States of America'
latitudefloat8YESDecimal degrees
longitudefloat8YESDecimal degrees
time_zonetextYESIANA timezone string
phonetextYESPrimary phone number
emailtextYESPrimary email
emailstext[]YESArray of all known emails
websitetextYESPrimary website URL
categorytextYESGoogle Places category (e.g., 'church')
subtypestext[]YESGoogle Places subtypes array
denominationtextYESRaw denomination string from source data
ratingnumericYESGoogle rating (0–5)
reviews_countintegerYESNumber of Google reviews; default 0
reviews_per_scorejsonbYESDistribution of star ratings
photos_countintegerYESNumber of Google photos; default 0
photo_urltextYESPrimary photo URL
logo_urltextYESLogo URL (if available)
google_maps_urltextYESDirect Google Maps link
descriptiontextYESShort description
aboutjsonbYESExtended about information from Google
working_hoursjsonbYESService/office hours structured data
business_statustextYESDefault: 'OPERATIONAL'; may be 'CLOSED_TEMPORARILY' etc.
owner_verifiedbooleanYESTrue if a church owner has claimed and verified this listing; default false
sourcetextYESData source identifier; default 'outscraper'
source_querytextYESThe scraper query that produced this row
last_scraped_attimestamptzYESWhen data was last refreshed from source
deep_crawledbooleanYESTrue if website has been deep-crawled; default false
deep_crawl_contenttextYESRaw text extracted from deep website crawl — do not SELECT unless needed; can be large
website_scraped_attimestamptzYESTimestamp of last website scrape
website_statustextYESHTTP status or error from last website scrape
is_premiumbooleanYESTrue if church has an active Premium Page subscription; default false
directory_visiblebooleanYESCRITICAL — only true rows are shown in the directory; default true. Always filter on this.
lgbtq_inclusivebooleanYESDetected LGBTQ+ inclusivity signal (see inclusivity_signals)
inclusivity_signalstext[]YESRaw signals that informed lgbtq_inclusive classification
ftstsvectorYESFull-text search vector (auto-maintained by trigger) — do not write directly
created_attimestamptzYESRow creation timestamp
updated_attimestamptzYESLast modification timestamp

Key relationships:

  • churches.id is referenced by church_theological_lenses.church_id, church_update_requests.church_id, church_local_resources.church_id, contact_submissions.church_id, church_leads.church_id, church_submissions.approved_church_id
  • premium_churches.church_idchurches.id (owned by ChurchWiseAI, not PewSearch)

denominations (64 rows)

Reference table of recognized denominations used to power the denomination filter on the directory. Each denomination belongs to a broader theological family.

ColumnTypeNullableNotes
idinteger PKNOAuto-increment
nametextNOCanonical denomination name
familytextNOTheological family (e.g., 'Baptist', 'Reformed', 'Methodist')
slugtextYESURL slug for denomination pages
display_orderintegerNOSort order in UI; default 100
church_countintegerNOCached count of matched churches; default 0
websitetextYESDenomination's official website
logo_urltextYESDenomination logo
founded_yearintegerYESYear the denomination was founded
headquarterstextYESCity/state of national headquarters
about_texttextYESShort editorial description
beliefsjsonbYESKey beliefs structured data
rss_feed_urltextYESRSS feed for denomination news (if available)
created_attimestamptzNORow creation timestamp

denomination_aliases (319 rows)

Maps raw denomination strings (as they appear in scraped data) to canonical denominations.name values. Used to normalize the messy denomination field on the churches table into filterable, structured values.

ColumnTypeNullableNotes
idinteger PKNOAuto-increment
canonicaltextNOThe canonical denomination name (matches denominations.name)
aliastextNORaw string variant found in source data

Category: Enrichment

church_theological_lenses (215,327 rows)

Join table between churches and sai_theological_lenses (the reference table of theological positions). Used to power advanced theological filtering in the directory. Each row links one church to one theological lens, with a confidence level. 215,323 rows are 'inferred' (from denomination data); only 4 are 'confirmed' (manually assigned).

ColumnTypeNullableNotes
church_iduuid FKNOReferences churches.id
theological_lens_idinteger FKNOReferences sai_theological_lenses.lens_id
confidencetextYESDefault: 'inferred'; 'confirmed' for manual assignments
created_attimestamptzYESRow creation timestamp

Note: This is a high-volume join table (215,327 rows). Queries filtering by theological lens should use indexed lookups on theological_lens_id. The sai_theological_lenses reference table is owned by the legacy B2C app namespace (sai_ prefix) but is read by PewSearch. FK target is sai_theological_lenses.lens_id (integer), not theological_lenses.id (uuid).


church_local_resources (19 rows)

Community resources associated with a specific church — food pantries, counseling services, shelters, etc. Used on church detail pages to surface how the church serves its local community.

ColumnTypeNullableNotes
iduuid PKNOAuto-generated
church_iduuid FKNOReferences churches.id
categoryUSER-DEFINEDNOEnum type for resource category (e.g., food, counseling, shelter)
nametextNOResource name
descriptiontextYESDescription of the resource
phonetextYESContact phone
addresstextYESResource address (may differ from church)
websitetextYESResource website
hourstextYESOperating hours
notestextYESAdditional notes
is_criticalbooleanNOTrue for high-priority resources (e.g., crisis hotlines); default false
is_activebooleanNOShow/hide without deleting; default true
sort_orderintegerNODisplay order; default 0
created_attimestamptzNORow creation timestamp
updated_attimestamptzNOLast modification timestamp

church_staff_contacts (~2 rows)

Named staff members at a church who receive chatbot-routed contacts (prayer requests, callback requests, visitor inquiries). Despite the name, this table is also used by the ChurchWiseAI voice/chatbot system to route notifications to the right staff member.

ColumnTypeNullableNotes
iduuid PKNOAuto-generated
organization_iduuid FKNOReferences churches.id
nametextNOStaff member's name
roletextNORole title (e.g., 'Pastor', 'Office Manager')
departmenttextYESDepartment or ministry area
emailtextYESStaff email for notifications
phonetextYESStaff phone
biotextYESStaff bio for public display
availabilityjsonbYESAvailability schedule; default {}
notification_preferencesjsonbYESHow and when to notify; default {}
is_activebooleanYESDefault true
created_attimestamptzYESRow creation timestamp
updated_attimestamptzYESLast modification timestamp

church_profiles (low row count)

Chatbot widget configuration for a church — welcome message, branding color, logo, service times, contact details, and social media links. Created when a church activates the ChurchWiseAI chatbot. Referenced by both the PewSearch directory widget embed and the ChurchWiseAI admin.

ColumnTypeNullableNotes
iduuid PKNOAuto-generated
organization_iduuid FKNOReferences churches.id
welcome_messagetextYESDefault: 'Welcome! How can I help you today?'
primary_colorvarcharYESHex color for widget branding; default '#6B46C1'
logo_urltextYESChurch logo URL
timezonevarcharYESDefault: 'America/New_York'
service_timesjsonbYESArray of service time objects; default []
locationjsonbYESStructured location data; default {}
contact_emailtextYESPublic contact email
contact_phonetextYESPublic contact phone
website_urltextYESChurch website
social_mediajsonbYESSocial media links; default {}
created_attimestamptzYESRow creation timestamp
updated_attimestamptzYESLast modification timestamp

church_rag_categories (low row count)

Hierarchical categories for organizing RAG knowledge base content within the admin. Allows churches to group their FAQ content into named sections with optional parent/child nesting.

ColumnTypeNullableNotes
iduuid PKNOAuto-generated
organization_iduuid FKNOReferences churches.id
nametextNOCategory display name
slugtextNOURL-safe slug
descriptiontextYESOptional description
parent_iduuid FKYESSelf-referential parent for nesting; references church_rag_categories.id
display_orderintegerYESSort order; default 0
icontextYESIcon identifier
is_activebooleanYESDefault true
created_attimestamptzYESRow creation timestamp
updated_attimestamptzYESLast modification timestamp

church_events (low row count)

Events for churches with Pro Website or chatbot plans. Supports one-time and recurring events via an iCal-style recurrence rule. Used on church detail pages and surfaced by the chatbot when visitors ask about upcoming events.

ColumnTypeNullableNotes
iduuid PKNOAuto-generated
organization_iduuid FKNOReferences churches.id
titletextNOEvent name
descriptiontextYESEvent description
start_timetimestamptzNOEvent start (UTC)
end_timetimestamptzNOEvent end (UTC)
locationtextYESLocation string (may differ from church address)
event_typevarcharYESCategory label (e.g., 'worship', 'outreach')
is_recurringbooleanYESDefault false
recurrence_ruletextYESiCal RRULE string for recurring events
registration_urltextYESExternal registration link
max_attendeesintegerYESCapacity cap (null = unlimited)
current_attendeesintegerYESCurrent RSVP count; default 0
is_activebooleanYESDefault true
created_byuuidYESStaff member or admin who created the event
created_attimestamptzYESRow creation timestamp
updated_attimestamptzYESLast modification timestamp

Category: Operational

church_update_requests (1 row — all-time total is low)

Incoming correction requests from church staff who spot incorrect data on their listing. A pastor can submit a phone/website/hours correction without having claimed the listing. Requires admin review before the churches row is updated. Currently has 1 row (rejected).

ColumnTypeNullableNotes
iduuid PKNOAuto-generated
church_iduuid FKNOReferences churches.id
submitter_nametextNOName of the person submitting the correction
submitter_emailtextNOContact email
submitter_roletextNOSelf-reported role (e.g., 'Pastor')
proposed_phonetextYESCorrected phone number
proposed_websitetextYESCorrected website URL
proposed_working_hoursjsonbYESCorrected hours in structured format
proposed_descriptiontextYESCorrected church description
statustextNO'pending' / 'approved' / 'rejected'; default 'pending'
reviewer_notestextYESInternal admin notes
reviewed_attimestamptzYESWhen the review was completed
created_attimestamptzYESSubmission timestamp
updated_attimestamptzYESLast modification timestamp

church_submissions (1 row)

New church listing submissions from the public — churches not yet in the directory. Requires Apostles' Creed confirmation and church leader attestation to qualify. Reviewed by admin before a new churches row is created.

ColumnTypeNullableNotes
iduuid PKNOAuto-generated
nametextNOSubmitted church name
streettextYESStreet address
citytextNOCity
statetextYESState
zip_codetextYESZIP code
countrytextNODefault: 'US'
phonetextYESPhone number
emailtextYESChurch email
websitetextYESChurch website
denominationtextYESSelf-reported denomination
descriptiontextYESChurch description
submitter_nametextNOName of the person submitting
submitter_emailtextNOSubmitter contact email
submitter_roletextNOSubmitter's role at the church
confirms_church_leaderbooleanNOAttestation that submitter is a church leader; default false
confirms_apostles_creedbooleanNOConfirms agreement with the Apostles' Creed; default false
statustextNO'pending' / 'approved' / 'rejected'; default 'pending'
reviewer_notestextYESInternal admin notes
reviewed_attimestamptzYESReview timestamp
approved_church_iduuid FKYESSet to the new churches.id if approved
submitter_iptextYESIP address for spam detection
created_attimestamptzYESSubmission timestamp
updated_attimestamptzYESLast modification timestamp

church_scrape_jobs (605 rows)

Scraper job queue — each row represents one Outscraper batch query (by city + state + keyword). Tracks progress from pending through completion or error. Used to manage the ongoing expansion of the churches database.

ColumnTypeNullableNotes
iduuid PKNOAuto-generated
querytextNOThe search query string sent to Outscraper
citytextYESTarget city
statetextYESTarget state
statustextYES'pending' / 'running' / 'completed' / 'failed'; default 'pending'
results_countintegerYESNumber of churches returned; default 0
error_messagetextYESError details if status is 'failed'
started_attimestamptzYESWhen job began processing
completed_attimestamptzYESWhen job finished
created_attimestamptzYESRow creation timestamp

church_leads (low row count)

Lead capture from church detail pages — when a pastor or admin fills out a "Claim your listing" or contact form before completing the full claim flow. Tracked for follow-up outreach. Distinct from church_submissions (which are new listing requests) and from claimed churches in premium_churches.

ColumnTypeNullableNotes
iduuid PKNOAuto-generated
church_idtextNOChurch identifier (text, not FK — may be a slug or UUID string)
nametextNOLead's name
emailtextNOLead's email
roletextNOSelf-reported role
sourcetextNOWhere the lead originated; default 'church_detail'
statustextNO'new' / 'contacted' / 'converted' / 'dead'; default 'new'
follow_up_sent_attimestamptzYESWhen follow-up email was sent
converted_attimestamptzYESWhen lead converted to a paying customer
created_attimestamptzNORow creation timestamp
updated_attimestamptzNOLast modification timestamp

contact_submissions (23 rows)

Visitor-to-church contact messages submitted through the PewSearch church detail page contact form. Stored for the church's reference and optionally forwarded via email. Written by pewsearch/web; read by ChurchWiseAI admin dashboard.

ColumnTypeNullableNotes
iduuid PKNOAuto-generated
church_iduuid FKNOReferences churches.id
nametextYESVisitor's name
emailtextYESVisitor's email
messagetextYESMessage content
created_attimestamptzYESSubmission timestamp

known_issues / known_issue_history (low row counts)

User-reported bug and feedback tracking tables, used across all properties. known_issues stores each reported issue with status lifecycle. known_issue_history is an append-only audit log of every status transition.

known_issues

ColumnTypeNullableNotes
iduuid PKNOAuto-generated
titletextNOShort issue title
descriptiontextNOFull description
categoryvarcharNOIssue category
statusvarcharNO'reported' / 'investigating' / 'in_progress' / 'resolved' / 'wont_fix'; default 'reported'
priorityvarcharYES'low' / 'medium' / 'high' / 'critical'; default 'medium'
affected_appvarcharYESWhich app/property is affected
upvote_countintegerNOUser upvote count; default 1
reporter_emailtextYESReporter's email
reporter_nametextYESReporter's name
admin_notestextYESInternal admin notes
fix_detailstextYESDescription of how it was fixed
screenshot_pathsjsonbYESArray of screenshot storage paths; default []
devicetextYESDevice/browser info from reporter
created_attimestamptzNOReport submission timestamp
updated_attimestamptzNOLast modification timestamp
resolved_attimestamptzYESWhen the issue was resolved
feedback_countintegerYESNumber of feedback responses; default 0

known_issue_history

ColumnTypeNullableNotes
iduuid PKNOAuto-generated (uuid_generate_v4())
issue_iduuid FKNOReferences known_issues.id
old_statustextYESPrevious status value
new_statustextNONew status value
changed_bytextYESWho made the change; default 'system'
change_reasontextYESOptional explanation
metadatajsonbYESAdditional context; default {}
created_attimestamptzYESTransition timestamp

Category: Geographic

state_boundaries (62 rows)

PostGIS geometry table — one polygon per US state (plus territories). Used for geographic search queries, e.g., filtering churches within a state boundary or "near me" radius searches that need to stay within state lines.

ColumnTypeNullableNotes
idinteger PKNOAuto-increment
state_codetextNOTwo-letter state code (e.g., 'CA', 'TX')
countrytextNODefault: 'US'
geomgeometryNOPostGIS geometry column (polygon/multipolygon) — requires PostGIS extension

Note: Queries against this table require the PostGIS extension. Use ST_Within, ST_Intersects, or ST_DWithin for geographic lookups. Direct column reads on geom return WKB hex — use ST_AsText(geom) or ST_AsGeoJSON(geom) for human-readable output.


Row Count Summary

Counts verified against live production database on 2026-03-25.

TableExact / Estimated RowsNotes
churches261,139 total218,369 visible (directory_visible = true); 42,770 hidden
church_theological_lenses215,327Join table; 215,323 inferred, 4 confirmed
denomination_aliases319Raw → canonical denomination mapping
church_scrape_jobs605Outscraper job history
denominations64Reference table
state_boundaries62One row per US state/territory
contact_submissions23Visitor contact messages
church_local_resources19Community resources per church
church_update_requests1Correction requests (all-time)
church_submissions1New listing requests (all-time)
church_staff_contacts~2Staff notification routing
All others~0Operational queues, empty or near-empty

Key Safety Rules

  1. Always filter directory_visible = true for public-facing queries. Visible: 218,369. Raw total: 261,139.
  2. Never bulk delete churches. Hidden listings still have historical value and relationships.
  3. deep_crawl_content can be large. Do not SELECT it unless the column is actually needed.
  4. lgbtq_inclusive and inclusivity_signals are sensitive classification fields. Never display in user-facing UI without editorial review.
  5. fts is auto-maintained. Do not write to this column directly — it is updated by a database trigger on INSERT/UPDATE.
  6. church_theological_lenses.theological_lens_id is an integer FK to sai_theological_lenses.lens_id, not to theological_lenses.id (which is a separate uuid-keyed table used by the legacy B2C app).

See Also