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.
This document provides architecture decisions, database design rationale, and infrastructure details intended for developers, DBAs, and technical stakeholders.
Technology Stack
| Layer | Technology | Version | Purpose |
|---|---|---|---|
| Backend | ASP.NET Core | 9.0 | REST API framework, dependency injection, middleware pipeline |
| Backend | C# | 13 | Primary server-side language |
| Backend | Entity Framework Core | 9.0 | ORM, code-first model, LINQ queries, JSONB mapping |
| Database | PostgreSQL | 18 | Primary data store with JSONB, GIN indexes, citext, sequences |
| Database | Npgsql | 9.0 | PostgreSQL .NET data provider with dynamic JSON serialization |
| Frontend | React | 19 | Component-based UI with hooks and context |
| Frontend | TypeScript | 5.x | Type-safe frontend development |
| Frontend | Vite | 6.x | Build tool, dev server, HMR, proxy to API |
| Backend | JWT Bearer | 9.0 | Stateless authentication tokens |
| Backend | Google.Apis.Auth | 1.x | Google OAuth ID token validation |
| Backend | Twilio | 7.x | SMS phone verification via Twilio Verify API (managed sender pool) |
| Backend | BCrypt.Net-Next | 4.0 | Industry-standard password hashing |
| Infra | Nginx | — | Reverse proxy, static file serving, SSL termination |
| Infra | Ubuntu | 24.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.
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
Sharedproject 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 isolation —
pg_hba.confrestricts PostgreSQL tolocalhostonly 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.
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,DELETEon all tablesUSAGEon all sequences- Password configured in
appsettings.Production.jsonon 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,UPDATEon configuration tables only:feature_flags,module_permission,role_module_permissionUSAGEon sequences (required for schema migrations)- Explicit
REVOKE ALLon 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) withplatform_opsconnection 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_opsrole lacks permissions
Available Commands
| Command | Function | DB Access Required |
|---|---|---|
health-check | Test DB connectivity, app process status, disk space | None (connectivity test only) |
toggle-module <key> | Enable/disable feature flags | feature_flags table |
migrate | Apply EF Core schema migrations | Schema DDL + sequences |
version | Show deployed application version | None (reads assembly metadata) |
logs --tail N | Tail the systemd journal for the app service | None (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.
Project Structure
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.emailfor natural email matching withoutLOWER()calls on every query. - Array types — native
text[]used forpeople.allergiesandforms.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_casefor 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.
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.
Recent check-ins & registrations
Rolling window
Automated script
Off-peak schedule
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%.
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
email + password + phone
Person + Email + Phone + User
code sent (Twilio)
→ JWT issued
Google OAuth
"Sign in with Google"
Google ID token
if first sign-in
(add 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.
| Role | Access Level |
|---|---|
| SUPERADMIN | App owner — all permissions including platform configuration |
| ADMIN | Full operational access to all modules |
| STAFF | Broad read access with people/families editing |
| EVENT_COORDINATOR | Full events management |
| CHECKIN_ADMIN | Check-in management and people view |
| GROUP_LEADER | Management of their own group(s) |
| WORSHIP_LEADER | Services and worship planning management |
| FINANCE_MANAGER | Giving management and data export |
| FINANCE_VIEWER | Read-only giving access |
| TECH_ADMIN | Integrations and system audit |
| VOLUNTEER | Limited operational access for assigned areas |
| MEMBER | Self-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.
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-motionmedia query,focus-visiblerings, sufficient contrast ratios. - Responsive breakpoints: Primary at 900px, secondary at 700px.
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):
| Screen | Stack | Description |
|---|---|---|
| HomeScreen | Home | Branded landing page with church info, sermon link, small groups link |
| SmallGroupsScreen | Home | Browse active small groups with photos, schedules, leaders |
| LoginScreen | Tab | Email/password, Google OAuth, biometric authentication |
| GiveScreen | Give | Fund selection, amount input, PayPal donation |
| PayPalWebViewScreen | Give | In-app WebView for PayPal payment approval |
| MyGivingScreen | Give | Year-filtered donation history with totals |
| CheckinScreen | Check-In | Family self-check-in with event selection |
| CheckinResultScreen | Check-In | Post-check-in confirmation with security codes |
| MediaScreen | Tab | YouTube 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
release build
production build
production server
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.
VPS & Nginx
The production server runs all components on a single VPS with Nginx as the front door.
SSL termination
Static file serving
Reverse proxy
REST API
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
| Task | Schedule | Mechanism | Purpose |
|---|---|---|---|
| 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
Live database
Nightly compressed
SQL snapshot
14-day retention
on server
Off-site copy
geo-redundant
Backup Components
| Component | Schedule | Retention | Storage |
|---|---|---|---|
| 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
| Metric | Standard Deployment | High 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
| Scenario | Recovery Procedure | Estimated 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.
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:
PCO → Local
People, Families, Groups
PCO Webhooks
Person CRUD events
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
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:
Local → Mailchimp
Members, Merge Fields, Tags
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).