Architecture Overview¶
System Architecture¶
Ministry Mapper consists of two main components working together:
High-Level Architecture Diagram¶
┌──────────────────────────────────────────────────────────────────┐
│ Client Applications │
│ (Web UI, Mobile Apps, Third-party Integrations) │
└──────────────────────────────┬───────────────────────────────────┘
│
HTTP REST API (Port 8080)
│
┌──────────────────────────────▼───────────────────────────────────┐
│ PocketBase Application │
├──────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ API Layer (internal/handlers/) │ │
│ │ - Map Management (9 endpoints) │ │
│ │ - Territory Management (2 endpoints) │ │
│ │ - Configuration (1 endpoint) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Middleware Layer │ │
│ │ - Authentication & Authorization │ │
│ │ - Error Capture (Sentry) │ │
│ │ - Request Logging │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Background Jobs (internal/jobs/) │ │
│ │ - Scheduled tasks (cron-based) │ │
│ │ - Feature flag control (LaunchDarkly) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Built-in Services │ │
│ │ - Authentication (Email/Password, OAuth2, OTP, MFA) │ │
│ │ - Real-time Events (SSE) │ │
│ │ - Admin Dashboard │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└────────────┬──────────────────────┬────────────────┬──────────────┘
│ │ │
│ │ │
┌────────▼──────┐ ┌────────▼──────┐ ┌─────▼────────┐
│ SQLite │ │ Sentry │ │MailerSend │
│ Database │ │ (Error Track)│ │(Email) │
│ (/app/pb_data)│ │ │ │ │
└────────────────┘ └────────────────┘ └──────────────┘
Technology Stack¶
Backend Stack¶
| Layer | Technology | Version | Purpose |
|---|---|---|---|
| Language | Go | 1.25.0 | High-performance backend |
| Backend Framework | PocketBase | 0.36.7 | BaaS with SQLite |
| Database | SQLite | v1.40.2+ | Self-contained database |
| Web Framework | Echo | v5 | HTTP routing |
| Container | Docker | Latest | Containerization |
| Error Tracking | Sentry | v0.43.0 | Error monitoring |
| Email Service | MailerSend | v1.6.3 | Email API |
| Feature Flags | LaunchDarkly | v7.14.6 | Feature management |
| Report Generation | Excelize | v2.10.1 | Excel reports |
| AI Summaries | OpenAI GPT | v3.29.0 | Intelligent report & message summaries |
Frontend Stack¶
| Layer | Technology | Version | Purpose |
|---|---|---|---|
| Framework | React | 19.2.4 | UI library |
| Language | TypeScript | 5.9.3 | Type safety |
| Build Tool | Vite | 8.0.2 | Fast dev & build |
| Routing | Wouter | 3.9.0 | Lightweight routing |
| State Management | Context API | - | Global state |
| UI Framework | Bootstrap | 5.3.8 | CSS framework |
| Mapping | Leaflet | 1.9.4 | Interactive maps |
| Testing | Vitest | 4.1.1 | Unit testing |
| Code Quality | ESLint + Prettier | Latest | Linting & formatting |
Data Architecture¶
Entity Relationship Model¶
The system organizes data hierarchically with congregation-level isolation:
Congregation (Organization boundary)
├── Territory (Geographic region)
│ ├── Map (Building/Location)
│ │ └── Address (Individual unit)
│ └── Option (Address type classification)
├── User (System user)
│ └── Role (Permission assignment)
├── Assignment (Publisher access)
└── Message (Notification)
Core Collections¶
1. Congregations - Organization settings and boundaries - Controls multi-tenant isolation - Defines assignment duration and retry limits - Regional settings (timezone, country)
2. Territories - Geographic divisions - Contains multiple maps - Tracks aggregate completion percentage - Organizes field service areas
3. Maps - Specific locations (buildings) - Single or multi-floor structures - Geographic coordinates - Progress tracking and statistics
4. Addresses - Individual units/households - Status tracking (not done, done, not home, DNC) - Visit notes and history - Floor and unit information
5. Users - System accounts - Email/password or OAuth2 authentication - Multi-factor authentication support - Congregation-specific roles
6. Roles - Permission assignments - Three levels: read_only, conductor, administrator - Congregation-specific permissions - Role-based access control
7. Assignments - Publisher access tokens - Time-limited access links - Anonymous field worker access - Automatic expiration
8. Options - Address classifications - Customizable per congregation - Countable vs non-countable types - Affects progress calculations
9. Messages - Communications - Publisher feedback - Admin instructions - Email notifications
Frontend Architecture¶
Component Organization Pattern¶
Ministry Mapper uses a feature-based component organization:
Pages (Routes)
├── Admin Dashboard (/)
├── Publisher Map (/map/:id)
├── User Management (/usermgmt)
└── Front Page (/)
Components (Reusable UI)
├── Form Components (14 components)
├── Modal Components (24+ modals)
├── Navigation Components (28 components)
├── Table Components (9 components)
├── Map Components (7 components)
├── Middleware/Providers (5 components)
└── Static Pages (8 components)
Business Logic (Custom Hooks)
├── useTerritoryManagement
├── useMapManagement
├── useCongManagement
├── useModalManagement
├── useRealtimeSubscription
└── [4 more...]
Utilities & Types
├── TypeScript Interfaces
├── Constants
├── Helper Functions (30+)
├── PocketBase Integration
├── Authorization Policies
└── i18n Configuration
State Management Strategy¶
Four-Layer Approach:
- Global Context - Theme, language, app mode
- Custom Hooks - Domain-specific logic and data
- Local Component State - UI toggles and forms
- Persistent State - LocalStorage for preferences
Benefits: - No Redux overhead - Simpler data flow - Better code splitting - Easier testing
Data Flow Pattern¶
User Action
↓
Component Event Handler
↓
Custom Hook (validation, state management)
↓
PocketBase Utils (CRUD operations)
↓
PocketBase Backend (permissions, database)
↓
Real-time Subscription (SSE)
↓
UI Auto-updates
Key Design Patterns¶
| Pattern | Usage | Purpose |
|---|---|---|
| Middleware Wrapper | Sentry integration | Centralized error tracking |
| Event Hooks | PocketBase lifecycle | Automatic updates |
| Job Scheduler | Cron with feature flags | Scheduled operations |
| Transaction Pattern | Database operations | Data consistency |
| Link-Based Access | Assignment tokens | Anonymous access |
| Aggregate Caching | JSON fields | Fast calculations |
| Custom Hooks | Business logic | Reusable logic |
| Provider Pattern | Context providers | Global state |
| Lazy Loading | Route splitting | Performance |
| Policy Pattern | Authorization | Security rules |
Security Architecture¶
Authentication Methods¶
- Email/Password - Standard authentication with bcrypt hashing
- OAuth2 (Google) - Social login with PKCE flow
- One-Time Password (OTP) - Additional security layer
- Multi-Factor Authentication (MFA) - Enhanced security for admins
Authorization Model¶
Role-Based Access Control (RBAC):
| Role | Permissions | Use Case |
|---|---|---|
| read_only | View data only | Observers, auditors |
| conductor | Create assignments, manage maps | Field coordinators |
| administrator | Full access | System administrators |
Access Control Patterns¶
Pattern 1: Authenticated User with Role
Pattern 2: Link-Based Access
Assignment ID passed in header
+ Assignment exists and not expired
+ Assignment belongs to requested map
Pattern 3: Congregation Isolation
Every entity has congregation foreign key
+ Access rules filter by congregation
+ Prevents cross-congregation data access
Real-Time Synchronization¶
SSE Architecture¶
- PocketBase Real-time API: Server-Sent Events (SSE)
- Automatic Subscriptions: Components subscribe to collections
- Live Updates: Changes broadcast to all connected clients
- Conflict Resolution: Timestamp-based resolution
- Visibility Detection: Auto-refresh when tab becomes active
Subscription Pattern¶
// Components subscribe to data changes
useRealtimeSubscription('addresses', (data) => {
// UI updates automatically
});
Background Jobs¶
Scheduled Tasks¶
| Job | Schedule | Purpose |
|---|---|---|
| Assignment Cleanup | Every 5 min | Delete expired assignments |
| Territory Aggregates | Every 10 min | Update progress statistics |
| Message Processing | Every 30 min | Send message notifications |
| Instructions | Every 30 min | Send admin messages |
| Note Updates | Every 1 hour | Notify of note changes |
| Monthly Reports | 1st of month | Generate Excel reports (with optional AI summaries) |
| Unprovisioned Users | Daily 01:00 UTC | Enforce user lifecycle (warnings → disable → delete) |
| Inactive Users | Daily 01:30 UTC | Warn and disable inactive accounts |
Feature Flag Control¶
All background jobs controlled by LaunchDarkly feature flags: - Enable/disable jobs without deployment - Gradual rollout capabilities - Emergency off switch
AI/LLM Integration¶
Ministry Mapper integrates with OpenAI's GPT model for intelligent text summarisation. This is an optional feature gated by the enable-report-ai-summary LaunchDarkly flag.
Model: GPT (latest available via openai-go SDK v3.29.0)
Temperature: 0.3 (factual, deterministic output)
Response Format: JSON mode for structured data
Use Cases:
| Context | Job | Output |
|---|---|---|
| Monthly Excel reports | generateMonthlyReport |
Per-territory summary and key_points |
| Publisher message digests | processMessages |
overview and key_themes |
| Congregation notes digests | processNotes |
overview and key_themes |
Graceful Degradation: If OPENAI_API_KEY is not set or the enable-report-ai-summary flag is off, the system falls back to reports and emails without AI-generated content — no errors are raised.
Frontend Optimizations¶
- Code Splitting: Lazy-loaded routes
- Bundle Optimization: Tree shaking, minification
- React 19 Compiler: Automatic memoization
- PWA Caching: Service worker for static assets
- Virtualized Lists: React-window for large datasets
Backend Optimizations¶
- Database Indexes: 25+ indexes for fast queries
- Aggregate Caching: Pre-calculated statistics in JSON
- Connection Pooling: Efficient database connections
- Transaction Batching: Reduce database round-trips
Deployment Architecture¶
Docker Containerization¶
Backend: - Multi-stage Docker build - Alpine base for small footprint - Volume mounts for data persistence - Health checks for reliability
Frontend: - Static build served by CDN - Edge caching for fast delivery - Progressive Web App capabilities
Infrastructure Options¶
- Hosted Service (Recommended)
- ministry-mapper.com
- Managed infrastructure
-
Automatic updates
-
Self-Hosted
- Railway, Render, DigitalOcean
- Requires technical expertise
- Full control
Monitoring & Observability¶
Error Tracking¶
- Sentry Integration: Both frontend and backend
- Error Categorization: By severity and type
- Source Maps: Debugging minified code
- Release Tracking: Version-specific errors
Logging¶
- Backend: Structured JSON logs
- Frontend: Console logging in development
- Production: Errors sent to Sentry
- Audit Trail: User actions tracked
Scalability Considerations¶
Current Limitations¶
- SQLite single-writer limitation
- Suitable for small to medium congregations (< 1000 concurrent users)
- Vertical scaling (more powerful server)
Future Scalability¶
- PocketBase supports read replicas
- Can migrate to PostgreSQL if needed
- CDN caching for static assets
- Edge functions for API optimization
Technology Decisions¶
Why These Technologies?¶
React 19: Latest features, automatic optimization, smaller bundle
TypeScript: Type safety, better IDE support, fewer runtime errors
Vite: Fast dev server, instant HMR, optimized builds
PocketBase: Self-hosted, no vendor lock-in, easy to maintain
Wouter: Lightweight (3KB vs 40KB for React Router)
Bootstrap: Battle-tested, comprehensive components, good accessibility
Leaflet: Free maps, no API limits, lightweight
SQLite: Self-contained, no separate database server, perfect for self-hosting
Next Steps¶
- Backend Setup - Configure the backend
- Frontend Setup - Deploy the frontend
- Security Guide - Security best practices