← Back to Documentation Home

Technical Overview

Church Management Platform is a full-stack church management system built with a REST API backend serving a React single-page application frontend. The architecture is designed for long-term maintainability, small database footprint, and future expansion to native mobile clients.

4
.NET Projects
1
React App
40+
DB Tables
80+
API Endpoints

This document provides architecture decisions, database design rationale, and infrastructure details intended for developers, DBAs, and technical stakeholders.

Technology Stack

LayerTechnologyVersionPurpose
Backend ASP.NET Core9.0 REST API framework, dependency injection, middleware pipeline
Backend C#13 Primary server-side language
Backend Entity Framework Core9.0 ORM, code-first model, LINQ queries, JSONB mapping
Database PostgreSQL18 Primary data store with JSONB, GIN indexes, citext, sequences
Database Npgsql9.0 PostgreSQL .NET data provider with dynamic JSON serialization
Frontend React19 Component-based UI with hooks and context
Frontend TypeScript5.x Type-safe frontend development
Frontend Vite6.x Build tool, dev server, HMR, proxy to API
Backend JWT Bearer9.0 Stateless authentication tokens
Backend Google.Apis.Auth1.x Google OAuth ID token validation
Backend Twilio7.x SMS phone verification via Twilio Verify API (managed sender pool)
Backend BCrypt.Net-Next4.0 Industry-standard password hashing
Infra Nginx Reverse proxy, static file serving, SSL termination
Infra Ubuntu24.04 Production OS (Hostinger VPS)
Infra Let's Encrypt Free SSL certificates via certbot

Clean Architecture

The backend follows Clean Architecture (aka Onion Architecture), separating concerns into four .NET projects with strict dependency rules. The innermost layer has zero external dependencies; each outer layer depends only on layers inside it.

Dependency Flow (outside → inside) ChurchCheckIn.API → Controllers, Services, DI registration, Program.cs ↓ ChurchCheckIn.Infrastructure → EF DbContext, Repositories, Data Configurations ↓ ChurchCheckIn.Core → Entities, Repository Interfaces (zero dependencies) ChurchCheckIn.Shared → DTOs, Utilities (referenced by API; could be shared with mobile)

Why Clean Architecture?

  • Testability — Core entities and interfaces can be unit tested without a database or HTTP server.
  • Swappability — The data layer (EF/PostgreSQL) can be replaced without touching business logic.
  • Shared DTOs — The Shared project allows a future mobile app or background worker to share the same data contracts as the API.

Data Privacy & Tenant Isolation

Each church deployment runs on a fully isolated infrastructure stack: dedicated VPS, dedicated PostgreSQL instance, dedicated domain with its own SSL certificate. No multi-tenant shared database. The isolation model separates the platform operator (developer who deploys and maintains the code) from the church's data through multiple enforcement layers.

Isolation Architecture

  • Server isolation — one VPS per church, either purchased by the platform operator or provided by the church. No shared compute or storage.
  • Database isolation — one PostgreSQL instance per church with its own credentials. No cross-church queries are possible because the databases are on separate machines.
  • Network isolationpg_hba.conf restricts PostgreSQL to localhost only by default. Remote DB connections are disabled unless the church explicitly enables them for their own technical staff.
  • Application isolation — no web-app login exists for the platform operator. The highest in-app role (CHURCH_ADMIN) belongs to the church's designated administrator.
Leadership-friendly version For a non-technical explanation of data privacy suitable for church leadership, see the Data Privacy Architecture document.

PostgreSQL Role Model

Three database roles enforce the separation of concerns. These are PostgreSQL roles (not application roles)—enforced by the database engine regardless of what application code runs.

Role: postgres (Church-Owned)

  • PostgreSQL superuser—full access to all tables, sequences, functions, and configuration
  • Password set by the church administrator during onboarding; platform operator does not retain it
  • Used for: direct database access by church admin or tech staff, backup/restore, granting access to additional church personnel

Role: app_runtime (Church-Owned)

  • SELECT, INSERT, UPDATE, DELETE on all tables
  • USAGE on all sequences
  • Password configured in appsettings.Production.json on the server
  • Church administrator sets this password; platform operator does not need it for deployments
  • Used for: the running application's connection string (the only role the .NET app uses)

Role: platform_ops (Developer-Owned)

  • SELECT, INSERT, UPDATE on configuration tables only: feature_flags, module_permission, role_module_permission
  • USAGE on sequences (required for schema migrations)
  • Explicit REVOKE ALL on all data tables: people, families, family_members, person_emails, person_phones, users, donations, recurring_gifts, giving_funds, checkins, events, registrations, church_group, group_membership, small_group, small_group_leader, small_group_attendance, form_submissions, event_attendance, service_plans, schedule_assignments, and all other data-bearing tables
  • Used for: platform CLI tool, feature flag toggles, schema migrations

Verification

Church tech staff can verify role grants at any time using \dp in psql, which shows the access privileges for every table. A SELECT * FROM people executed as platform_ops will fail with a permission denied error.

PostgreSQL's log_connections = on setting logs every connection attempt with the role name, providing an audit trail of which credentials accessed the database and when.

Platform CLI Tool

Instead of a web-based platform admin login, infrastructure management uses a server-side CLI tool that connects to PostgreSQL using the platform_ops role. This tool runs only on the server (bound to localhost) and is never exposed through Nginx or any web endpoint.

Design

  • .NET console application at /opt/platform-cli/ on the server
  • Own configuration file (appsettings.platformcli.json) with platform_ops connection string
  • No references to data-layer repositories (IPeopleRepository, IFamilyRepository, IGivingRepository, etc.)—the tool physically cannot construct queries against data tables even at the code level
  • Even if someone modified the CLI code to query data tables, PostgreSQL would reject the query because the platform_ops role lacks permissions

Available Commands

CommandFunctionDB Access Required
health-checkTest DB connectivity, app process status, disk spaceNone (connectivity test only)
toggle-module <key>Enable/disable feature flagsfeature_flags table
migrateApply EF Core schema migrationsSchema DDL + sequences
versionShow deployed application versionNone (reads assembly metadata)
logs --tail NTail the systemd journal for the app serviceNone (reads OS logs)

Deployment Workflow

The deploy script uses a template appsettings.Production.json with placeholder values (__DB_PASSWORD__). If a production config already exists on the server, it is never overwritten—preserving the church's credentials. The platform operator does not need the app_runtime password to deploy code or run migrations.

Implementation status The data privacy isolation model is fully designed and documented but not yet implemented. The current deployment operates as a development sandbox with full developer access. The isolation model will be activated when onboarding the first production church deployment.
← Back to Documentation Home

Project Structure

Repository Layout src/ API Project Entry point — controllers, services, middleware Controllers/ 24 REST API controllers Services/ JWT, Email, SMS, Payment, Sync services Core Project Domain layer — no external dependencies Entities/ 51 domain entities Interfaces/ 39 repository interfaces Infrastructure Project Data access layer Data/ EF Core DbContext and configurations Repositories/ Repository implementations Shared Project Cross-cutting concerns DTOs/ 60+ data transfer object types Utilities/ Phone normalization, helpers Web Project React frontend (Vite + TypeScript) components/ Reusable UI components pages/ 30+ page components services/ API service modules types/ TypeScript interfaces scripts/ SQL scripts — schema, seeds, archival docs/ User manual, technical docs

PostgreSQL Overview

PostgreSQL was chosen over alternatives (SQL Server, MySQL, SQLite) for several reasons critical to this application's design:

  • Native JSONB — first-class binary JSON with GIN indexing, enabling the compact attendance archival system without a separate document store.
  • citext extension — case-insensitive text type used on person_emails.email for natural email matching without LOWER() calls on every query.
  • Array types — native text[] used for people.allergies and forms.required_fields, eliminating junction tables for simple lists.
  • Explicit sequences — fine-grained control over ID generation, supporting both explicit ID inserts and auto-incrementing new records.
  • Free & open source — no licensing cost on the production VPS.

Schema Conventions

The database follows consistent conventions for maintainability and data integrity:

  • Naming — All table and column names use snake_case for PostgreSQL convention compliance.
  • Right-sized types — Primary keys use appropriate integer types based on expected volume. Lookup tables use smaller types; transactional tables use standard integers.
  • Timestamps — All date/time columns use timezone-aware types with sensible defaults.
  • Referential integrity — Comprehensive foreign key constraints and indexes across all tables ensure data consistency.
  • JSONB for archival — Binary JSON columns with specialized indexes enable compact storage of historical attendance data.
  • Phone normalization — All phone numbers stored in E.164 international format for consistent lookup.
  • Soft deletes — Core entities use active/inactive flags rather than physical deletion, preserving data history.
Planning Center Integration — Live Two-way API integration with Planning Center Online is fully operational. Inbound sync pulls people, families, and groups from PCO; outbound push mirrors local records back. Real-time webhooks keep person data synchronized automatically. See the full Planning Center API section below, or the dedicated PCO API Integration reference document for endpoint details and architecture.
← Back to Documentation Home

Data Archival

The system uses a two-tier storage model to keep the database compact as attendance data accumulates over years. Relational tables hold a rolling window of recent data optimized for real-time kiosk operations. A weekly automated script archives older records into compact JSONB arrays (one row per event instead of hundreds), deletes expired data, and archives inactive memberships. Specialized indexes enable efficient per-person history queries across the archived data.

Tier 1 — Relational
Recent check-ins & registrations
Rolling window
Weekly Archival
Automated script
Off-peak schedule
Tier 2 — JSONB
Compact attendance records
Permanent storage

A proof-of-concept load test validated the approach: tens of thousands of individual check-in rows were compressed into just over 100 JSONB rows, reducing table sizes by 71% to 87%.

Full Documentation For comprehensive details — schema design, script internals, upsert SQL, EF Core integration, query patterns, and long-term storage projections — see the dedicated Database Archival Feature document. The Data Generation Plan covers the demo data methodology and results.

REST API Design

The API follows RESTful conventions with resource-oriented URLs, returning JSON responses. With 80+ endpoints across 24 controllers, the API covers every feature in the platform — people/families, events, check-ins, groups, forms, services, giving, reports, and integrations.

Authorization Model

Each endpoint enforces a three-layer authorization model: module enablement, user authentication, and granular permission checks. Different endpoints require different access levels — from public (kiosk check-in) to fully authenticated with specific permissions (admin operations).

Kiosk Security

The kiosk flow is designed for public-facing lobby touchscreens where user login is impractical. Security is maintained by limiting the scope of data exposed and the operations available — only essential check-in functions are accessible, with no access to sensitive or administrative data.

Authentication Flow

The system supports two authentication methods: email/password and Google OAuth. Both produce the same JWT token, and all subsequent API calls use the same Bearer token mechanism.

Email/Password Registration

User submits
email + password + phone
Backend creates
Person + Email + Phone + User
SMS verification
code sent (Twilio)
User verifies phone
→ JWT issued

Google OAuth

User clicks
"Sign in with Google"
Backend validates
Google ID token
Auto-creates account
if first sign-in
Complete profile
(add phone)
Verify phone
→ JWT issued

Password Storage

Passwords are hashed using industry-standard BCrypt with a secure cost factor. Password reset uses time-limited, cryptographically hashed tokens delivered via email.

JWT & Authorization

JWT tokens carry identity, role, and permission claims used by a three-layer authorization system. Every API request is checked for: (1) is the module enabled, (2) is the user authenticated, and (3) does the user have the required permission. Unauthorized or insufficient-permission requests are rejected.

Granular Permission System

The system uses 48 granular permissions organized across 10 features plus admin functions. Permissions are computed as the union of a user’s role defaults plus any individual overrides (grants or revokes). The resulting effective permission set is embedded in the JWT and checked server-side on every protected endpoint.

12 Roles

Twelve roles provide tiered access from app owner (SUPERADMIN) to self-service (MEMBER). Administrators can customize role permissions and add per-user overrides via the admin UI.

RoleAccess Level
SUPERADMINApp owner — all permissions including platform configuration
ADMINFull operational access to all modules
STAFFBroad read access with people/families editing
EVENT_COORDINATORFull events management
CHECKIN_ADMINCheck-in management and people view
GROUP_LEADERManagement of their own group(s)
WORSHIP_LEADERServices and worship planning management
FINANCE_MANAGERGiving management and data export
FINANCE_VIEWERRead-only giving access
TECH_ADMINIntegrations and system audit
VOLUNTEERLimited operational access for assigned areas
MEMBERSelf-service: own family, browse, register, give online (default)

Permission Admin UI

The Permission Admin page provides three tabs for managing access control:

  • Role Permissions — View and edit the default permission set for each role as a checkbox grid grouped by module.
  • User Overrides — Search for a user and toggle individual permission grants or revokes beyond their role defaults.
  • Role Assignment — Search for a user and change their role.
← Back to Documentation Home

Phone Verification

All users verify their phone number via SMS before accessing the application. This confirms the user’s identity and enables the kiosk phone-lookup flow.

  • Provider: Twilio Verify API — managed sender pool handles code generation, delivery, expiry, and rate limiting (no A2P 10DLC registration needed)
  • Security: Time-limited one-time codes with built-in rate limiting and fraud protection
  • Per-church config: Each deployment uses its own Twilio account and Verify Service — credentials are externalized in application settings with zero code changes

React Architecture

The frontend is a single-page application built with React 19 and TypeScript, using Vite as the build tool and dev server.

Key Patterns

  • Context-based state — Authentication and permission state managed via React Context with instant hydration (no loading flash).
  • Service layer — Each API resource has a dedicated service module for clean separation of concerns.
  • Type safety — TypeScript interfaces mirror backend data contracts throughout the frontend.
  • Persistent layout — Sidebar and header render once; page content scrolls independently for a desktop-class feel.
  • Protected routes — Routes check authentication, profile completeness, and phone verification before granting access.
  • Permission-based UI — Sidebar items, dashboard tiles, and page features are gated by individual permission codes rather than role names, enabling fine-grained access control in the UI.

API Communication

All API calls go through a centralized HTTP client that handles authentication token attachment, session expiry detection, and automatic redirect to login when needed.

Design System

The UI uses a CSS custom property (design token) system defined in index.css. All colors, typography, spacing, shadows, and transitions are defined as var(--token-name) tokens for consistency across 20+ pages.

  • Font: Inter (Google Fonts, weights 400/500/600/700) with system-ui fallback.
  • Color palette: Primary navy (50-900 scale), accent warm gold, neutral warm grays, semantic colors (success/warning/error/info).
  • Elevation: 6-level shadow system for card depth.
  • Accessibility: prefers-reduced-motion media query, focus-visible rings, sufficient contrast ratios.
  • Responsive breakpoints: Primary at 900px, secondary at 700px.
← Back to Documentation Home

Kiosk Mode

The kiosk is a separate, unauthenticated UI flow designed for lobby touchscreen displays. It runs in the same React app but uses dedicated routes (/kiosk, /kiosk/checkin) with no sidebar, header, or auth context.

Smart Check-In Window

The backend uses an intelligent time-window algorithm to determine which events are available for check-in at any given moment. The system automatically opens check-in before each service with appropriate lead time, and prevents early arrivals from accidentally checking into the wrong service when multiple services run on the same morning.

Hierarchical Group Matching

When a child checks in, the system automatically matches them to eligible events based on their group membership, including parent groups in the organizational hierarchy. A child in a specific age group will see events for their department, not just their exact group.

Label Printing

Check-in labels are generated as HTML in a new browser window, sized for 4"×2" thermal labels (ZD421 printer). Three label types: child name tag (with allergies and security code), parent pickup ticket (dual-sided with matching code), and volunteer name badge.

Mobile App

The platform includes a companion mobile application built with React Native (Expo SDK 54) for iOS and Android. The mobile app consumes the same REST API as the web frontend — no separate backend or database is required.

Technology

  • React Native via Expo SDK 54 — single codebase for iOS and Android
  • React Navigation v7 — bottom tab navigator with nested stack navigators
  • TypeScript — shared type definitions ported from the web frontend
  • expo-secure-store — encrypted JWT storage on device (iOS Keychain / Android Keystore)
  • expo-local-authentication — Face ID and fingerprint biometric login
  • react-native-webview — in-app PayPal payment flow
  • react-native-youtube-iframe — inline YouTube video playback for sermons

Screens

The app has 9 screens organized into stack navigators and two conditional tab bars (authenticated / unauthenticated):

ScreenStackDescription
HomeScreenHomeBranded landing page with church info, sermon link, small groups link
SmallGroupsScreenHomeBrowse active small groups with photos, schedules, leaders
LoginScreenTabEmail/password, Google OAuth, biometric authentication
GiveScreenGiveFund selection, amount input, PayPal donation
PayPalWebViewScreenGiveIn-app WebView for PayPal payment approval
MyGivingScreenGiveYear-filtered donation history with totals
CheckinScreenCheck-InFamily self-check-in with event selection
CheckinResultScreenCheck-InPost-check-in confirmation with security codes
MediaScreenTabYouTube sermon browser with inline player

Authentication

JWT tokens are stored in encrypted device storage via expo-secure-store. The app supports email/password login, Google OAuth (in development builds), and biometric unlock (Face ID / Fingerprint) after the first successful login. Saved credentials are automatically cleared if the server rejects them (e.g., after a password change).

API Integration

The mobile app uses axios with the same interceptor pattern as the web frontend — JWT attached to every request, with 401 responses triggering automatic logout. All endpoints consumed by the mobile app are existing web API endpoints; no mobile-specific endpoints were added. See the Mobile App documentation for full feature details.

API-First Design

Every user-facing feature follows an API-first pattern: the backend endpoint is designed and built first, then the frontend consumes it. This ensures:

  • Multi-client support — web, mobile, and any future client (tablet kiosk app, admin CLI) all use the same API.
  • Clear contracts — DTOs define the exact shape of request/response data, acting as a contract between frontend and backend developers.
  • Independent deployment — the React frontend is built to static files served by Nginx. The API runs as a separate systemd service. Either can be updated independently.
  • Testability — API endpoints can be tested with curl, Postman, or automated tests without a browser.

Deployment Pipeline

The application is deployed to a Hostinger VPS running Ubuntu 24.04. Deployment is a manual process (build locally, SCP to server, restart service) designed for simplicity and reliability.

Build & Deploy Steps

Backend
release build
Frontend
production build
Transfer to
production server
Restart
application service

Configuration Strategy

The application uses a layered configuration approach where base settings are committed to the repository and production-specific overrides (credentials, connection strings) live only on the server. This ensures sensitive values are never in source control while keeping the deploy process simple.

← Back to Documentation Home

VPS & Nginx

The production server runs all components on a single VPS with Nginx as the front door.

Internet
Nginx
SSL termination
Static file serving
Reverse proxy
ASP.NET Core
REST API
PostgreSQL
Database

Nginx handles SSL termination via Let’s Encrypt, serves the React SPA as static files, and reverse-proxies API requests to the backend application. SPA-style routing ensures client-side navigation works seamlessly.

SSL & Scheduled Tasks

SSL Certificates

SSL certificates are managed by certbot (Let’s Encrypt) with automatic renewal via a system timer. HTTPS is enforced for all traffic.

Scheduled Tasks

TaskScheduleMechanismPurpose
Database backup Daily 2:00 AM cron → pg_dump Full compressed database snapshot, copied to off-site cloud storage
Data archival Sunday 3:00 AM cron → psql Migrate old checkins/registrations to JSONB, reclaim disk space
Backup verification Sunday 4:00 AM cron → psql Restore latest backup to temp DB, validate record counts, alert on failure
SSL renewal Twice daily (certbot default) systemd timer Renew Let's Encrypt certificates before expiry
App restart On boot systemd service Auto-start ASP.NET Core after server reboot

Backup & Disaster Recovery

The platform implements a multi-layer backup strategy designed to protect against data loss from hardware failure, accidental deletion, corruption, or security incidents.

Backup Architecture

PostgreSQL
Live database
pg_dump
Nightly compressed
SQL snapshot
Local Storage
14-day retention
on server
Cloud Storage
Off-site copy
geo-redundant

Backup Components

ComponentScheduleRetentionStorage
Full database dump Daily, 2:00 AM 14 days local, configurable cloud Local + cloud (B2/S3)
Photo assets Daily (after DB) Continuous sync Cloud storage
Server configuration Weekly Rolling snapshots Cloud storage
Backup verification Weekly, Sunday 4:00 AM Temp DB on server

Recovery Objectives

MetricStandard DeploymentHigh Availability
RPO (Recovery Point Objective) < 24 hours Seconds (streaming replication)
RTO (Recovery Time Objective) 1–2 hours 5–15 minutes (failover)

Backup Verification

Automated weekly verification restores the latest backup to an isolated temporary database, validates record counts and data integrity, then drops the temporary database. This ensures backups are not silently corrupted — failures trigger immediate alerts.

Monitoring & Alerting

  • Uptime monitoring — external service checks the platform every 5 minutes; alerts via email on downtime.
  • Health check endpoint — reports database connectivity, disk usage, and time since last successful backup.
  • Backup failure alerts — notification on any backup script failure (missing file, undersized dump, verification failure).
  • Disk space monitoring — alerts when server disk usage exceeds threshold.

Disaster Recovery Scenarios

ScenarioRecovery ProcedureEstimated Time
Server failure Provision new VPS, install prerequisites, restore DB from cloud backup, redeploy from Git, restore photos and config, update DNS 1–2 hours
Database corruption Stop application, drop and restore from latest verified backup, restart 15–30 minutes
Accidental data deletion Restore backup to temporary DB, extract deleted records, copy back to production 30–60 minutes
Security incident Isolate server, snapshot state, rotate all credentials, assess scope, clean restore from pre-incident backup 2–4 hours

High Availability Options

The standard single-server deployment is appropriate for most churches. For organizations requiring higher availability, the platform supports several upgrade paths:

  • PostgreSQL streaming replication — a hot standby database on a separate server that stays seconds behind the primary. Manual failover in 5–15 minutes.
  • Managed database (cloud) — services like DigitalOcean Managed Postgres or AWS RDS provide automatic backups, point-in-time recovery, and optional auto-failover with a standby node.
  • Multi-server application tier — multiple ASP.NET Core instances behind an Nginx load balancer. The stateless JWT architecture requires no session affinity.
Stateless by design The platform’s stateless API architecture (JWT tokens, no server-side sessions) means adding application servers is straightforward — each instance is identical and can serve any request. The database is the single source of truth.
← Back to Documentation Home

ID & Sequence Strategy

A deliberate decision was made to use INTEGER (int4) primary keys with explicit PostgreSQL sequences rather than the more common IDENTITY pattern.

Rationale

  • Right-sized integers — Standard integers for transactional tables, smaller types for lookup tables. A church will never approach the 2.1 billion integer limit.
  • External data import support — The sequence strategy supports both auto-generated IDs for new records and explicit IDs when importing from external systems.
  • Smaller storage footprint — Right-sized types across 40+ tables with millions of rows and dozens of indexes add up to meaningful disk and memory savings.

Additional Platform Features

Beyond core people/family management, check-in, events, and groups, the platform includes several additional modules and systems added in February 2026.

Giving Module (Stripe + PayPal)

Online donation processing via Stripe (primary) and PayPal. Stripe supports credit/debit cards, bank ACH, Apple Pay, and Google Pay for one-time donations, plus Stripe Subscriptions for recurring gifts (weekly, bi-weekly, monthly, quarterly, annually). PayPal supports one-time donations via Smart Buttons. Manual donation entry by admins for cash, check, and offline gifts. Fund management with default fund, sort order, and active/inactive toggling. Frontend includes a public Give page (3-tab payment selector with recurring toggle), My Giving history with recurring subscription management for donors, and a Giving Admin page with overview dashboard, fund management, manual entry, and recurring gift management tabs. Webhook signature verification ensures payment integrity for both Stripe and PayPal events. Alternative giving methods (Zelle, Venmo, Cash App, bank ACH) are configurable per church.

Feature Flags System

Eleven features can be independently toggled per deployment: people/families (always on), groups, events, kiosk, services, giving, reports, PCO, forms, mailchimp, and communications. Both backend and frontend enforce feature enablement — disabled features return access-denied responses from the API and are hidden from navigation and direct URL access in the frontend. The SUPERADMIN manages feature toggles from the Configuration section.

SUPERADMIN Role & Configuration Section

The SUPERADMIN role is reserved for the app owner with full access to all permissions and platform configuration. A dedicated Configuration section in the sidebar provides access to Feature Modules management, PCO Sync settings, and Permissions administration — each gated by individual permissions so they can be delegated to other roles if needed.

User Feedback System

Authenticated users can submit feedback (general, bug, feature request, praise, question, or other) via a modal on the dashboard. Admins review all feedback with filtering by category and status, expandable message detail, admin notes, and resolve/delete actions. The admin dashboard tile shows the count of unresolved feedback items.

Recent Activity Feed

The admin dashboard includes a Recent Activity tab with filter chips across 8 categories: families, people, events, check-ins, registrations, forms, form submissions, and donations. Summary counts and paginated detail views provide a rolling window of recent church activity. High-volume categories display aggregated summaries rather than individual rows for readability. Filter chips automatically respect feature flags — disabled modules are hidden.

Planning Center API Integration

Planning Center Online (PCO) is a widely-used church management platform. Church Management Platform implements a full two-way API integration with PCO, enabling the system to serve as a complete replacement while maintaining data synchronization during any transition period.

Integration Architecture

The integration operates across three channels:

Inbound Sync
PCO → Local
People, Families, Groups
Real-Time
PCO Webhooks
Person CRUD events
Outbound Push
Local → PCO
People, Families, Memberships

Architecture

The integration is built from separate components for API communication, inbound sync orchestration, outbound push orchestration, webhook processing, and sync logging. Rate limiting ensures the platform stays within PCO’s API usage policies. A smart matching strategy uses multiple identifiers (PCO ID, email, name + date of birth) to correctly link records between systems.

Data Mapping

Bidirectional ID links between the local database and PCO enable reliable record matching. The integration covers people, families/households, groups, group memberships, locations, and calendar events across both read and write operations.

Admin UI

The PCO Sync page (/admin/pco-sync) provides connection testing, one-click sync/push buttons for each data type, real-time progress with 3-second polling, and a history table of the last 20 runs with status badges and error details. Accessible from the admin dashboard and sidebar (ADMIN role only).

Key Design Decisions

  • Personal Access Token authentication — simplest option for single-org deployment; can be upgraded to OAuth 2.0 for multi-tenant SaaS
  • PCO authoritative for demographics; local authoritative for operational data (allergies, photo, verification status)
  • Check-ins stay local — PCO’s Check-Ins API is read-only; local kiosk check-ins are managed entirely within the platform
  • Responsible rate limiting — API requests are throttled to stay well within PCO’s published rate limits
Full API Reference For complete endpoint details, write/read capability matrices, entity mapping, model differences, and webhook specifications, see the dedicated Planning Center API Integration document. For the high-level platform comparison, see the Planning Center Module.

Mailchimp Integration

Mailchimp is the leading email marketing platform. Church Management Platform integrates with the Mailchimp Marketing API v3 to automatically manage email audiences, keeping the church’s Mailchimp subscriber list in sync with local membership data.

Integration Architecture

The integration operates across two channels:

Outbound Push
Local → Mailchimp
Members, Merge Fields, Tags
Inbound Webhooks
Mailchimp → Local
Unsubscribe, Profile Updates

Outbound Push

The sync service queries all active people with primary email addresses and pushes them to a configured Mailchimp audience using the Batch API for efficient bulk operations (up to 500 operations per batch). Each member includes merge fields for first name, last name, and phone number. Church group memberships are synced as Mailchimp tags, enabling targeted email campaigns (e.g., send only to “Youth Group” or “Worship Team” members).

Inbound Webhooks

Mailchimp sends real-time webhook notifications when subscribers unsubscribe, get cleaned (bounced), or update their profile. The platform processes these events to keep local subscription status current. Critically, the system respects unsubscribes—once a member opts out via Mailchimp, subsequent syncs will not re-subscribe them.

Key Design Decisions

  • API key authentication — simple per-organization setup; Mailchimp API keys include the datacenter suffix for automatic endpoint routing
  • Batch API for bulk operations — Mailchimp’s Batch endpoint processes hundreds of member upserts in a single API call, reducing sync time and staying within rate limits
  • Tag-based segmentation — church groups map to Mailchimp tags rather than separate lists, following Mailchimp best practices for audience management
  • Unsubscribe tracking — subscription status stored locally to prevent re-subscribing opted-out members on subsequent syncs
  • Rate limiting — concurrent request throttling respects Mailchimp’s 10-connection limit

Admin UI

The Mailchimp page provides connection testing, one-click sync buttons for members and tags, real-time progress with polling, and a history table of recent sync runs with status badges and error details. Accessible from the Configuration sidebar section (requires mailchimp.manage permission).

Configuration The Mailchimp module is disabled by default. Enable it via Configuration → Feature Modules, then set the API key and List ID in the server configuration. The admin UI is accessible at Configuration → Mailchimp.
← Back to Documentation Home