Concept and architecture
Ministrium implements multi-campus as a two-level hierarchical model on top of the multi-tenant architecture.
Tenant (Church)
└─ Campus 1
├─ Members / prospects / families
├─ Rooms / kiosk
├─ Events and service plans
└─ Cell groups
└─ Campus 2
└─ ...What’s per-campus vs per-church
| Resource | Lives at | Shared across campuses |
|---|---|---|
| Member / prospect | Campus | No (transferable) |
| Household | Campus | No |
| Attendance | Campus | No |
| Donation | Originating campus | Consolidated reportable |
| Stripe account | Church | Yes (single account) |
| Communication templates | Church | Yes |
| Roles & permissions | Church (definition) | Assignment is per-campus |
| Plan & billing | Church | Yes |
| Basic branding | Church | Yes |
| Logo / address | Campus | No (each campus has its own) |
Why a single Stripe?
Because fiscally, the church is one legal entity. The EIN/Tax ID is one, and 501c3 receipts must be issued in the church’s name, not the campus’s. Each donation is tagged with the originating campus for reporting, but funds land in a single bank account.
Only if each campus is an independent legal entity. In that case they’re two churches in Ministrium, not two campuses. See Stripe Connect.
Data isolation
At the database layer, every query includes organization_id and campus_id. RLS (Row-Level Security) policies verify both. A user scoped to North trying to read a member from Downtown gets 404, not 403 — from their perspective, the member doesn’t exist.
Consolidated reports without losing per-campus
Reports (attendance, donations, health) have a picker that swaps between:
- A single campus: filtered.
- All campuses: aggregated.
- Comparison: side by side.
Only org_admin and finance see the “all” and “comparison” options.