diff --git a/CLAUDE.md b/CLAUDE.md index 43e2af8..ffdab92 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,27 +6,60 @@ contents, because restated details drift. ## What this repository is -Ekklesia is a modular, self-hosted church platform built as a strictly layered pnpm/TypeScript -monorepo: +Ekklesia is a modular, self-hosted church platform. **This repository is the platform** — Core, the +API, the Dashboard and display shell, and the public `@ekklesia/*` module-development packages — built +as a strictly layered pnpm/TypeScript monorepo: - **Core** (`core/`) owns platform infrastructure: identity, database connectivity, migration - execution, module discovery/lifecycle, and other feature-agnostic services. Core never imports a - feature module, a surface, or an app. -- **Modules** (`modules/*`, template at `templates/module`) are independently versioned product - packages. They own their own data and migrations, declare capabilities/permissions through - `@ekklesia/contracts` and `@ekklesia/module-sdk`, and must never import Core, another module, or a - surface directly. Per ADR 0021 a module owns its UI; manifest v7 permits independently optional - primary and full-viewport display artifacts, authored in React against the same role-neutral - `@ekklesia/module-ui-sdk` ABI. Ekklesia mounts each through a separate surface role, while - `pnpm boundaries` still rejects every non-React UI framework and non-`.tsx` presentation source. + execution, module discovery/lifecycle, devices, and other feature-agnostic services. Core never + imports a feature module, a surface, or an app. +- **Modules** are independently versioned product packages. First-party modules live in **their own + repositories** (Signage is `Zayin/Signage`), build against the published `@ekklesia/*` packages + (ADR 0053), and reach an installation as a Module Package (ADR 0049) installed into module storage + outside the image (ADR 0048). No module source lives in this repository; `templates/module` is the + example, and `modules/` is only an optional, ignored local installed-modules directory. A module owns + its data, migrations, and **its own domain UI** (ADR 0021), declares capabilities/permissions through + `@ekklesia/contracts` and `@ekklesia/module-sdk`, and never imports Core, another module, or a + surface. Manifest v8 permits independently optional primary and full-viewport display artifacts, + authored in React against the role-neutral `@ekklesia/module-ui-sdk` ABI; database access is the + Module Database ABI v1 (ADR 0050). - **Surfaces** (`surfaces/*`) own the containing application shell, navigation, and every - presentation concern a module does not. They consume public API/client contracts only, never Core - or module internals directly. + presentation concern a module does not. The shell **hosts** module UI through the generic loader; + it never rebuilds a module's domain screens. Surfaces consume public API/client contracts only. These boundaries are enforced by `pnpm boundaries` (`scripts/check-boundaries.ts`), not just documented. Read `docs/architecture/repository-boundaries.md` and `docs/architecture/platform-architecture.md` before proposing any change that crosses a layer. +## Product direction lives beside this repository + +The current roadmap and product/interface design contract are `ROADMAP.md` and `DESIGN.md` in the +parent development directory (`../ROADMAP.md` and `../DESIGN.md` from a checkout in the standard +`~/development/ekklesia/` layout). They are deliberately **not** committed here; do not copy them into +this repository to make them available. They are authoritative for product direction: read the +relevant stages and sections before designing a change. If this repository's documentation disagrees +with them, flag the conflict, correct the repository-local documentation where appropriate, and never +silently follow the stale text. Architectural decisions still change only through ADRs (below). + +Rules from those documents that every change here must respect: + +- **Ownership.** Modules own their domain data, behaviour, and UI. Shared resources — displays and + devices, accounts and identity, roles and authorization, branding, mail, push, storage providers, + and module installation/lifecycle — belong to the platform, and modules consume them. +- **Branding.** Normal user-facing UI never hard-codes "Ekklesia"; product identity comes from + installation branding (ADR 0046). Package names, diagnostics, logs, and developer tooling may. + Existing hard-coded shell strings are known debt for Stage 1, not a pattern to copy. +- **Visual direction.** Simple, minimal, and calm; responsive for phone, tablet, and desktop; light, + dark, and system modes. Normal UI colours come only from the shared design tokens + (`@ekklesia/design-tokens`, ADR 0039) — never a hard-coded colour. +- **No browser-native dialogs.** `window.alert`, `window.confirm`, and `window.prompt` are prohibited + in product UI. Destructive actions use in-product confirmation proportional to their impact. +- **Displays are transitional.** Displays are platform-owned. Today's device pairing (the Dashboard + sidebar's *Display devices* panel) and Signage's own display roster are a transitional + implementation that Stage 1 migrates to **Settings → Displays**. Fix defects in them, but do not + build the Stage 1 Settings, global Displays, theme editor, module installer, or responsive shell + redesign early, and keep existing paired displays working across any change. + ## ADRs are authoritative `docs/architecture/decisions/` records durable architectural decisions. **Accepted ADRs are @@ -43,6 +76,7 @@ At minimum, read the current versions of: - `docs/architecture/decisions/README.md` and every ADR relevant to your change - `docs/architecture/platform-architecture.md` and `docs/architecture/repository-boundaries.md` - `README.md` (current platform status — what is and is not implemented) +- `../ROADMAP.md` and `../DESIGN.md` (current product direction; see above) - `docs/development/repository-workflow.md` and `docs/development/testing.md` - `CONTRIBUTING.md` @@ -52,8 +86,16 @@ your own memory of a prior session** — treat stale assumptions as a bug to cat ## Working conventions -- Work on a clean branch off an up-to-date `main`; never commit or push directly to `main`; never - change branch-protection settings. +- The canonical repositories are on the church Gitea under the `Zayin` organization: + `ssh://git@192.168.68.76:2222/Zayin/Ekklesia.git` (this one), `Zayin/Signage.git`, and + `Zayin/Classroom_Desktop.git`. A local clone may be behind the server: `git fetch --prune --tags` + and branch from `origin/main`, never from whatever is checked out. +- One branch per PR, off an up-to-date `origin/main`. Never commit or push directly to `main`, never + merge your own PR, and never change branch-protection settings. +- Never create or push a release tag. Release tags belong to the human maintainer. +- A change that needs both a platform contract change and a module change is two PRs: Core first, on + its own branch, with the compatibility boundary stated explicitly; then the module. Do not copy + platform logic into a module to avoid making the correct Core change. - Keep PRs focused on one bounded slice. Record major architectural changes in an ADR rather than burying them in an implementation. - Add or update tests when you change a contract or architectural rule. New behavior needs new