The documentation still described Phase 5D as in progress, Phase 6 as blocked, and a disposable-runner isolation proof as a prerequisite for opening the real pull request. All five passes and the independent whole-repository re-audit have landed, so those statements no longer match the accepted operating model. The README's current status now records Phase 5D as complete under the current trusted-contributor, not-yet-deployed threat model, with Phase 6 unblocked, and gains a pass 5 closure paragraph covering the re-audit, the repository-local supply-chain and dependency fixes, the accepted trusted-code-only CI boundary, and what remains required before untrusted CI or a public launch. The pass 1-4 paragraphs keep their technical content unchanged; only their tense changes, so each reads as what was outstanding at the close of that pass rather than as a current claim. `platform-architecture.md` no longer stops at pass 1 or says passes 2-5 are unfinished; it summarizes all five passes and defers the remaining operational limitations to the security document. `security.md` states the trusted-code-only operating rule explicitly and replaces "CI blockers before the real pull request is opened" with "Requirements before executing untrusted contributions", framing the five hardening items as prerequisites for relaxing that rule rather than as Phase 6 blockers, and naming an isolated hosted-runner service as an accepted alternative. The Gitea 1.24.2 warnings, the scope of `persist-credentials: false`, and the unverified runner topology and job-token authority are preserved verbatim; no external Gitea setting is claimed. The launch checklist is marked as gating a public launch, not development. Both Doctor examples are corrected to the real three-migration output, adding `core:0002_authorization_integrity · 634294731180`. The stale sentence calling Core authorization the next architectural phase is refreshed. ADRs 0017-0020 are untouched: their statements that later passes were outstanding are historical records made when each was accepted. Documentation only — no production code, test, workflow, dependency, migration, or schema change. Co-Authored-By: Claude Opus 5 <[email protected]>
220 lines
10 KiB
Markdown
220 lines
10 KiB
Markdown
# Repository workflow
|
|
|
|
## Prerequisites
|
|
|
|
- Node.js 24 LTS (`.node-version` and `.nvmrc` pin the reviewed patch)
|
|
- pnpm 11.12.0
|
|
- Docker with the Compose plugin for local infrastructure
|
|
|
|
Install dependencies from the committed lockfile:
|
|
|
|
```bash
|
|
pnpm install --frozen-lockfile
|
|
```
|
|
|
|
## Quality gates
|
|
|
|
```bash
|
|
pnpm format:check # formatting without mutation
|
|
pnpm lint # Biome recommended rules
|
|
pnpm boundaries # architectural directions, UI ownership, and cycles
|
|
pnpm modules:validate # installed module manifests, compatibility, and dependency graph
|
|
pnpm migrations:validate # offline Core + module migration inventory and exact checksums
|
|
pnpm identity:schema:validate # detects drift against the pinned Better Auth schema generator
|
|
pnpm migrations:plan # read-only comparison with PostgreSQL applied history
|
|
pnpm migrations:apply # locked, transactional application of the pending batch
|
|
pnpm doctor # build-first, read-only human readiness dashboard
|
|
pnpm typecheck # strict TypeScript
|
|
pnpm test # Vitest
|
|
pnpm test:migrations:integration # production runner against disposable PostgreSQL
|
|
pnpm build # Turborepo package build graph
|
|
pnpm verify # every code-only gate; never plan or apply
|
|
```
|
|
|
|
The lint, typecheck, and test commands run both repository-root checks and every matching
|
|
package-level Turborepo task. New packages add their own `lint`, `typecheck`, and `test` scripts;
|
|
the root verification command discovers them automatically.
|
|
|
|
`pnpm modules:validate` builds the workspace, then scans `modules/*` without a central registry. A
|
|
missing or empty modules directory is valid and reports zero installed modules. Installed modules
|
|
must produce the compiled JavaScript entrypoints declared by their static manifests. Optional
|
|
schema entrypoints are loaded and validated for table ownership, namespacing, duplicates, and
|
|
foreign-key isolation; this command does not connect to PostgreSQL or run migrations.
|
|
|
|
`pnpm migrations:validate` also builds first, completes static module discovery, and atomically
|
|
checks Core's own `core/drizzle` migration directory together with every declared module Drizzle
|
|
migration directory. It reports Core's migration first, followed by dependency-first module
|
|
inventories, with exact SHA-256 checksums, without importing module code, connecting to
|
|
PostgreSQL, or executing SQL. Modules with no migration history are valid.
|
|
|
|
`pnpm identity:schema:validate` regenerates Better Auth's canonical schema with the pinned local
|
|
`auth` CLI into a temporary, package-local directory, structurally compares every core model
|
|
(columns, types, nullability, defaults, foreign keys, and indexes) against the checked-in
|
|
`core/src/identity/schema.ts`, and always removes the temporary output. It requires no
|
|
`DATABASE_URL`. See [Identity](identity.md) for the full upgrade workflow.
|
|
|
|
## Developer Doctor
|
|
|
|
Run the complete local readiness dashboard with:
|
|
|
|
```bash
|
|
pnpm doctor
|
|
```
|
|
|
|
The root command follows the repository's build-first convention, so it works from a clean checkout
|
|
without preexisting ignored `dist` output. The build itself may create ignored compiled artifacts;
|
|
the diagnostics that follow are operationally read-only. Doctor never edits configuration, applies
|
|
migrations, creates the Core history table, acquires the migration apply lock, starts module server
|
|
entrypoints, provisions storage, or invokes Docker.
|
|
|
|
Doctor reports a fixed, deterministic set of checks:
|
|
|
|
- The active Node.js version against the repository's declared engine range.
|
|
- Static module discovery and dependency-first ordering.
|
|
- Schema discovery, including validated module and table counts. This imports compiled schema
|
|
definitions, which the module contract requires to perform no configuration reads, I/O, or
|
|
database connection.
|
|
- Offline migration discovery for Core's own identity migration and every module, with safe
|
|
identities and consistently truncated checksums, Core listed first.
|
|
- PostgreSQL connectivity and read-only applied-history planning when `DATABASE_URL` is configured.
|
|
- Identity runtime configuration: skipped (not a failure) when no secret, base URL, or trusted
|
|
origins are set; otherwise validated with `createIdentityConfig` and reported pass or failure.
|
|
This check never constructs Better Auth or opens a database connection.
|
|
- Object storage as skipped while Core has no production storage client or configuration contract.
|
|
|
|
Every check has a stable ID and one of four states: pass, warning, failure, or skipped. Independent
|
|
checks continue after a failure; a failed prerequisite causes only its dependent checks to be
|
|
skipped. Pending or approval-blocked migrations are warnings and are never applied. Invalid
|
|
history, checksum disagreement, unknown applied migrations, or a failed configured connection are
|
|
failures. If `DATABASE_URL` is missing, PostgreSQL is skipped and all static checks still run.
|
|
|
|
`READY` means every check passed. `READY WITH WARNINGS` means no check failed but at least one check
|
|
warned or was skipped. Both results exit zero. `NOT READY` means at least one check failed and exits
|
|
one. Meaning never depends on color, a TTY, timestamps, or interactive input.
|
|
|
|
For the current repository with no installed modules and no `DATABASE_URL`, the concise inventory
|
|
ends like this:
|
|
|
|
```text
|
|
Modules
|
|
✓ Module discovery complete
|
|
0 modules installed
|
|
✓ Dependency graph valid
|
|
Dependency order is empty.
|
|
✓ Permission registry composed
|
|
1 permission registered
|
|
|
|
Data definitions
|
|
✓ Schemas validated
|
|
0 modules · 0 tables
|
|
✓ Migrations validated
|
|
3 migrations · checksums valid
|
|
core:0000_identity_core_tables · f8f2086ef06f
|
|
core:0001_authorization_core_tables · 830e1fbc26d0
|
|
core:0002_authorization_integrity · 634294731180
|
|
|
|
PostgreSQL
|
|
○ Connection check skipped
|
|
DATABASE_URL is not configured.
|
|
○ Migration plan skipped
|
|
A validated migration inventory and configured PostgreSQL connection are required.
|
|
|
|
Identity
|
|
○ Identity configuration skipped
|
|
Core identity schema defines 4 tables (ekklesia_core_account, ekklesia_core_session, ekklesia_core_user, ekklesia_core_verification).
|
|
Identity runtime configuration (signing key, base URL, trusted origins) is not set.
|
|
|
|
Object storage
|
|
○ Check unavailable
|
|
Core storage integration has not been implemented yet.
|
|
|
|
Result: READY WITH WARNINGS
|
|
```
|
|
|
|
Doctor is a local, human-readable summary. `pnpm verify`, `pnpm ci:verify`, infrastructure smoke,
|
|
and migration smoke remain the authoritative automated evidence because they exercise formatting,
|
|
boundaries, types, tests, builds, containers, and live mutation/rollback behavior that Doctor does
|
|
not repeat. Core authorization and the explicit platform-owner bootstrap command have since shipped,
|
|
and Doctor reports the composed permission registry; it still does not diagnose grant evaluation, the
|
|
`apps/api` HTTP transport, runtime module health, or production storage, and it never constructs an
|
|
operational Better Auth instance, starts the API, or claims sign-in works. See [API](api.md) for
|
|
`pnpm api:start` and the identity HTTP transport this repository now has.
|
|
|
|
Migration planning and application require `DATABASE_URL`. Keep it in the uncommitted `.env`
|
|
created from `.env.example`:
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
pnpm migrations:plan
|
|
pnpm migrations:apply
|
|
```
|
|
|
|
Planning completes discovery and validation, reads Core's applied history, and prints a
|
|
deterministic applied/pending/approval-blocked inventory. It is read-only and can become stale if
|
|
another process applies migrations afterward. Applying is an explicit mutating operation: it
|
|
acquires the bounded Core advisory lock, rereads history, checks every destructive approval, and
|
|
executes the complete pending aggregate in one transaction. A later failure rolls back all schema
|
|
and history changes from that invocation; migrations committed by earlier invocations remain.
|
|
|
|
The default command composition supplies no destructive approvals. There is no `--force`, wildcard,
|
|
or source-controlled approval escape hatch; deployments must later compose a trusted external
|
|
provider that supplies an exact module ID, migration identity, and checksum triple.
|
|
|
|
Migration-runner unit tests cover orchestration through its narrow database port. Run the separate
|
|
live suite when changing migration behavior:
|
|
|
|
```bash
|
|
pnpm test:migrations:integration
|
|
```
|
|
|
|
It requires Docker with Compose, starts the pinned PostgreSQL image with a generated throwaway
|
|
credential and a Docker-assigned loopback port, creates an isolated database for each scenario,
|
|
and removes its containers, network, databases, and volume afterward. It exercises the production
|
|
adapter and real PostgreSQL transactions, history, advisory locks, approvals, and sanitized errors.
|
|
It remains outside the Docker-free `pnpm verify` command.
|
|
|
|
CI runs `pnpm ci:verify`, which adds Compose configuration validation to `pnpm verify`. Separate
|
|
`infrastructure-smoke` and `migration-smoke` jobs run the live service and migration suites. The
|
|
exact pull-request context to add to `main` branch protection after merge is
|
|
`CI / migration-smoke (pull_request)`. The explicit `ci:verify` suffix avoids pnpm's built-in `ci`
|
|
install command.
|
|
|
|
## Development infrastructure
|
|
|
|
Create an untracked local environment file before using Compose:
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
pnpm infrastructure:up
|
|
```
|
|
|
|
Stop services or follow their logs with:
|
|
|
|
```bash
|
|
pnpm infrastructure:down
|
|
pnpm infrastructure:logs
|
|
```
|
|
|
|
Exercise both services with isolated, throwaway credentials and Docker-assigned host ports:
|
|
|
|
```bash
|
|
pnpm infrastructure:smoke
|
|
```
|
|
|
|
The smoke test verifies PostgreSQL password authentication and authenticated S3 list, put, get,
|
|
head, and delete operations. It also proves invalid database passwords, anonymous object access,
|
|
and invalid S3 signatures are rejected. Its containers, network, and volumes are removed on exit.
|
|
When the smoke script itself runs in a Docker-based CI job, it temporarily joins that job container
|
|
to the isolated Compose network and reaches object storage by its service name. Direct host runs
|
|
continue to use Docker-assigned random ports published only on loopback.
|
|
|
|
PostgreSQL and the S3 endpoint bind to `127.0.0.1` only. Compose uses persistent named volumes;
|
|
`infrastructure:down` preserves data. The S3 service creates the configured development bucket
|
|
idempotently at startup.
|
|
|
|
The checked-in credentials are safe only for local development. Deployed secrets must come from
|
|
an environment-appropriate secret provider and must not be committed.
|
|
|
|
Docker is not installed in every contributor environment. Compose validation and live service
|
|
health therefore run separately from the code-only `pnpm verify` gate.
|