216 lines
10 KiB
Markdown
216 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.
|
|
|
|
Data definitions
|
|
✓ Schemas validated
|
|
0 modules · 0 tables
|
|
✓ Migrations validated
|
|
1 migration · checksums valid
|
|
core:0000_identity_core_tables · f8f2086ef06f
|
|
|
|
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 an explicit platform-owner bootstrap command are the next
|
|
architectural phase; Doctor does not diagnose authorization, the `apps/api` HTTP transport, runtime
|
|
module health, or production storage yet, 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.
|