Church App — MVP Scope
Ship the smallest thing that makes one denomination say “yes.” Everything else is Phase 2.
The MVP Question
The temptation: build everything we’ve designed. The architecture supports it. The domain model is ready. AI agents can generate code fast.
The reality: even with AI agents, a solo founder needs to ship something usable to real churches within 4-6 months. Every feature added to MVP is a feature that needs to be tested, polished, supported, and explained. The MVP isn’t about what you CAN build — it’s about what you MUST ship to close the first denomination deal.
The test: Would ICF or Chrischona/Viva sign a pilot agreement based on this feature set? If yes, it’s enough. If no, what’s missing?
What the First Pilot Church Needs
Put yourself in the shoes of an ICF Zürich campus pastor evaluating your app:
"We currently use [Communiapp / WhatsApp groups / email lists / nothing].
We need:
1. Our members can find and download OUR app (branded, in the store)
2. Members can sign up and see they belong to ICF Zürich
3. We can post news and announcements → members get push notifications
4. Members can see our groups and join them
5. Members can see upcoming events and RSVP
6. Members can find each other (directory)
7. Group leaders can message their groups
8. It looks good and works fast
That's it. If it does these things better than what we have, we'll try it."
Notice what’s NOT on the list: giving, Sunday live experience, chat, translation, ticketing, camp tenants, syndication, AI features. These are all differentiators — but they’re not blockers for the first pilot.
MVP Feature Set
✅ IN MVP
1. AUTHENTICATION & EMAIL
├── Zitadel (self-hosted): email/password, password reset, passkeys
├── Mailgun (paid): transactional email gateway
│ ├── EU-hosted infrastructure (GDPR compliance — data stays in Europe)
│ ├── Password reset emails
│ ├── Invite emails ("Join FEG Winterthur")
│ ├── Email verification
│ └── Proven deliverability, you have working experience with it
├── JWT-based API authentication
├── Role-based access (admin, leader, member, guest)
└── Organization access flows (see .ai/context/ORG_ACCESS_FLOWS.md)
├── Open join: auto-membership on first API call (DONE)
├── Org switching: GET /api/v1/me/organizations + org picker
├── Invite-only join: admin sends invite link/QR → member accepts
├── Leave org: member can leave, auto-removes group memberships
├── registrationMode per org (open, invite_only, by_request)
└── by_request join: deferred to Phase 2 (approval workflow + notifications)
2. SELF-SERVICE TENANT CREATION
├── Admin backend wizard: name, type, denomination, branding
├── Auto-approve, live immediately
├── Subdomain: {slug}.yourapp.com
├── Free tier (≤ 50 members, no credit card)
└── Demo tenant pre-populated for marketing site
3. ADMIN BACKEND
├── Symfony + Twig + Vue 3 islands
├── Tenant setup wizard (self-service)
├── Organization tree management (create, edit, reorder)
├── Member management (list, search, roles, invite)
├── Content management (news, events, groups)
├── Basic dashboard (member count, recent activity)
└── Super admin panel (your internal tool: tenant overview, conflict detection)
4. MODULES:
├── Personal Profile
│ ├── Edit name, photo, bio, contact info
│ ├── Privacy settings (who sees what)
│ ├── Language preference (DE, EN minimum)
│ └── Notification preferences
│
├── People Directory
│ ├── Searchable member directory (within org scope)
│ ├── Member profile view (respecting privacy)
│ └── Contact actions (email, phone — if visible)
│
├── Groups
│ ├── Group directory (browse, search, filter by type)
│ ├── Group detail (description, members, leader, schedule)
│ ├── Join group (open / request / invite-only)
│ ├── Group hierarchy (sub-groups)
│ ├── "My Groups" view
│ └── Admin: create, edit, archive, manage members
│
├── Events
│ ├── Event list (upcoming, filtered by org/group)
│ ├── Event detail (description, time, location, map)
│ ├── RSVP Level 1 ("I'll be there") + Level 2 (registration + capacity)
│ ├── Recurring events (RRULE)
│ ├── Event ↔ Group relationship
│ ├── "My Events" view
│ ├── Calendar export (iCal)
│ └── Admin: create, edit, cancel, view attendees
│
├── News
│ ├── Multi-level feed (org-scoped, cascading down tree)
│ ├── Rich text posts with images
│ ├── Post targeting (all / specific org / specific group)
│ └── Admin: create, edit, delete, schedule
│
└── Push Notifications
├── Firebase FCM (Android) + APNs (iOS)
├── Web push (service worker, for PWA users)
├── Types: news post, event reminder, group update
├── Member preferences (enable/disable per type)
└── Deep link from notification → relevant screen
5. INFRASTRUCTURE & PIPELINE
├── Symfony 7 (modular monolith, DDD structure)
├── PostgreSQL 16 + ltree + PgBouncer
├── Redis 7 (cache + Symfony Messenger transport)
├── Cloudflare R2 (media storage) + CDN
├── Mailgun (transactional email, EU-hosted)
├── Hetzner: CPX21 (app) + CPX11 (db)
├── Docker Compose (all environments)
├── Deptrac boundary enforcement
├── JSON-serializable domain events from day one
├── Observe & Protect Pipeline: audit + history consumers
├── REST API (OpenAPI documented)
├── OpenTofu for server provisioning
└── Automated CI/CD (see below)
6. FRONTEND: DUAL DELIVERY
├── React Native (Expo): iOS + Android + Web (PWA)
├── Single codebase, three targets
│
├── WEB APP (PWA) — primary delivery for MVP
│ ├── Expo Web build → Cloudflare Pages
│ ├── Per-tenant subdomain: {slug}.yourapp.com
│ ├── Service worker: offline support + web push
│ ├── "Add to home screen" prompt
│ ├── Responsive: works on mobile browsers + desktop
│ └── This is how most users access the app initially
│
└── NATIVE APP — demo/showcase in stores
├── One "demo" app published to App Store + Play Store
├── Points to the demo tenant (pre-populated data)
├── Purpose: let people see the native experience
├── Real denomination apps: published later per customer
└── Expo EAS Build for iOS + Android binaries
7. AUTOMATED DEPLOYMENT (CI/CD)
├── GitLab CI/CD (free tier)
│
├── On every push:
│ ├── PHP: lint + PHPStan (level 8) + Deptrac + unit tests
│ ├── JS: ESLint + TypeScript check
│ └── Fast feedback: < 3 minutes
│
├── On merge to main:
│ ├── Full test suite (unit + integration)
│ ├── Build Docker image → push to GitLab Container Registry
│ ├── Build Expo Web → deploy to Cloudflare Pages (staging)
│ ├── Deploy backend to staging server
│ └── Auto: no manual step
│
├── On tag / release:
│ ├── Deploy to production (backend + web app)
│ ├── Expo EAS Build for native (when needed)
│ └── OTA update push for existing native installs
│
├── Environments:
│ ├── dev: Docker Compose on laptop (€0)
│ ├── staging: Hetzner CPX11 (€4.50/mo) — auto-deployed on merge
│ └── production: Hetzner CPX21 + CPX11 (€12/mo)
│
└── Goal: push to main → live on staging in < 5 minutes
tag a release → live in production in < 10 minutes
pilot users on staging get features days before production
❌ NOT IN MVP
PHASE 2 (build next, after first pilots):
├── By-request org join (approval workflow, admin UI, notifications)
├── Giving (Stripe Connect, TWINT, recurring — the retention moat)
├── Chat (Centrifugo — members use WhatsApp until then)
├── Sunday Experience (live polls, prayer wall, sermon notes)
├── Registration Level 3-4 (custom fields, ticketing, scanning)
├── Translation (DeepL — multilingual churches can wait)
├── Tenant merge (build when first denomination consolidation happens)
PHASE 3+:
├── Pinboard
├── Event syndication (cross-tenant linking)
├── Camp/conference tenants
├── Cross-tenant org switching (multi-tenant native app)
├── ChMS adapters
├── AI Admin Pack
├── Public API
├── Seat selection / badge printing
MVP Technical Stack (Confirmed)
| Layer | Technology | Cost |
|---|---|---|
| Backend | Symfony 7, PHP 8.3+ | Free |
| Database | PostgreSQL 16 + ltree + PgBouncer | Included in Hetzner |
| Cache/Queue | Redis 7 | Included in Hetzner |
| Identity | Zitadel (self-hosted Docker) | Free |
| Mailgun (EU region) | Free tier → ~€35/mo at scale | |
| Storage | Cloudflare R2 + CDN | Free tier |
| Hosting | Hetzner CPX21 + CPX11 | €12/mo |
| Frontend | React Native (Expo) — iOS/Android/Web | Free |
| Web hosting | Cloudflare Pages (PWA) | Free |
| CI/CD | GitLab CI/CD | Free tier |
| IaC | OpenTofu | Free |
| Monitoring | Uptime Kuma + Prometheus/Grafana | Free (self-hosted) |
| Push | Firebase FCM + APNs | Free tier |
| Error tracking | Sentry (self-hosted) | Free |
| Total MVP | ~€25-35/mo |
MVP Build Plan
Phase 0: Foundation (Weeks 1-3)
INFRASTRUCTURE:
├── Hetzner servers provisioned via OpenTofu
├── Docker Compose: PostgreSQL, Redis, Symfony, Zitadel
├── GitLab repo with CI pipeline (lint, PHPStan, Deptrac, tests)
├── Staging environment auto-deploys on merge to main
├── Mailgun account (EU region) + Symfony Mailer integration
└── Cloudflare: DNS, R2 bucket, Pages project
SYMFONY PROJECT:
├── DDD directory structure (Core/, Module/, Pipeline/)
├── .ai/ directory with all guideline files
├── Deptrac configuration (all module boundaries)
├── Domain event bus (Symfony Messenger + Redis)
├── Tenant resolution middleware (subdomain → tenant context)
└── OpenAPI documentation setup
IDENTITY:
├── Zitadel deployment (Docker on Hetzner)
├── OIDC integration (Symfony JWT validation)
├── Password reset flow via Zitadel (emails via Mailgun)
├── Member auto-creation on first login
└── Role mapping
PIPELINE:
├── Audit log consumer (append-only, all events)
└── History tracker consumer (entity snapshots)
EXPO PROJECT:
├── React Native (Expo) project with Expo Router
├── Custom design system foundation (tokens, components)
├── Auth flow (OIDC → Zitadel)
├── Web build configuration (Cloudflare Pages deployment)
└── Navigation shell (tabs: Feed, Groups, Events, Directory, Profile)
Phase 1: Core Modules (Weeks 4-8)
BACKEND (API + Admin):
├── Org access flows (see .ai/context/ORG_ACCESS_FLOWS.md):
│ ├── GET /api/v1/me/organizations (cross-tenant org list for org picker)
│ ├── OrgInvitation entity + invite/accept endpoints
│ ├── DELETE /api/v1/me/organizations/{id} (leave org)
│ └── Admin UI: invitation management, registration mode config
├── People module (member CRUD, profile, privacy, directory search)
├── Groups module (group CRUD, hierarchy, membership, types, visibility)
├── Events module (event CRUD, RRULE recurrence, RSVP L1+L2, group linking)
├── News module (multi-level feed, rich text, targeting, scheduling)
├── Notification module (push via FCM/APNs, web push, preferences)
├── Self-service tenant creation wizard (admin backend)
└── Each module: Domain layer (pure PHP) → Application → Infrastructure → API
FRONTEND (parallel, starts when first APIs are stable):
├── Org access screens:
│ ├── Org picker / switcher (bottom sheet, grouped by tenant)
│ ├── Org landing page (before login — shows name, logo, registrationMode)
│ ├── Invite accept screen (resolve token → show org → accept)
│ └── Leave org flow (confirmation + auto-switch to next org)
├── Feed screen (news, pull-to-refresh, push deep link)
├── Groups screens (my groups, discovery, detail, join/leave)
├── Events screens (my events, detail, RSVP, calendar export)
├── Directory screens (search, profile view)
├── Profile screens (edit, privacy, notifications, language)
└── Basic settings (language toggle DE/EN)
Phase 2: Polish & Deployment (Weeks 8-12)
WEB APP:
├── Expo Web build → Cloudflare Pages
├── Per-tenant subdomain routing
├── Web push notifications
├── PWA manifest + "add to home screen"
├── Test on: Safari iOS, Chrome Android, Chrome/Firefox desktop
└── Demo tenant: pre-populated, linked from marketing site
NATIVE APP (demo):
├── Expo EAS Build: iOS + Android
├── Demo tenant configuration (app name, icon, splash)
├── TestFlight (iOS) + Internal testing (Android)
├── Submit to stores: one "demo" app
└── OTA update pipeline configured (Expo Updates)
ADMIN BACKEND:
├── Dashboard (member count, active users, recent activity)
├── Org tree visual editor
├── Bulk member invite (CSV or email list)
├── Content scheduling
└── Super admin: tenant overview, conflict detection
POLISH:
├── Empty states (new church, no content yet)
├── Onboarding screens (first launch)
├── Error handling, retry logic, offline states
├── Loading skeletons, animations
└── Accessibility basics
Phase 3: Pilot (Weeks 12-18)
├── Onboard 3-5 pilot churches from your network
├── Staging = beta channel (pilot users get features first)
├── Production = stable channel (after staging validation)
├── Weekly feedback calls with pilot admins
├── Rapid iteration: fix → push to staging → validate → tag release → production
├── Monitor: downloads, DAU, feature usage, crash reports
├── Success metric: >30% member adoption within 3 months
└── Decision: ready for first denomination pitch?
Onboarding & Sign-Up Process
The Funnel
MARKETING SITE SELF-SERVICE PILOT NATIVE APP
───────────── ──────────── ───── ──────────
Visitor lands on Creates tenant Church uses the Denomination
website in 5 minutes web app for commits →
real with members App Store
"Join waiting ──────▶ "Set up your ──────▶ ──────▶ submission
list" community" Proves value. (manual,
Members engage. 2-3 weeks)
OR Self-service: Feedback loop.
name, org type,
"Try the demo ──────▶ branding, first Decision point:
tenant" admin account "We want our
→ live web app own native app"
in minutes
Step 1: Marketing Site — Waiting List + Demo
WAITING LIST:
├── Simple form on the marketing site: name, email, church/org name, size
├── Stored in your DB (or simple tool like Loops, Buttondown, even a Google Sheet)
├── Purpose: gauge demand, collect leads, notify when ready
├── "We're launching soon. Be the first to try it."
└── You personally follow up with warm contacts (ICF, FEG, etc.)
DEMO TENANT:
├── A public, pre-populated tenant anyone can explore
├── Fake church: "Demo Community Zürich" with realistic data
│ ├── 3 org nodes (Demo Community → Zürich → Campus City)
│ ├── 8 groups (small groups, teams, communities)
│ ├── 15 events (services, workshops, retreats)
│ ├── 30 fake members with profiles
│ └── News feed with sample posts
├── Accessible via web: demo.yourapp.com
├── Login: "Try as member" (pre-filled demo account) or "Try as admin"
├── Read-only for visitors OR sandboxed (reset every 24 hours)
├── Purpose: let church leaders experience the product without commitment
└── Link from marketing site: "See it in action →"
Step 2: Self-Service Tenant Creation (Auto-Approve, Flag Conflicts)
Every new tenant goes live immediately. No approval gate. No waiting. Growth > control.
The reality of adoption is bottom-up:
MONTH 1: FEG Winterthur signs up. Creates tenant. Invites 80 members.
MONTH 2: FEG Zuerich signs up independently. Creates tenant. 120 members.
MONTH 3: FEG Bern signs up. 60 members.
MONTH 5: FEG Schweiz (denomination HQ) notices three of their churches
are already on the platform. They want a denomination tenant.
MONTH 6: You create the FEG Schweiz denomination tenant.
Winterthur, Zuerich, Bern merge as locations under FEG Schweiz.
Members keep everything. Zero disruption.
Blocking churches with an approval gate would have killed months 1-3. Those 260 members are your traction, your social proof, and the reason the denomination HQ pays attention.
SELF-SERVICE FLOW (instant, no approval):
1. Marketing site -> "Set up your community" button
2. STEP 1: Basics (1 min)
-- Organization name: "FEG Winterthur"
-- Type: Church / Scout group / Youth org / Other
-- Denomination / movement: [dropdown or free text]
"Do you belong to a larger movement?"
Options: ICF, FEG, Chrischona/Viva, EMK, Independent, Other
NOT a gate. Just metadata for your dashboard.
-- Your name + email
-- Creates Zitadel account + Tenant (status: ACTIVE immediately)
3. STEP 2: Structure (1 min)
-- How many locations? creates org tree
-- Or: "Just one location" flat structure
-- Pre-fills based on type
4. STEP 3: Branding (1 min)
-- Upload logo
-- Pick primary color
-- Preview: "This is how your app will look"
5. STEP 4: Invite (1 min)
-- Share link: "Join FEG Winterthur on [app name]"
-- Copy link / QR code / send via email
-- Members join immediately via web app
6. DONE. Live.
-- Web app live: feg-winterthur.yourapp.com
-- Members can join right now
-- Admin backend ready
-- Free tier for 50 members or fewer, no credit card
-- 30-day trial of all paid features
TOTAL: 5 minutes from "I want to try this" to "my members are using it."
No approval. No waiting. No friction.
Your Super Admin Dashboard: Smart Conflict Detection
Instead of approving tenants, you monitor and consolidate. The dashboard flags potential conflicts automatically.
Conflict detection rules:
- Same denomination selected: flag when 2+ independent tenants exist for same movement
- Name similarity: flag “ICF Aarau” when “ICF Movement” tenant exists
- Geography overlap: flag two churches in same city, same denomination
- Run on every tenant creation + weekly batch check
Your workflow is reactive, not blocking:
- Church signs up, goes live immediately
- Dashboard flags potential conflicts
- You reach out proactively, or the denomination does
- When ready: create denomination tenant, merge the independents as locations
- This is also a sales trigger: “Three of your churches are already using us.”
Tenant Merge: Routine Operation, Not Edge Case
With bottom-up adoption, merge is one of the most common admin operations.
Merge scenarios by frequency:
COMMON (monthly at scale):
- Independent church merges as location under denomination tenant
- Multiple independent churches: denomination creates tenant, absorbs all
OCCASIONAL:
- Two independent tenants merge (churches join forces)
RARE:
- Denomination restructuring (church moves between denominations)
Merge flow:
MERGE: "FEG Winterthur" (independent) into "FEG Schweiz" (denomination)
1. INITIATION
-- Superadmin triggers merge
-- Select: source tenant, target tenant, target org node
-- Both tenant admins confirm
2. PRE-MERGE CHECK
-- Member overlap: "12 members exist in both tenants (same Zitadel ID)"
These get OrgMembership added, not duplicated
-- Data volume: "80 members, 8 groups, 45 events, 120 news posts"
-- Preview shown to both admins
3. EXECUTION (automated)
-- Create org node "Winterthur" under FEG Schweiz (if needed)
-- Migrate members: new ones created, overlapping ones get OrgMembership
-- Migrate groups: set organizationId to new Winterthur node
-- Migrate events: set organizationId to new Winterthur node
-- Migrate news: set organizationId to new Winterthur node
-- Copy media assets to target tenant storage
-- All domain events emitted (audit trail)
4. REDIRECT and NOTIFY
-- Source tenant status: MERGED
-- feg-winterthur.yourapp.com redirects to feg-schweiz.yourapp.com
-- Push notification to migrated members:
"FEG Winterthur has joined the FEG Schweiz family!
All your groups, events, and content are here."
-- Source tenant admin gets admin role in target tenant Winterthur node
5. GRACE PERIOD (30 days)
-- Old URL still redirects
-- Old data accessible in archived state
-- After 30 days: old tenant data archived permanently
What members experience:
- Push notification: “Your community has joined FEG Schweiz!”
- Same web URL redirects seamlessly
- Their groups, events, news: all there, now under a bigger umbrella
- They now also see denomination-level news and events from sister churches
- Login unchanged (Zitadel identity is the same)
Tenant Statuses
ACTIVE -- live, members can join (default on creation)
SUSPENDED -- billing issue or policy violation
ARCHIVED -- temporary tenant expired, or manually archived
MERGED -- absorbed into another tenant, subdomain redirects
No PENDING status. No approval gate. Growth first, consolidate later.
App Delivery Strategy: Web Apps for Everyone, Native Apps for Denominations
The native app is the gate. Only denominations/movements get a native app in the stores. An individual church that belongs to a denomination does NOT get its own native app — they should call their denomination. But every church gets a web app instantly.
APP DELIVERY MATRIX:
WEB APP (PWA) NATIVE APP
───────────── ──────────
Denomination ✅ {slug}.app.com ✅ Own app in stores
(ICF Movement) (denomination-wide) (CHF 2,000 setup)
Individual church ✅ {slug}.app.com ❌ Not available
within a denomination (scoped to their "Contact your
(ICF Zürich Oerlikon) location) denomination"
Independent church ✅ {slug}.app.com ✅ Own app in stores
(not part of a (full tenant access) (if they pay for it)
denomination)
Per-Location Web Apps (Within a Tenant)
This is the key insight: a web app doesn’t have to be tenant-wide. An individual location within a denomination tenant can have its own scoped web app entry point.
ICF MOVEMENT TENANT:
Tenant-level web app:
icf.yourapp.com → full ICF Movement experience
(all locations, all content)
Per-location web apps:
icf-zurich.yourapp.com → scoped to ICF Zürich
icf-zurich-oerlikon.yourapp.com → scoped to ICF Zürich Oerlikon
icf-basel.yourapp.com → scoped to ICF Basel
icf-muenchen.yourapp.com → scoped to ICF München
Each per-location web app:
├── Same tenant, same backend, same data
├── BUT: default view scoped to that location's org node
├── Member sees: their location's news, groups, events first
├── Content from parent orgs (ICF CH, ICF Movement) cascades down
├── Member CAN navigate up to see other locations (if they want)
├── "Add to home screen" → feels like their own church's app
└── Branded: same denomination branding (ICF), location name in header
How it works technically:
URL RESOLUTION:
Request: icf-zurich-oerlikon.yourapp.com
1. Cloudflare wildcard DNS: *.yourapp.com → your server
2. Symfony middleware extracts subdomain: "icf-zurich-oerlikon"
3. Lookup: subdomain → (tenantId, orgId)
├── Table: subdomain_mappings
│ ├── "icf" → tenantId: icf-uuid, orgId: null (tenant root)
│ ├── "icf-zurich" → tenantId: icf-uuid, orgId: zurich-uuid
│ └── "icf-zurich-oerlikon" → tenantId: icf-uuid, orgId: oerlikon-uuid
└── Result: tenant = ICF Movement, scoped to org = Oerlikon
4. API responses filtered to this org scope by default
5. Web app loads with Oerlikon as the "home" context
6. Content cascade: Oerlikon news + Zürich news + ICF CH news + ICF Movement news
Admin configures this in the admin backend:
- Denomination admin goes to org tree → selects “ICF Zürich Oerlikon”
- “Enable web app for this location” → generates subdomain
- Custom slug optional (default: auto-generated from org name)
- The location admin can share their specific web app link with their members
Why this matters for adoption:
- ICF Oerlikon pastor doesn’t need to wait for the denomination to create their native app
- They get
icf-zurich-oerlikon.yourapp.comimmediately - Members “add to home screen” → it looks and feels like their own app
- When ICF Movement eventually publishes the native app, members can switch
- Zero disruption: same account, same data, native app just has better push + UX
Step 3: Native App (Denomination Only)
The native app is a denomination commitment. It’s the premium tier — a branded app in the stores with the denomination’s name, icon, and identity.
NATIVE APP RULES:
├── Available to: denominations, movements, large independent churches
├── NOT available to: individual locations within a denomination
│ "ICF Zürich Oerlikon" does NOT get its own native app
│ They use the ICF Movement native app (scoped to their location)
│ OR their per-location web app
├── Requirement: paid subscription (Movement tier or denomination deal)
├── Setup fee: CHF 2,000 (covers build config + store submission)
└── The native app serves ALL locations within the denomination
NATIVE APP PROCESS:
1. Denomination decides: "We want our own app in the stores"
2. REQUIREMENTS:
├── Movement tier subscription or denomination deal
├── Apple Developer Account (€99/year — they create it)
├── Google Play Developer Account ($25 one-time — they create it)
└── Setup fee: CHF 2,000
3. YOU DO:
├── Configure Expo build: app name, bundle ID, icons, splash screen
├── Tenant config: API endpoint, tenant slug, branding
├── EAS Build → iOS + Android binaries
├── Submit to stores (using their developer accounts)
└── Turnaround: 1-3 weeks
4. THE NATIVE APP:
├── Member downloads "ICF" app from store
├── Signs up / logs in → selects their location (Zürich Oerlikon)
├── Home screen scoped to their location (same as web app)
├── Can navigate to other locations, denomination content
├── Full native push notifications
├── OTA updates via Expo (JS changes skip store review)
└── Web app remains as fallback / desktop access
Self-Service vs. Sales-Assisted
SELF-SERVICE SALES-ASSISTED
(website → web app) (your network → deal)
Target: Individual churches, Denominations,
small orgs, curious large churches,
leaders exploring committed buyers
Entry: Free tier, no Demo call, pilot
credit card agreement, setup fee
Onboarding: 5-min web wizard Personalized: you set
up the tenant, import
data, configure the tree
App delivery: Web app (instant) Web app (immediate) +
native app (1-3 weeks)
Billing: Self-service Stripe Invoice, denomination
checkout when ready discount, annual contract
Support: Docs + email Direct line to you
Expected volume: 80% of tenants 20% of tenants
(many small churches) (most of the revenue)
MVP Implication
The web app (PWA) MUST be in MVP. Without it, every new church requires manual App Store setup — which means you can’t self-service, can’t have a demo tenant, can’t onboard pilot churches quickly. The web app is the growth engine.
This changes the MVP technical scope slightly:
ADDED TO MVP:
├── Web build of the React Native app (Expo Web / PWA)
│ ├── Same codebase as native (React Native Web via Expo)
│ ├── Hosted on Cloudflare Pages: {slug}.yourapp.com
│ ├── Service worker for offline support + web push notifications
│ └── "Add to home screen" prompt for app-like experience
│
├── Self-service tenant creation wizard
│ ├── Web-based (part of marketing site or separate onboarding app)
│ ├── Creates: Zitadel org + tenant + first admin + org tree
│ ├── Generates subdomain
│ └── Redirects to admin backend
│
└── Demo tenant
├── Pre-populated with realistic data
├── Accessible from marketing site
└── Reset daily or sandboxed per visitor
MVP Timeline Summary
Weeks 1-3: Foundation (infra, Symfony, Zitadel, pipeline, Expo shell)
Weeks 4-8: Core modules (people, groups, events, news, push — API + admin)
Weeks 8-12: Frontend polish + web app (PWA) + native demo app + deployment pipeline
Weeks 12-18: Pilot (3-5 churches on staging/beta, iterate fast)
Week 18: Decision: ready for first denomination pitch?
TOTAL: ~3 months to working product. ~4.5 months to validated pilot.
The deployment pipeline is the force multiplier. Once staging auto-deploys on merge, the iteration loop is: code → push → live on staging in 5 minutes → pilot users test → tag release → production in 10 minutes. This is how a solo founder ships as fast as a team.
MVP Definition of Done
The MVP is “done” when a pilot church admin can:
- Self-service create a tenant (wizard, live immediately)
- Configure their org structure
- Set registration mode per org (open, invite-only, by-request)
- Invite members (via link, QR code, or email via Mailgun)
- See and manage pending invitations
- Post news that members see with a push notification
- Create groups that members can browse and join
- Create events that members can RSVP to
- View a member directory
- See basic dashboard (member count, recent activity)
And a pilot church member can:
- Open the web app ({slug}.yourapp.com) on any device
- Sign up with email/password (receive verification email via Mailgun)
- Reset password (email flow via Zitadel + Resend)
- Join an open org seamlessly on first login (auto-join)
- Accept an invite link to join an invite-only org
- Switch between orgs (if member of multiple)
- Leave an org they no longer belong to
- Set language preference (DE/EN)
- See news from their church (and parent org)
- Browse and join groups
- See upcoming events and RSVP (Level 1 + 2)
- Find other members in the directory
- Receive push notifications (web push on PWA, native push on demo app)
- Edit their profile and privacy settings
And the demo native app:
- Available in App Store + Play Store
- Points to demo tenant with realistic data
- Showcases the full member experience
- Proves native performance and push notifications work
And the deployment pipeline:
- Push to main → staging auto-deploys in < 5 minutes
- Tag release → production deploys in < 10 minutes
- Pilot users on staging get features before production
If all checklists pass: ship it. Start onboarding pilots.
What Makes This MVP Enough
The MVP competes directly with Communiapp’s core offering (news, groups, events, directory, push) at a lower price with better architecture. It doesn’t yet compete on giving (Donkey Mobile’s strength) or church management (ChurchTools). That’s fine — the first pilot is about proving the member experience and the self-service onboarding, not the feature list.
The web app (PWA) is the growth engine: any church can be live in 5 minutes. The native demo app is the showcase: proves the quality. The automated pipeline is the iteration engine: ship improvements daily during pilot.
The architecture is ready for everything else. Giving, chat, Sunday, ticketing, translation, syndication — they all plug into the module system. The domain events are flowing. The Deptrac boundaries are enforced. The .ai/ directory guides every agent. When Phase 2 starts, it’s adding modules to a proven platform, not building from scratch.
Status: MVP Scope v2 — Ready to Build Next: Start coding. Scaffold the foundation. Read the .ai/ guidelines.