From 2603aeb6e5a7ccca516051953cbd70a5a6c94c4b Mon Sep 17 00:00:00 2001
From: Charlie Team <97194984+ToolboxAid@users.noreply.github.com>
Date: Wed, 24 Jun 2026 14:19:41 -0400
Subject: [PATCH] PR_26175_CHARLIE_008-system-health-current-database-health
---
admin/system-health.html | 11 +++---
assets/theme-v2/js/admin-system-health.js | 34 ++++++++---------
...8-system-health-current-database-health.md | 37 +++++++++++++++++++
.../reports/coverage_changed_js_guardrail.txt | 2 +-
.../reports/playwright_v8_coverage_report.txt | 4 +-
src/dev-runtime/server/local-api-router.mjs | 26 +++++++++++--
.../AdminHealthOperations.test.mjs | 5 +++
.../tools/AdminHealthOperationsPage.spec.mjs | 9 +++--
8 files changed, 93 insertions(+), 35 deletions(-)
create mode 100644 docs_build/dev/reports/PR_26175_CHARLIE_008-system-health-current-database-health.md
diff --git a/admin/system-health.html b/admin/system-health.html
index 9aebcf0bd..b4b9f477f 100644
--- a/admin/system-health.html
+++ b/admin/system-health.html
@@ -124,12 +124,11 @@
System Health Tables
- | Provider | Postgres | PASS |
- | Host | Configured host placeholder | PENDING |
- | Port | 5432 | PASS |
- | Database | Configured database placeholder | PENDING |
- | Migration Version | Pending migration reader | PENDING |
- | Status | Connection check pending | PENDING |
+ | Database type | Loading | PENDING |
+ | Connectivity | Loading | PENDING |
+ | Response time | Loading | PENDING |
+ | Version | Loading | PENDING |
+ | Last checked | Loading | PENDING |
diff --git a/assets/theme-v2/js/admin-system-health.js b/assets/theme-v2/js/admin-system-health.js
index 6ba5c0f2a..61b446a3e 100644
--- a/assets/theme-v2/js/admin-system-health.js
+++ b/assets/theme-v2/js/admin-system-health.js
@@ -101,7 +101,7 @@ class AdminSystemHealthController {
["name", "hostingModel", "siteUrl", "apiUrl", "databaseModel", "storageFolder", "lastHealthCheck"].forEach((key) => {
this.setEnvironmentStatus(key, "PENDING", reason);
});
- ["host", "database", "migration", "connection"].forEach((key) => {
+ ["type", "connectivity", "responseTime", "version", "lastChecked"].forEach((key) => {
this.setStatus(key, "PENDING", reason);
});
this.renderStartupPending(reason);
@@ -134,25 +134,21 @@ class AdminSystemHealthController {
}
renderPostgresStatus(databaseStatus = {}) {
- const migrationCounts = databaseStatus.migrationCounts || {};
- const lastMigration = databaseStatus.lastMigration || {};
- const migrationSummary = lastMigration.name
- ? `${asText(lastMigration.type, "migration")} ${lastMigration.name}${lastMigration.appliedAt ? ` at ${lastMigration.appliedAt}` : ""}`
- : `DDL=${migrationCounts.DDL || 0}; DML=${migrationCounts.DML || 0}; last migration not recorded`;
- const connectionReason = databaseStatus.message || "Postgres diagnostic status returned by the safe Admin System Health API.";
+ const reason = databaseStatus.message || "Current environment database health returned by the safe Admin System Health API.";
+ const responseTime = Number.isFinite(databaseStatus.responseTimeMs)
+ ? `${databaseStatus.responseTimeMs} ms`
+ : "not available";
- this.setValue("provider", "Postgres");
- this.setStatus("provider", "PASS");
- this.setValue("host", databaseStatus.host, "not configured");
- this.setStatus("host", databaseStatus.hostStatus, connectionReason);
- this.setValue("port", databaseStatus.port ? String(databaseStatus.port) : "", "not configured");
- this.setStatus("port", databaseStatus.portStatus, connectionReason);
- this.setValue("database", databaseStatus.databaseName, "not configured");
- this.setStatus("database", databaseStatus.databaseNameStatus, connectionReason);
- this.setValue("migration", migrationSummary);
- this.setStatus("migration", databaseStatus.lastMigrationStatus || databaseStatus.migrationStatus, connectionReason);
- this.setValue("connection", databaseStatus.configured === true ? connectionReason : databaseStatus.message || "Postgres configuration is not complete.");
- this.setStatus("connection", databaseStatus.status, connectionReason);
+ this.setValue("type", databaseStatus.databaseType, "PostgreSQL");
+ this.setStatus("type", databaseStatus.databaseType ? "PASS" : "WARN", reason);
+ this.setValue("connectivity", databaseStatus.connectivity, databaseStatus.message || "not configured");
+ this.setStatus("connectivity", databaseStatus.connectivityStatus || databaseStatus.status, reason);
+ this.setValue("responseTime", responseTime);
+ this.setStatus("responseTime", Number.isFinite(databaseStatus.responseTimeMs) ? "PASS" : "WARN", reason);
+ this.setValue("version", databaseStatus.version, "not available");
+ this.setStatus("version", databaseStatus.versionStatus, reason);
+ this.setValue("lastChecked", databaseStatus.lastChecked, "not available");
+ this.setStatus("lastChecked", databaseStatus.lastChecked ? "PASS" : "WARN", reason);
}
renderStorageStatus(storageStatus = {}) {
diff --git a/docs_build/dev/reports/PR_26175_CHARLIE_008-system-health-current-database-health.md b/docs_build/dev/reports/PR_26175_CHARLIE_008-system-health-current-database-health.md
new file mode 100644
index 000000000..48883304b
--- /dev/null
+++ b/docs_build/dev/reports/PR_26175_CHARLIE_008-system-health-current-database-health.md
@@ -0,0 +1,37 @@
+# PR_26175_CHARLIE_008 System Health Current Database Health
+
+## Scope
+
+Team: Charlie
+
+Purpose: Add current-environment database health only to Admin System Health.
+
+## Changes
+
+- Replaced the Database Health table body with current-environment fields:
+ - database type
+ - connectivity
+ - response time
+ - version
+ - last checked
+- Added safe server-owned database status fields to the Admin System Health API payload.
+- Database type follows the current environment identity:
+ - Local, DEV, and IST: Local Docker PostgreSQL
+ - UAT and PRD: Supabase PostgreSQL
+- Updated focused API and Playwright tests.
+
+## Architecture Constraint
+
+PASS. Database health reads only the currently configured deployment database. No database checks are made for peer environments.
+
+## Validation
+
+- PASS: `node --check src/dev-runtime/server/local-api-router.mjs`
+- PASS: `node --check assets/theme-v2/js/admin-system-health.js`
+- PASS: `git diff --check`
+- PASS: `node --test tests/dev-runtime/AdminHealthOperations.test.mjs`
+- PASS: `npx playwright test tests/playwright/tools/AdminHealthOperationsPage.spec.mjs --workers=1 --reporter=line`
+
+## Artifact
+
+- `tmp/PR_26175_CHARLIE_008-system-health-current-database-health_delta.zip`
diff --git a/docs_build/dev/reports/coverage_changed_js_guardrail.txt b/docs_build/dev/reports/coverage_changed_js_guardrail.txt
index 833366a34..e8e235569 100644
--- a/docs_build/dev/reports/coverage_changed_js_guardrail.txt
+++ b/docs_build/dev/reports/coverage_changed_js_guardrail.txt
@@ -7,7 +7,7 @@ Source: Playwright/Chromium built-in V8 coverage from the active Playwright run.
Changed runtime JS files considered:
(0%) src/dev-runtime/server/local-api-router.mjs - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
-(89%) assets/theme-v2/js/admin-system-health.js - executed lines 288/288; executed functions 33/37
+(89%) assets/theme-v2/js/admin-system-health.js - executed lines 284/284; executed functions 33/37
Guardrail warnings:
(0%) src/dev-runtime/server/local-api-router.mjs - WARNING: changed runtime JS file missing from coverage; advisory only
diff --git a/docs_build/dev/reports/playwright_v8_coverage_report.txt b/docs_build/dev/reports/playwright_v8_coverage_report.txt
index c5c648f78..b83e6a3d3 100644
--- a/docs_build/dev/reports/playwright_v8_coverage_report.txt
+++ b/docs_build/dev/reports/playwright_v8_coverage_report.txt
@@ -18,7 +18,7 @@ Exercised tool entry points detected:
Changed runtime JS files covered:
(0%) src/dev-runtime/server/local-api-router.mjs - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
-(89%) assets/theme-v2/js/admin-system-health.js - executed lines 288/288; executed functions 33/37
+(89%) assets/theme-v2/js/admin-system-health.js - executed lines 284/284; executed functions 33/37
Files with executed line/function counts where available:
(36%) src/api/server-api-client.js - executed lines 167/167; executed functions 5/14
@@ -28,7 +28,7 @@ Files with executed line/function counts where available:
(74%) assets/theme-v2/js/gamefoundry-partials.js - executed lines 1001/1001; executed functions 69/93
(80%) src/api/admin-owner-navigation.js - executed lines 42/42; executed functions 4/5
(83%) assets/js/shared/status.js - executed lines 37/37; executed functions 5/6
-(89%) assets/theme-v2/js/admin-system-health.js - executed lines 288/288; executed functions 33/37
+(89%) assets/theme-v2/js/admin-system-health.js - executed lines 284/284; executed functions 33/37
(91%) assets/theme-v2/js/admin-owner-navigation.js - executed lines 58/58; executed functions 10/11
(100%) src/api/admin-system-health-api-client.js - executed lines 19/19; executed functions 3/3
diff --git a/src/dev-runtime/server/local-api-router.mjs b/src/dev-runtime/server/local-api-router.mjs
index b632d31aa..7305d14c0 100644
--- a/src/dev-runtime/server/local-api-router.mjs
+++ b/src/dev-runtime/server/local-api-router.mjs
@@ -3653,9 +3653,14 @@ class ApiRuntimeDataSource {
};
}
- async ownerDatabaseStatus() {
+ async ownerDatabaseStatus(environmentIdentity = systemHealthEnvironmentIdentity()) {
+ const startedAt = Date.now();
const databaseStatus = {
...databaseConfigStatus(),
+ connectivity: "not configured",
+ connectivityStatus: "WARN",
+ databaseType: environmentIdentity.databaseModel || "PostgreSQL",
+ lastChecked: new Date().toISOString(),
lastMigration: {
appliedAt: "",
name: "",
@@ -3667,10 +3672,14 @@ class ApiRuntimeDataSource {
DML: 0,
},
migrationStatus: "WARN",
+ responseTimeMs: null,
status: "WARN",
+ version: "",
+ versionStatus: "WARN",
};
try {
const adapter = this.supabaseDatabaseAdapter("Reading Admin System Health migration history");
+ const versionRows = await adapter.databaseClient().query("SELECT version() AS version;");
const countRows = await adapter.databaseClient().query(`
SELECT "migrationType", count(*)::int AS count
FROM schema_migrations
@@ -3685,8 +3694,11 @@ LIMIT 1;
`);
const counts = new Map(countRows.map((row) => [String(row.migrationType || ""), Number(row.count || 0)]));
const lastRow = lastRows[0] || {};
+ const version = String(versionRows[0]?.version || "").trim();
return {
...databaseStatus,
+ connectivity: "connected",
+ connectivityStatus: "PASS",
lastMigration: {
appliedAt: String(lastRow.appliedAt || ""),
name: String(lastRow.migrationName || ""),
@@ -3698,12 +3710,20 @@ LIMIT 1;
DML: counts.get("DML") || 0,
},
migrationStatus: "PASS",
+ message: "Current environment database connection responded through the safe Admin System Health API.",
+ responseTimeMs: Date.now() - startedAt,
status: databaseStatus.configured === true ? "PASS" : "WARN",
+ version: version || "not available",
+ versionStatus: version ? "PASS" : "WARN",
};
} catch (error) {
return {
...databaseStatus,
- message: `Migration history read failed: ${error instanceof Error ? error.message : String(error || "Unknown database error.")}`,
+ connectivity: "failed",
+ connectivityStatus: "FAIL",
+ message: `Current environment database health read failed: ${error instanceof Error ? error.message : String(error || "Unknown database error.")}`,
+ responseTimeMs: Date.now() - startedAt,
+ status: "FAIL",
};
}
}
@@ -3756,7 +3776,7 @@ LIMIT 1;
const checkedAt = new Date().toISOString();
const environmentIdentity = systemHealthEnvironmentIdentity(process.env, checkedAt);
const environmentMap = systemHealthEnvironmentMap();
- const databaseStatus = await this.ownerDatabaseStatus();
+ const databaseStatus = await this.ownerDatabaseStatus(environmentIdentity);
const storageStatus = this.ownerStorageStatus();
const environmentStatus = storageProjectsPrefixStatus();
const localApiStartup = systemHealthLocalApiStartupDiagnostics();
diff --git a/tests/dev-runtime/AdminHealthOperations.test.mjs b/tests/dev-runtime/AdminHealthOperations.test.mjs
index e3669cced..e7863ac4e 100644
--- a/tests/dev-runtime/AdminHealthOperations.test.mjs
+++ b/tests/dev-runtime/AdminHealthOperations.test.mjs
@@ -137,6 +137,11 @@ test("Admin can view operational health while Creator sessions are blocked", asy
assert.equal(health.environmentIdentity.storageFolder, "/local");
assert.equal(health.environmentIdentity.siteUrl.includes("site-user"), false);
assert.equal(health.environmentIdentity.apiUrl.includes("api-user"), false);
+ assert.equal(health.databaseStatus.databaseType, "Local Docker PostgreSQL");
+ assert.ok(["connected", "failed", "not configured"].includes(health.databaseStatus.connectivity));
+ assert.equal(typeof health.databaseStatus.lastChecked, "string");
+ assert.equal(typeof health.databaseStatus.responseTimeMs === "number" || health.databaseStatus.responseTimeMs === null, true);
+ assert.equal(typeof health.databaseStatus.version, "string");
assert.deepEqual(
health.environmentMap.map((row) => row.name),
["Local", "DEV", "IST", "UAT", "PRD"],
diff --git a/tests/playwright/tools/AdminHealthOperationsPage.spec.mjs b/tests/playwright/tools/AdminHealthOperationsPage.spec.mjs
index 10120dbba..76c78b53e 100644
--- a/tests/playwright/tools/AdminHealthOperationsPage.spec.mjs
+++ b/tests/playwright/tools/AdminHealthOperationsPage.spec.mjs
@@ -151,10 +151,11 @@ test("Admin System Health renders Postgres diagnostics through the safe status A
await expect(page.getByRole("table", { name: "Local API startup diagnostics" })).toContainText("deferred/cancelled");
await expect(page.getByRole("table", { name: "Local API startup diagnostics" })).not.toContainText("secret");
await expect(page.getByRole("table", { name: "Database health" })).toContainText("Postgres");
- await expect(page.locator("[data-admin-system-health-db-value='provider']")).toHaveText("Postgres");
- await expect(page.locator("[data-admin-system-health-db-value='host']")).not.toHaveText("Configured host placeholder");
- await expect(page.locator("[data-admin-system-health-db-value='database']")).not.toHaveText("Configured database placeholder");
- await expect(page.locator("[data-admin-system-health-db-value='connection']")).not.toHaveText("Connection check pending");
+ await expect(page.locator("[data-admin-system-health-db-value='type']")).toHaveText("Local Docker PostgreSQL");
+ await expect(page.locator("[data-admin-system-health-db-value='connectivity']")).not.toHaveText("Loading");
+ await expect(page.locator("[data-admin-system-health-db-value='responseTime']")).not.toHaveText("Loading");
+ await expect(page.locator("[data-admin-system-health-db-value='version']")).not.toHaveText("Loading");
+ await expect(page.locator("[data-admin-system-health-db-value='lastChecked']")).not.toHaveText("Loading");
await expect(page.getByRole("table", { name: "Database health" })).not.toContainText("postgres://");
await expect(page.getByRole("table", { name: "Database health" })).not.toContainText("postgresql://");
await expect(page.getByRole("table", { name: "Storage health" })).toContainText("Cloudflare R2");