feat: add infrastructure checks (DB exists, Spaces prefix) to customer overview
Some checks failed
Build & Release / build (push) Has been cancelled

This commit is contained in:
Ryan Moon
2026-04-03 20:23:48 -05:00
parent bd97d65613
commit 530698f52e
2 changed files with 59 additions and 10 deletions

View File

@@ -624,7 +624,7 @@
} }
} }
function renderDetail({ customer, status, sizeHistory }) { function renderDetail({ customer, status, infra, sizeHistory }) {
// Header // Header
document.getElementById('detail-name').textContent = customer.name || customer.slug; document.getElementById('detail-name').textContent = customer.name || customer.slug;
document.getElementById('detail-slug').textContent = customer.slug; document.getElementById('detail-slug').textContent = customer.slug;
@@ -718,6 +718,30 @@
${conditionsHtml} ${conditionsHtml}
${podsHtml} ${podsHtml}
</div> </div>
<div class="stat-card">
<div class="card-title">Infrastructure</div>
<div class="stat-row">
<span class="stat-label">Database</span>
<span class="stat-value">${infra?.database?.exists
? '<span class="badge badge-green">Exists</span>'
: '<span class="badge badge-red">Not found</span>'}</span>
</div>
<div class="stat-row">
<span class="stat-label">Storage</span>
<span class="stat-value">${infra?.spaces?.configured
? '<span class="badge badge-green">Configured</span>'
: '<span class="badge badge-gray">Not configured</span>'}</span>
</div>
${infra?.spaces?.configured ? `
<div class="stat-row">
<span class="stat-label">Bucket</span>
<span class="stat-value" style="font-family:monospace;font-size:0.8rem">${infra.spaces.bucket}</span>
</div>
<div class="stat-row">
<span class="stat-label">Prefix</span>
<span class="stat-value" style="font-family:monospace;font-size:0.8rem">${infra.spaces.prefix}</span>
</div>` : ''}
</div>
<div class="stat-card"> <div class="stat-card">
<div class="card-title">Provisioning Steps</div> <div class="card-title">Provisioning Steps</div>
<div class="step-list">${stepsHtml}</div> <div class="step-list">${stepsHtml}</div>

View File

@@ -219,19 +219,44 @@ export async function customerRoutes(app: FastifyInstance) {
statusEntry = { data: liveStatus, cachedAt: new Date().toISOString() }; statusEntry = { data: liveStatus, cachedAt: new Date().toISOString() };
} }
// ── Size history (last 30 days) ─────────────────────────────────────────── // ── Infrastructure checks ─────────────────────────────────────────────────
const sizeHistory = await db` 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 SELECT recorded_at, db_size_bytes, spaces_size_bytes, spaces_object_count
FROM customer_size_snapshots FROM customer_size_snapshots
WHERE slug = ${slug} WHERE slug = ${slug}
ORDER BY recorded_at DESC ORDER BY recorded_at DESC
LIMIT 30 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({ return reply.send({
customer, customer,
status: { ...statusEntry.data, cachedAt: statusEntry.cachedAt }, status: { ...statusEntry.data, cachedAt: statusEntry.cachedAt },
sizeHistory, infra,
sizeHistory: sizeHistory.status === "fulfilled" ? sizeHistory.value : [],
}); });
}); });