Tighten control plane flow and status presentation

This commit is contained in:
Keith Casko
2026-10-02 11:20:13 -04:00
parent be741fbc1b
commit bcf115a83b
4 changed files with 88 additions and 54 deletions
+16 -24
View File
@@ -24,7 +24,7 @@
<div class="control-state"> <div class="control-state">
<span class="status-dot"></span> <span class="status-dot"></span>
<span>LAB CONFIGURATION / VERIFIED OCT 2026</span> <span>LIVE TELEMETRY / CONFIG VERIFIED OCT 2026</span>
</div> </div>
<nav aria-label="Control plane navigation"> <nav aria-label="Control plane navigation">
@@ -150,14 +150,10 @@
<aside class="activity-panel"> <aside class="activity-panel">
<div class="panel-title"> <div class="panel-title">
<span>OPERATIONAL CAPABILITIES</span> <span>PLATFORM CONTROLS</span>
<small>DOCUMENTED</small> <small>DOCUMENTED</small>
</div> </div>
<ol class="event-list"> <ol class="event-list">
<li>
<span class="event-ok">DEPLOY</span>
<p>Automated deployment through Woodpecker CI</p>
</li>
<li> <li>
<span class="event-info">AUTH</span> <span class="event-info">AUTH</span>
<p>OIDC authentication through Authentik</p> <p>OIDC authentication through Authentik</p>
@@ -166,10 +162,6 @@
<span class="event-ok">BACKUP</span> <span class="event-ok">BACKUP</span>
<p>Persistent data backup and documented recovery procedures</p> <p>Persistent data backup and documented recovery procedures</p>
</li> </li>
<li>
<span class="event-warn">SEC</span>
<p>CrowdSec threat detection and decision evidence</p>
</li>
<li> <li>
<span class="event-info">TLS</span> <span class="event-info">TLS</span>
<p>Certificate and HTTPS management through the reverse proxy</p> <p>Certificate and HTTPS management through the reverse proxy</p>
@@ -248,7 +240,7 @@
<a href="assets/images/portfolio-grafana-logs.png" target="_blank"> <a href="assets/images/portfolio-grafana-logs.png" target="_blank">
<img src="assets/images/portfolio-grafana-logs.png" alt="Centralized logs snapshot in Grafana" /> <img src="assets/images/portfolio-grafana-logs.png" alt="Centralized logs snapshot in Grafana" />
</a> </a>
<p class="evidence-note">CAPTURED OCT 2026 · LOGGING EVIDENCE SNAPSHOT · VALUES SHOWN ARE FROM CAPTURE TIME</p> <p class="evidence-note">OCT 2026 · LOGGING EVIDENCE</p>
</figure> </figure>
<div class="coverage-matrix"> <div class="coverage-matrix">
@@ -282,15 +274,15 @@
<div class="service-layout"> <div class="service-layout">
<div class="service-table" role="table" aria-label="Service inventory"> <div class="service-table" role="table" aria-label="Service inventory">
<div class="service-row service-head" role="row"> <div class="service-row service-head" role="row">
<span>Service</span><span>Role</span><span>Access</span><span>State</span> <span>Service</span><span>Role</span><span>Access</span>
</div> </div>
<div class="service-row"><strong>Gitea</strong><span>Source control</span><span>SSO</span><i>CONFIGURED</i></div> <div class="service-row"><strong>Gitea</strong><span>Source control</span><span>SSO</span></div>
<div class="service-row"><strong>Wiki.js</strong><span>Documentation</span><span>SSO</span><i>CONFIGURED</i></div> <div class="service-row"><strong>Wiki.js</strong><span>Documentation</span><span>SSO</span></div>
<div class="service-row"><strong>Dashy</strong><span>Service portal</span><span>SSO</span><i>CONFIGURED</i></div> <div class="service-row"><strong>Dashy</strong><span>Service portal</span><span>SSO</span></div>
<div class="service-row"><strong>Vaultwarden</strong><span>Secrets</span><span>DIRECT</span><i>CONFIGURED</i></div> <div class="service-row"><strong>Vaultwarden</strong><span>Secrets</span><span>DIRECT</span></div>
<div class="service-row"><strong>Stirling PDF</strong><span>Document tools</span><span>SSO</span><i>CONFIGURED</i></div> <div class="service-row"><strong>Stirling PDF</strong><span>Document tools</span><span>SSO</span></div>
<div class="service-row"><strong>IT Tools</strong><span>Utilities</span><span>SSO</span><i>CONFIGURED</i></div> <div class="service-row"><strong>IT Tools</strong><span>Utilities</span><span>SSO</span></div>
<div class="service-row"><strong>Uptime Kuma</strong><span>Availability</span><span>SSO</span><i>CONFIGURED</i></div> <div class="service-row"><strong>Uptime Kuma</strong><span>Availability</span><span>SSO</span></div>
</div> </div>
<div class="portal-shot live-service-panel" aria-label="Live service health"> <div class="portal-shot live-service-panel" aria-label="Live service health">
@@ -299,7 +291,7 @@
<small>SANITIZED ENDPOINT CHECKS</small> <small>SANITIZED ENDPOINT CHECKS</small>
</figcaption> </figcaption>
<div class="service-health-grid"> <div class="service-health-grid">
<div><span>GITEA</span><strong id="health-gitea">CHECKING</strong><small id="gitea-version">VERSION --</small></div> <div><span>GITEA</span><strong id="health-gitea">CHECKING</strong><small>SOURCE CONTROL</small></div>
<div><span>WOODPECKER</span><strong id="health-woodpecker">CHECKING</strong><small>CI / DELIVERY</small></div> <div><span>WOODPECKER</span><strong id="health-woodpecker">CHECKING</strong><small>CI / DELIVERY</small></div>
<div><span>UPTIME KUMA</span><strong id="health-kuma">CHECKING</strong><small>AVAILABILITY</small></div> <div><span>UPTIME KUMA</span><strong id="health-kuma">CHECKING</strong><small>AVAILABILITY</small></div>
<div><span>PROMETHEUS</span><strong id="health-prometheus">CHECKING</strong><small>METRICS</small></div> <div><span>PROMETHEUS</span><strong id="health-prometheus">CHECKING</strong><small>METRICS</small></div>
@@ -336,7 +328,7 @@
<div class="delivery-state"> <div class="delivery-state">
<span class="delivery-kicker">SERVICE STATE</span> <span class="delivery-kicker">SERVICE STATE</span>
<strong id="pipeline-gitea-state">CHECKING</strong> <strong id="pipeline-gitea-state">CHECKING</strong>
<small id="pipeline-gitea-version">VERSION --</small> <small>REPOSITORY HOST</small>
</div> </div>
<div class="delivery-meta"> <div class="delivery-meta">
<span>ROLE</span><strong>REPOSITORY HOST</strong> <span>ROLE</span><strong>REPOSITORY HOST</strong>
@@ -392,7 +384,7 @@
<a href="assets/images/portfolio-crowdsec-decisions.png" target="_blank"> <a href="assets/images/portfolio-crowdsec-decisions.png" target="_blank">
<img src="assets/images/portfolio-crowdsec-decisions.png" alt="CrowdSec firewall decision evidence snapshot" /> <img src="assets/images/portfolio-crowdsec-decisions.png" alt="CrowdSec firewall decision evidence snapshot" />
</a> </a>
<p class="evidence-note">CAPTURED OCT 2026 · SECURITY EVIDENCE SNAPSHOT · NOT A LIVE DECISION FEED</p> <p class="evidence-note">OCT 2026 · DECISION-HISTORY EVIDENCE</p>
</figure> </figure>
</div> </div>
</section> </section>
@@ -418,7 +410,7 @@
<a href="assets/images/portfolio-wiki-disaster-recovery.png" target="_blank"> <a href="assets/images/portfolio-wiki-disaster-recovery.png" target="_blank">
<img src="assets/images/portfolio-wiki-disaster-recovery.png" alt="ByteGeist disaster recovery runbook documentation snapshot" /> <img src="assets/images/portfolio-wiki-disaster-recovery.png" alt="ByteGeist disaster recovery runbook documentation snapshot" />
</a> </a>
<p class="evidence-note">CAPTURED OCT 2026 · DOCUMENTED RECOVERY PROCEDURE</p> <p class="evidence-note">OCT 2026 · RUNBOOK CAPTURE</p>
</figure> </figure>
</div> </div>
</section> </section>
@@ -429,7 +421,7 @@
<img src="assets/images/bytegeist-logo.png" alt="" /> <img src="assets/images/bytegeist-logo.png" alt="" />
<div><strong>BYTEGEIST</strong><span>KEITH CASKO / INFRASTRUCTURE LAB</span></div> <div><strong>BYTEGEIST</strong><span>KEITH CASKO / INFRASTRUCTURE LAB</span></div>
</div> </div>
<p>PLAIN HTML / CSS / JAVASCRIPT</p> <p>HTML / CSS / JAVASCRIPT · PYTHON STATUS API · NGINX</p>
<p>VERIFICATION: <span class="status-text">OCT 2026</span></p> <p>VERIFICATION: <span class="status-text">OCT 2026</span></p>
</footer> </footer>
</body> </body>
+12 -19
View File
@@ -19,9 +19,7 @@ const fields = {
healthWoodpecker: document.querySelector("#health-woodpecker"), healthWoodpecker: document.querySelector("#health-woodpecker"),
healthKuma: document.querySelector("#health-kuma"), healthKuma: document.querySelector("#health-kuma"),
healthPrometheus: document.querySelector("#health-prometheus"), healthPrometheus: document.querySelector("#health-prometheus"),
giteaVersion: document.querySelector("#gitea-version"),
pipelineGiteaState: document.querySelector("#pipeline-gitea-state"), pipelineGiteaState: document.querySelector("#pipeline-gitea-state"),
pipelineGiteaVersion: document.querySelector("#pipeline-gitea-version"),
pipelineWoodpeckerState: document.querySelector("#pipeline-woodpecker-state"), pipelineWoodpeckerState: document.querySelector("#pipeline-woodpecker-state"),
deployedCommit: document.querySelector("#deployed-commit"), deployedCommit: document.querySelector("#deployed-commit"),
}; };
@@ -31,7 +29,7 @@ const telemetryHistory = {
memory: [], memory: [],
}; };
let lastSuccessfulUpdate = null; let lastSampledAt = null;
let requestInFlight = false; let requestInFlight = false;
function updateClock() { function updateClock() {
@@ -80,8 +78,6 @@ function setUnavailable() {
element.classList.add("status-down"); element.classList.add("status-down");
} }
} }
fields.giteaVersion.textContent = "VERSION --";
fields.pipelineGiteaVersion.textContent = "VERSION --";
fields.deployedCommit.textContent = "-------"; fields.deployedCommit.textContent = "-------";
refreshElement.textContent = "TELEMETRY UNAVAILABLE"; refreshElement.textContent = "TELEMETRY UNAVAILABLE";
refreshElement.classList.add("telemetry-error"); refreshElement.classList.add("telemetry-error");
@@ -104,10 +100,6 @@ function pushHistory(series, value) {
if (series.length > 24) series.shift(); if (series.length > 24) series.shift();
} }
function serviceLabel(service) {
return service && service.up ? "ONLINE" : "UNAVAILABLE";
}
function setServiceState(element, service) { function setServiceState(element, service) {
if (!element) return; if (!element) return;
const up = Boolean(service && service.up); const up = Boolean(service && service.up);
@@ -143,11 +135,6 @@ function renderStatus(data) {
setServiceState(fields.pipelineGiteaState, services.gitea); setServiceState(fields.pipelineGiteaState, services.gitea);
setServiceState(fields.pipelineWoodpeckerState, services.woodpecker); setServiceState(fields.pipelineWoodpeckerState, services.woodpecker);
const giteaVersion = services.gitea && services.gitea.version
? "VERSION " + services.gitea.version
: "VERSION --";
fields.giteaVersion.textContent = giteaVersion;
fields.pipelineGiteaVersion.textContent = giteaVersion;
fields.deployedCommit.textContent = data.deployment && data.deployment.commit fields.deployedCommit.textContent = data.deployment && data.deployment.commit
? data.deployment.commit ? data.deployment.commit
: "-------"; : "-------";
@@ -159,14 +146,21 @@ function renderStatus(data) {
fields.telemetry.classList.remove("metric-error"); fields.telemetry.classList.remove("metric-error");
refreshElement.classList.remove("telemetry-error"); refreshElement.classList.remove("telemetry-error");
lastSuccessfulUpdate = Date.now(); lastSampledAt = Number(data.sampled_at) * 1000;
updateRefreshLabel(); updateRefreshLabel();
} }
function updateRefreshLabel() { function updateRefreshLabel() {
if (!lastSuccessfulUpdate) return; if (!lastSampledAt) return;
const ageSeconds = Math.max(0, Math.floor((Date.now() - lastSuccessfulUpdate) / 1000)); const ageSeconds = Math.max(0, Math.floor((Date.now() - lastSampledAt) / 1000));
refreshElement.textContent = "LIVE TELEMETRY | UPDATED " + String(ageSeconds).padStart(2, "0") + "s AGO"; const stale = ageSeconds > 45;
refreshElement.textContent = (stale ? "TELEMETRY STALE | SAMPLE " : "LIVE TELEMETRY | SAMPLE ")
+ String(ageSeconds).padStart(2, "0") + "s AGO";
refreshElement.classList.toggle("telemetry-error", stale);
fields.telemetry.textContent = stale ? "STALE" : "LIVE";
fields.telemetry.classList.toggle("metric-error", stale);
} }
async function refreshTelemetry() { async function refreshTelemetry() {
@@ -198,4 +192,3 @@ refreshTelemetry();
window.setInterval(updateClock, 1000); window.setInterval(updateClock, 1000);
window.setInterval(updateRefreshLabel, 1000); window.setInterval(updateRefreshLabel, 1000);
window.setInterval(refreshTelemetry, 15000); window.setInterval(refreshTelemetry, 15000);
-5
View File
@@ -63,11 +63,6 @@ def check_services():
try: try:
status, body = get_text(url) status, body = get_text(url)
services[name] = {"up": 200 <= status < 400, "status": status} services[name] = {"up": 200 <= status < 400, "status": status}
if name == "gitea":
try:
services[name]["version"] = json.loads(body).get("version")
except Exception:
pass
except Exception: except Exception:
services[name] = {"up": False, "status": None} services[name] = {"up": False, "status": None}
return services return services
+60 -6
View File
@@ -664,10 +664,10 @@ h1 {
.module-header { .module-header {
display: grid; display: grid;
grid-template-columns: 1fr minmax(260px, .75fr) auto; grid-template-columns: 1fr minmax(260px, .75fr) auto;
gap: 40px; gap: 28px;
align-items: end; align-items: end;
min-height: 132px; min-height: 108px;
padding: 28px 30px; padding: 22px 28px;
border-bottom: 1px solid var(--line-strong); border-bottom: 1px solid var(--line-strong);
} }
@@ -679,7 +679,7 @@ h1 {
.module h2 { .module h2 {
margin: 7px 0 0; margin: 7px 0 0;
font-size: clamp(1.8rem, 3vw, 3.3rem); font-size: clamp(1.65rem, 2.5vw, 2.7rem);
font-weight: 500; font-weight: 500;
line-height: 1; line-height: 1;
letter-spacing: -.05em; letter-spacing: -.05em;
@@ -868,7 +868,7 @@ h1 {
.service-row { .service-row {
display: grid; display: grid;
grid-template-columns: 1fr 1.2fr .65fr .55fr; grid-template-columns: 1fr 1.25fr .7fr;
gap: 12px; gap: 12px;
align-items: center; align-items: center;
min-height: 53px; min-height: 53px;
@@ -1331,7 +1331,7 @@ footer {
.service-row span:nth-child(3), .service-row span:nth-child(3),
.service-head span:nth-child(3) { .service-head span:nth-child(3) {
display: none; display: block;
} }
.system-map { .system-map {
@@ -1376,3 +1376,57 @@ footer {
animation-iteration-count: 1 !important; animation-iteration-count: 1 !important;
} }
} }
/* Final rhythm and evidence polish */
.module + .module {
position: relative;
}
.module + .module::before {
content: "";
position: absolute;
top: -1px;
left: 28px;
width: 48px;
height: 1px;
background: var(--purple-low);
}
.evidence-note {
opacity: .72;
font-size: .49rem;
letter-spacing: .05em;
}
.evidence-wide img,
.crowdsec-shot img,
.recovery-layout img {
max-height: 430px;
object-fit: contain;
object-position: top center;
background: #050608;
}
.activity-panel .event-list li {
padding: 15px 0;
}
.activity-panel .event-list p {
line-height: 1.5;
}
@media (max-width: 560px) {
.module-header {
min-height: auto;
padding: 20px 16px;
}
.module + .module::before {
left: 16px;
}
.service-row {
grid-template-columns: 1fr 1fr auto;
}
}