# Platform architecture Ekklesia is a long-lived platform from which churches can compose many applications and user experiences. It begins as a modular monolith so contracts can stabilize before distribution is introduced. ## Dependency model The arrows below mean "depends on." Presentation and composition depend on stable lower-level contracts; infrastructure never learns individual feature names. ```text Surface Builder configuration -> Surfaces -> public capability contracts ^ | HTTP/API and client contracts | Feature Modules -> Module SDK / platform contracts <- Core implementations ``` The four ownership layers are: 1. **Core** orchestrates generic platform infrastructure: startup, identity, permissions, configuration, database connectivity, storage, events, jobs, module discovery, and lifecycle. 2. **Modules** own backend domain behavior, data schemas, resources, actions, routes, events, permissions, and jobs. 3. **Surfaces** own every presentation concern: components, renderers, layout, navigation, accessibility, interaction, branding, and client state. 4. **Surface Builder** stores validated declarative composition. It selects capabilities and surface-owned renderers but contains neither executable code nor module business logic. Modules do not own UI. For example, Calendar data, actions, and permissions will live in `modules/calendar`; Calendar renderers for a dashboard or public website will live in those surfaces. ## Stable seams - Modules use public SDK ports and injected Core services, never undocumented Core internals. - Modules do not import another module's schema or private code. Integrations use public service contracts, capabilities, events, or APIs. - Surfaces consume API/client and capability contracts, never feature-module packages. - Core discovers feature modules generically. It contains no feature-specific imports or conditional branches. - Deployable apps are thin composition roots and do not become domain-logic owners. - Generated bootstrap artifacts may connect discovered entry points at the application edge; they do not become manually maintained Core registries. ## Security invariants - Authorization is enforced server-side. - Secrets are isolated from public configuration and logs. - Authentication tokens, private form content, prayer requests, and pastoral information are not logged. - Sensitive actions are designed for auditability without copying sensitive content into audit records. - Private objects use signed access and namespaced storage paths. - Every network service starts from least-privilege and local-only development defaults. ## Current implementation status Implemented now: the Phase 1 repository and infrastructure foundation plus public module contracts, static versioned manifests, independent capability versions and dependency ranges, automatic filesystem discovery, compiled server loading, runtime-definition verification, staged capability registration, dependency-ordered startup and reverse shutdown, rollback, and a backend-only module template. Optional compiled schema entrypoints now contribute validated, namespaced module-owned Drizzle tables to a deterministic aggregate without connecting to a database. Optional module-owned Drizzle migration directories now produce an atomic dependency-ordered offline inventory with validated metadata, explicit destructive-change declarations, and exact SHA-256 checksums. Core can now compare that inventory with its fixed PostgreSQL history table, produce a read-only plan, and apply the complete pending batch under a session advisory lock and one transaction. Destructive migrations require an exact externally supplied approval bound to module, identity, and checksum. Target architecture, not yet implemented: production approval-provider composition, live PostgreSQL migration-runner integration coverage, Better Auth, permission enforcement, physical storage-bucket provisioning, Surface SDK, richer public resource and action contracts, API server, dashboard, Builder, and reference feature modules.