Project · Air
Ekklesia
The gathered church, administered — every campus, member and tithe in one place.
Essence
For the people who use it
Ekklesia is a multi-tenant church-management platform built specifically for South African megachurches and multi-campus networks. It is not a generic CRM with a religious skin — it speaks the language of the SA church: homecells, not "small groups"; tithes and offerings, not "donations"; Section 18A tax certificates; giving via PayShap, EFT, SnapScan and Ozow. Every screen was designed for the people who actually run a church across many sites.
The platform serves a whole hierarchy at once. HQ leadership see attendance, giving and growth rolled up across every campus. A campus pastor sees only their location — members, homecells, events, the Sunday workflow. Finance administrators reconcile giving and issue SARS-compliant Section 18A certificates in batches. Homecell leaders mark attendance from their phone. And members themselves get a self-service portal: their giving history, their own tax certificate, their consent settings.
Underneath the convenience is a hard compliance spine. South Africa's POPIA — its equivalent of GDPR — governs every byte of personal data, so Ekklesia treats audit, consent, encryption, data-export and erasure not as afterthoughts but as first-class features, designed to survive a real privacy audit and a real penetration test before a single congregation goes live.
- Member directory — full-text search, life-stage segmentation, bulk CSV import with a dry-run preview, visitor follow-up.
- Homecells — attendance per Sunday, leader assignment, and a multiplication engine that flags cells "ready to multiply" or "needs attention".
- Digital giving — PayShap, EFT, SnapScan, Ozow and cash, with CSV import, fuzzy donor matching and reconciliation across funds.
- Section 18A certificates — SARS-compliant PDFs generated in batches, filterable by tax year, with signed-URL download.
- Visitor connect cards — public, QR-scannable, POPIA-gated, converting to members on pastoral follow-up.
- HQ dashboard — nine KPIs and trend charts rolled up across all campuses, plus per-campus drill-down.
- Communications, events & volunteers — broadcast composer with an audience query builder, RSVP tracking, and rosters with mobile self check-in.
- Member self-service portal — profile, giving history, own Section 18A download, consent management and POPIA data-subject requests.
Construction
For the engineers
Stack
- API
- .NET 10 · ASP.NET Core 10 · C# 14 — in-process IIS hosting
- Data
- Dapper (hand-written SQL, no EF Core) + DbUp migrations · SQL Server 2022 with TDE and Always Encrypted
- Patterns
- Clean Architecture ·
Mediator.SourceGenerator· Mapster · FluentValidation · aResult<T>wrapper - Identity
- Custom Dapper-backed identity · JWT (HS256) with dual audiences · PBKDF2-HMAC-SHA256 (210k iterations) · refresh-token rotation
- Background
- Hangfire on SQL Server storage, in-process
- Documents
- QuestPDF — SARS-compliant Section 18A certificates
- Tenant app
- Next.js 16.2 · React 19 · Tailwind 4 · TanStack Query v5 — staff & member portal
- Admin app
- Next.js 16.2 · React 19 · Tailwind 4 — platform operator console
- Integration
- OpenAPI-first — generated TypeScript types ·
openapi-fetch· react-hook-form + Zod - Testing
- xUnit · Testcontainers (MSSQL) — 104+ integration tests, 12 cross-tenant-leakage suites
- Deploy
- Windows Server / IIS (
AspNetCoreModuleV2) · Node 22 services via nssm + ARR · PowerShell orchestration · built on Linux
Architecture
Row-level multi-tenancy, enforced by construction. Every tenant — a church
network — lives in one SQL Server database, isolated by a ChurchId column on every
table. A TenantRepositoryBase<T> automatically appends
WHERE ChurchId = @ChurchId to every query and throws if the tenant context is missing,
so a developer cannot accidentally write a cross-tenant read. A second tier, CampusId,
scopes campus pastors and homecell leaders to their own location. The guarantee isn't trusted — a
suite of dedicated CrossTenantLeakageTests runs on every pull request and fails the
build if one tenant can ever see another's data.
Two JWT audiences, cleanly separated. Church staff receive a token with a
tenant audience; Ekklesia's own operators receive a platform audience.
Authorization policies make /api/v1/tenant/* reject a platform token and vice versa, so
the SaaS operators can never touch a congregation's pastoral data through the normal API. Identity
is hand-rolled on Dapper — no ASP.NET Core Identity dependency — with PBKDF2-HMAC-SHA256 hashing and
refresh-token rotation that detects token theft by revoking the whole token family on reuse.
POPIA is wired into the architecture. An append-only AuditLog captures
before/after JSON for every write to a personal-data entity, retained seven years. Data-subject
access requests queue a Hangfire job that assembles a ZIP and hands back a signed URL. An
Anonymise() domain method redacts a member's identity while deliberately
preserving their Section 18A records — because SARS requires the tax trail to survive
even an erasure request. A member's SA ID number is stored with SQL Server Always Encrypted.
Clean Architecture, feature-sliced. Code is organised by business capability
(Members/, Giving/, Communications/, Events/),
with handlers generated by a source-generated mediator pipeline, DTOs mapped via Mapster, and a
Result<T> wrapper unifying success and error across the HTTP edge. Schema is
hand-written SQL run through DbUp — versioned scripts applied once and never edited after merge,
plus re-runnable scripts for views and procedures. Hangfire handles the heavy lifting off the
request thread: batch Section 18A generation, nightly EFT reconciliation, DSAR fulfilment,
dashboard aggregation and broadcast delivery.
Two Next.js frontends over an OpenAPI contract. The tenant app (staff + member
portal) and the platform-admin console share a stack — Next.js 16.2 App Router, React 19, Tailwind 4
from a CSS-first design system drawn straight from the navy-and-gold mockups — but carry separate
httpOnly cookie names so their sessions never collide. Both run codegen against the
API's openapi.json so the TypeScript types can never drift from the server, and forms
are react-hook-form + Zod. Everything deploys onto Windows Server: the API in-process under IIS, the
Node apps as nssm services behind ARR, choreographed by a PowerShell deploy.ps1 that
backs up, migrates, copies, health-checks and rolls back on failure.
Notable details
- Section 18A certificates are real SARS-compliant PDFs (QuestPDF) generated in batches, with fuzzy donor matching reconciling PayShap / EFT / SnapScan / Ozow / cash against member records.
- Cross-tenant isolation is proven, not asserted — 12 leakage test suites across Members, Giving, Visitors, Communications and Events gate every PR.
- A documented penetration-test scope (auth bypass, XSS, SQLi, CORS, CSRF, rate limits, tenant isolation, consent, erasure, encryption) is a mandatory go-live gate.
- Eight tenant roles (HQ admin through read-only and member) plus two platform roles, with campus-level scoping enforced per handler.
- 43 versioned DbUp migration scripts, recorded immutably in
__SchemaVersions; deterministic builds with warnings-as-errors. - Built for scale on day one — piloting against a multi-campus network of roughly ninety sites and twelve thousand members.