Files
Ekklesia/core/src/diagnostics/doctor-report.ts
T
ekklesiaandClaude Sonnet 5 679a5d225c
CI / verify (pull_request) Successful in 25s
CI / infrastructure-smoke (pull_request) Successful in 12s
CI / migration-smoke (pull_request) Successful in 22s
feat: establish core identity foundation
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]>
2026-07-21 16:39:15 -05:00

58 lines
1.8 KiB
TypeScript

import type { DoctorCheck, DoctorCheckId, DoctorReport, DoctorResult } from "./doctor.js";
interface DoctorSection {
readonly checkIds: readonly DoctorCheckId[];
readonly title: string;
}
function section(title: string, checkIds: readonly DoctorCheckId[]): DoctorSection {
return Object.freeze({ checkIds: Object.freeze([...checkIds]), title });
}
const sections: readonly DoctorSection[] = Object.freeze([
section("Platform", ["platform.runtime"]),
section("Modules", ["modules.discovery", "modules.dependencies"]),
section("Data definitions", ["schemas.discovery", "migrations.discovery"]),
section("PostgreSQL", ["postgresql.connection", "postgresql.plan"]),
section("Identity", ["identity.configuration"]),
section("Object storage", ["object-storage.integration"]),
]);
const statusSymbols: Readonly<Record<DoctorCheck["status"], string>> = Object.freeze({
failure: "✗",
pass: "✓",
skipped: "○",
warning: "!",
});
const resultLabels: Readonly<Record<DoctorResult, string>> = Object.freeze({
"not-ready": "NOT READY",
ready: "READY",
"ready-with-warnings": "READY WITH WARNINGS",
});
export function formatDoctorReport(report: DoctorReport): readonly string[] {
const checks = new Map(report.checks.map((check) => [check.id, check]));
const lines = ["Ekklesia Doctor", ""];
for (const [sectionIndex, section] of sections.entries()) {
lines.push(section.title);
for (const checkId of section.checkIds) {
const check = checks.get(checkId);
if (!check) {
continue;
}
lines.push(` ${statusSymbols[check.status]} ${check.summary}`);
for (const detail of check.details) {
lines.push(` ${detail}`);
}
}
if (sectionIndex < sections.length - 1) {
lines.push("");
}
}
lines.push("", `Result: ${resultLabels[report.result]}`);
return Object.freeze(lines);
}