feat: consolidate database management work

Add catalog-owned logical relationships and runtime snapshots, extend the database-management UI and validation coverage, and document the updated operational workflow.

Keep active sensitive-generation status in a tooltip and indicator, and update the layout E2E to follow the history action in its new database-scoped location.
This commit is contained in:
Codex
2026-09-01 14:46:55 +02:00
parent f586152636
commit 076c9742c5
73 changed files with 6966 additions and 610 deletions
+65 -2
View File
@@ -2,6 +2,7 @@ import { buildInstallationContract } from "../workspaces/contracts.js";
import { resolveBinding } from "../workspaces/bindings.js";
import type { WorkspaceRegistry } from "../workspaces/registry.js";
import type { WorkspaceDescriptor } from "../workspaces/schema.js";
import { discoverWorkspaceSecretRequirements } from "../workspaces/secret-requirements.js";
import type { WorkspaceSecretStore } from "../workspaces/secret-store.js";
import { createConcreteDiagnosticAdapters } from "../workspaces/diagnostics.js";
import { CatalogOperationCoordinator } from "./operation-coordinator.js";
@@ -25,6 +26,21 @@ export interface CatalogListItem extends Omit<WorkspaceDatabase, "id"> {
workspaceName: string;
workspaceDescription?: string;
workspaceAvailable: boolean;
workspaceRevision: { commit: string; blob: string } | null;
workspaceEvidence: {
sourceType: "filesystem" | "http" | "s3" | null;
state:
| "not_declared"
| "materialized_current_revision"
| "configuration_required"
| "configured_unverified"
| "workspace_unavailable";
};
runtimeBinding: {
transport: DatabaseBinding["transport"];
configurationState: "ready" | "configuration_required";
sessionTransportSupported: boolean;
} | null;
configured: boolean;
secrets: Record<CatalogSecretName, boolean>;
}
@@ -68,6 +84,43 @@ function secretState(store: WorkspaceSecretStore, workspaceId: string): Record<C
))) as Record<CatalogSecretName, boolean>;
}
function workspaceRuntimeState(
store: WorkspaceSecretStore,
workspace: WorkspaceDescriptor,
secretRoots: readonly string[],
): NonNullable<CatalogListItem["runtimeBinding"]> {
const requirements = discoverWorkspaceSecretRequirements(workspace, process.env);
const secretVariables = new Set(requirements.map(({ variable }) => variable));
const effective = resolveBinding(workspace, "DWH", process.env, secretRoots);
const configurationRequired = requirements.some(({ id, required }) => (
required && !store.has(workspace.workspace.id, id)
)) || effective.missing.some((variable) => !secretVariables.has(variable));
return {
transport: effective.transport,
configurationState: configurationRequired ? "configuration_required" : "ready",
sessionTransportSupported: effective.transport !== "ssh_tunnel",
};
}
function workspaceEvidenceState(
store: WorkspaceSecretStore,
workspace: WorkspaceDescriptor,
): CatalogListItem["workspaceEvidence"] {
const source = workspace.evidence?.source;
if (!source) return { sourceType: null, state: "not_declared" };
if (source.type === "filesystem") {
return { sourceType: source.type, state: "materialized_current_revision" };
}
const configurationRequired = discoverWorkspaceSecretRequirements(workspace, process.env)
.some(({ connector, id, required }) => (
connector === "evidence" && required && !store.has(workspace.workspace.id, id)
));
return {
sourceType: source.type,
state: configurationRequired ? "configuration_required" : "configured_unverified",
};
}
export class CatalogService {
private readonly adapters = createConcreteDiagnosticAdapters();
@@ -91,7 +144,8 @@ export class CatalogService {
const byWorkspace = new Map(configured.map((database) => [database.workspaceId, database]));
const active = await Promise.all(workspaces.map(async (entry) => {
const database = byWorkspace.get(entry.id);
const { workspace } = await this.registry.read(entry.id);
const { workspace } = await this.registry.readPinned(entry.id, entry.revision.commit);
const runtimeDatabaseBinding = yamlBinding(workspace, this.secretRoots);
const base = database ?? {
workspaceId: entry.id,
engine: "postgres" as const,
@@ -100,7 +154,7 @@ export class CatalogService {
version: 0,
createdAt: "",
updatedAt: "",
binding: yamlBinding(workspace, this.secretRoots),
binding: runtimeDatabaseBinding,
connectionStatus: "untested" as const,
};
return {
@@ -108,6 +162,12 @@ export class CatalogService {
workspaceName: entry.name,
workspaceDescription: entry.description,
workspaceAvailable: true,
workspaceRevision: {
commit: entry.revision.commit,
blob: entry.revision.blob,
},
workspaceEvidence: workspaceEvidenceState(this.secretStore, workspace),
runtimeBinding: workspaceRuntimeState(this.secretStore, workspace, this.secretRoots),
configured: database !== undefined,
secrets: secretState(this.secretStore, entry.id),
};
@@ -120,6 +180,9 @@ export class CatalogService {
workspaceName: database.workspaceId,
workspaceDescription: "Workspace is no longer present in the repository catalog.",
workspaceAvailable: false,
workspaceRevision: null,
workspaceEvidence: { sourceType: null, state: "workspace_unavailable" },
runtimeBinding: null,
configured: true,
secrets: secretState(this.secretStore, database.workspaceId),
}));