diff --git a/frontend/index.html b/frontend/index.html
index 34bc353..12d9dc1 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -624,7 +624,7 @@
}
}
- function renderDetail({ customer, status, sizeHistory }) {
+ function renderDetail({ customer, status, infra, sizeHistory }) {
// Header
document.getElementById('detail-name').textContent = customer.name || customer.slug;
document.getElementById('detail-slug').textContent = customer.slug;
@@ -718,6 +718,30 @@
${conditionsHtml}
${podsHtml}
+
+
Infrastructure
+
+ Database
+ ${infra?.database?.exists
+ ? 'Exists'
+ : 'Not found'}
+
+
+ Storage
+ ${infra?.spaces?.configured
+ ? 'Configured'
+ : 'Not configured'}
+
+ ${infra?.spaces?.configured ? `
+
+ Bucket
+ ${infra.spaces.bucket}
+
+
+ Prefix
+ ${infra.spaces.prefix}
+
` : ''}
+
Provisioning Steps
${stepsHtml}
diff --git a/src/routes/customers.ts b/src/routes/customers.ts
index 720cc7d..ffb69f3 100644
--- a/src/routes/customers.ts
+++ b/src/routes/customers.ts
@@ -219,19 +219,44 @@ export async function customerRoutes(app: FastifyInstance) {
statusEntry = { data: liveStatus, cachedAt: new Date().toISOString() };
}
- // ── Size history (last 30 days) ───────────────────────────────────────────
- const sizeHistory = await db`
- SELECT recorded_at, db_size_bytes, spaces_size_bytes, spaces_object_count
- FROM customer_size_snapshots
- WHERE slug = ${slug}
- ORDER BY recorded_at DESC
- LIMIT 30
- `;
+ // ── Infrastructure checks ─────────────────────────────────────────────────
+ const [dbCheck, sizeHistory, secrets] = await Promise.allSettled([
+ // Try connecting to the customer DB
+ (async () => {
+ const sql = postgres(config.doadminDbUrl.replace(/\/([^/?]+)(\?|$)/, `/${slug}$2`), { max: 1, connect_timeout: 5 });
+ try {
+ await sql`SELECT 1`;
+ return true;
+ } finally {
+ await sql.end();
+ }
+ })(),
+ db`
+ SELECT recorded_at, db_size_bytes, spaces_size_bytes, spaces_object_count
+ FROM customer_size_snapshots
+ WHERE slug = ${slug}
+ ORDER BY recorded_at DESC
+ LIMIT 30
+ `,
+ getSecret(namespace, "lunarfront-secrets").catch(() => null),
+ ]);
+
+ const dbExists = dbCheck.status === "fulfilled" ? dbCheck.value : false;
+ const secretData = secrets.status === "fulfilled" ? secrets.value : null;
+ const infra = {
+ database: { exists: dbExists },
+ spaces: {
+ configured: !!(secretData?.["spaces-prefix"]),
+ bucket: secretData?.["spaces-bucket"] ?? null,
+ prefix: secretData?.["spaces-prefix"] ?? null,
+ },
+ };
return reply.send({
customer,
status: { ...statusEntry.data, cachedAt: statusEntry.cachedAt },
- sizeHistory,
+ infra,
+ sizeHistory: sizeHistory.status === "fulfilled" ? sizeHistory.value : [],
});
});