Adds Core-owned identity contracts, a Core-owned Better Auth database schema (ekklesia_core_user/session/account/verification), a first-class Core-owned migration source that coexists with module-owned migrations under the exact existing migration system, and an explicit Better Auth construction boundary. No authentication endpoint or sign-in UI is exposed yet (ADR 0010). Co-Authored-By: Claude Sonnet 5 <[email protected]>
96 lines
5.8 KiB
Markdown
96 lines
5.8 KiB
Markdown
# 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.
|
|
Hermetic integration coverage now exercises those contracts through the production adapter against
|
|
the pinned PostgreSQL container, including real DDL rollback and advisory-lock concurrency. The
|
|
Core-owned Doctor composes those existing services into a deterministic terminal readiness report:
|
|
static module, schema, and migration validation always run when their prerequisites succeed, while
|
|
PostgreSQL history planning runs only when configured. Schema inspection evaluates compiled schema
|
|
definition entrypoints, which the module contract requires to be side-effect-free; Doctor never
|
|
imports or starts module server entrypoints. It does not apply migrations or modify PostgreSQL, and
|
|
it honestly skips object storage because no production Core storage service exists yet.
|
|
|
|
Phase 4A adds the Core identity foundation. Core owns a Better Auth-backed identity schema
|
|
(`ekklesia_core_user`, `ekklesia_core_session`, `ekklesia_core_account`,
|
|
`ekklesia_core_verification`) reachable only through Ekklesia-owned contracts and an explicit
|
|
Core-owned Better Auth construction boundary; modules never import Better Auth or receive a raw
|
|
database client. That schema ships as a first-class Core-owned migration source that reuses the
|
|
exact migration format, checksum rule, planner, and transactional runner Phase 3 already
|
|
established, ordered before module migrations in the same aggregate. See
|
|
[ADR 0010](decisions/0010-core-identity-and-better-auth-adoption.md) and
|
|
[the identity development guide](../development/identity.md). Phase 4A does not mount an HTTP
|
|
handler or expose a sign-in endpoint; no user can authenticate yet.
|
|
|
|
The next architectural phase is identity HTTP transport and an explicit enrollment policy. Other
|
|
target architecture not yet implemented includes production approval-provider composition,
|
|
permission enforcement, physical storage-bucket provisioning, Surface SDK, richer public resource
|
|
and action contracts, API server, dashboard, Builder, and reference feature modules.
|