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">
<span class="status-dot"></span>
<span>LAB CONFIGURATION / VERIFIED OCT 2026</span>
<span>LIVE TELEMETRY / CONFIG VERIFIED OCT 2026</span>
</div>
<nav aria-label="Control plane navigation">
@@ -150,14 +150,10 @@
<aside class="activity-panel">
<div class="panel-title">
<span>OPERATIONAL CAPABILITIES</span>
<span>PLATFORM CONTROLS</span>
<small>DOCUMENTED</small>
</div>
<ol class="event-list">
<li>
<span class="event-ok">DEPLOY</span>
<p>Automated deployment through Woodpecker CI</p>
</li>
<li>
<span class="event-info">AUTH</span>
<p>OIDC authentication through Authentik</p>
@@ -166,10 +162,6 @@
<span class="event-ok">BACKUP</span>
<p>Persistent data backup and documented recovery procedures</p>
</li>
<li>
<span class="event-warn">SEC</span>
<p>CrowdSec threat detection and decision evidence</p>
</li>
<li>
<span class="event-info">TLS</span>
<p>Certificate and HTTPS management through the reverse proxy</p>
@@ -248,7 +240,7 @@
<a href="assets/images/portfolio-grafana-logs.png" target="_blank">
<img src="assets/images/portfolio-grafana-logs.png" alt="Centralized logs snapshot in Grafana" />
</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>
<div class="coverage-matrix">
@@ -282,15 +274,15 @@
<div class="service-layout">
<div class="service-table" role="table" aria-label="Service inventory">
<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 class="service-row"><strong>Gitea</strong><span>Source control</span><span>SSO</span><i>CONFIGURED</i></div>
<div class="service-row"><strong>Wiki.js</strong><span>Documentation</span><span>SSO</span><i>CONFIGURED</i></div>
<div class="service-row"><strong>Dashy</strong><span>Service portal</span><span>SSO</span><i>CONFIGURED</i></div>
<div class="service-row"><strong>Vaultwarden</strong><span>Secrets</span><span>DIRECT</span><i>CONFIGURED</i></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>IT Tools</strong><span>Utilities</span><span>SSO</span><i>CONFIGURED</i></div>
<div class="service-row"><strong>Uptime Kuma</strong><span>Availability</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></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></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></div>
<div class="service-row"><strong>Uptime Kuma</strong><span>Availability</span><span>SSO</span></div>
</div>
<div class="portal-shot live-service-panel" aria-label="Live service health">
@@ -299,7 +291,7 @@
<small>SANITIZED ENDPOINT CHECKS</small>
</figcaption>
<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>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>
@@ -336,7 +328,7 @@
<div class="delivery-state">
<span class="delivery-kicker">SERVICE STATE</span>
<strong id="pipeline-gitea-state">CHECKING</strong>
<small id="pipeline-gitea-version">VERSION --</small>
<small>REPOSITORY HOST</small>
</div>
<div class="delivery-meta">
<span>ROLE</span><strong>REPOSITORY HOST</strong>
@@ -392,7 +384,7 @@
<a href="assets/images/portfolio-crowdsec-decisions.png" target="_blank">
<img src="assets/images/portfolio-crowdsec-decisions.png" alt="CrowdSec firewall decision evidence snapshot" />
</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>
</div>
</section>
@@ -418,7 +410,7 @@
<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" />
</a>
<p class="evidence-note">CAPTURED OCT 2026 · DOCUMENTED RECOVERY PROCEDURE</p>
<p class="evidence-note">OCT 2026 · RUNBOOK CAPTURE</p>
</figure>
</div>
</section>
@@ -429,7 +421,7 @@
<img src="assets/images/bytegeist-logo.png" alt="" />
<div><strong>BYTEGEIST</strong><span>KEITH CASKO / INFRASTRUCTURE LAB</span></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>
</footer>
</body>
+12 -19
View File
@@ -19,9 +19,7 @@ const fields = {
healthWoodpecker: document.querySelector("#health-woodpecker"),
healthKuma: document.querySelector("#health-kuma"),
healthPrometheus: document.querySelector("#health-prometheus"),
giteaVersion: document.querySelector("#gitea-version"),
pipelineGiteaState: document.querySelector("#pipeline-gitea-state"),
pipelineGiteaVersion: document.querySelector("#pipeline-gitea-version"),
pipelineWoodpeckerState: document.querySelector("#pipeline-woodpecker-state"),
deployedCommit: document.querySelector("#deployed-commit"),
};
@@ -31,7 +29,7 @@ const telemetryHistory = {
memory: [],
};
let lastSuccessfulUpdate = null;
let lastSampledAt = null;
let requestInFlight = false;
function updateClock() {
@@ -80,8 +78,6 @@ function setUnavailable() {
element.classList.add("status-down");
}
}
fields.giteaVersion.textContent = "VERSION --";
fields.pipelineGiteaVersion.textContent = "VERSION --";
fields.deployedCommit.textContent = "-------";
refreshElement.textContent = "TELEMETRY UNAVAILABLE";
refreshElement.classList.add("telemetry-error");
@@ -104,10 +100,6 @@ function pushHistory(series, value) {
if (series.length > 24) series.shift();
}
function serviceLabel(service) {
return service && service.up ? "ONLINE" : "UNAVAILABLE";
}
function setServiceState(element, service) {
if (!element) return;
const up = Boolean(service && service.up);
@@ -143,11 +135,6 @@ function renderStatus(data) {
setServiceState(fields.pipelineGiteaState, services.gitea);
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
? data.deployment.commit
: "-------";
@@ -159,14 +146,21 @@ function renderStatus(data) {
fields.telemetry.classList.remove("metric-error");
refreshElement.classList.remove("telemetry-error");
lastSuccessfulUpdate = Date.now();
lastSampledAt = Number(data.sampled_at) * 1000;
updateRefreshLabel();
}
function updateRefreshLabel() {
if (!lastSuccessfulUpdate) return;
const ageSeconds = Math.max(0, Math.floor((Date.now() - lastSuccessfulUpdate) / 1000));
refreshElement.textContent = "LIVE TELEMETRY | UPDATED " + String(ageSeconds).padStart(2, "0") + "s AGO";
if (!lastSampledAt) return;
const ageSeconds = Math.max(0, Math.floor((Date.now() - lastSampledAt) / 1000));
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() {
@@ -198,4 +192,3 @@ refreshTelemetry();
window.setInterval(updateClock, 1000);
window.setInterval(updateRefreshLabel, 1000);
window.setInterval(refreshTelemetry, 15000);
-5
View File
@@ -63,11 +63,6 @@ def check_services():
try:
status, body = get_text(url)
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:
services[name] = {"up": False, "status": None}
return services
+60 -6
View File
@@ -664,10 +664,10 @@ h1 {
.module-header {
display: grid;
grid-template-columns: 1fr minmax(260px, .75fr) auto;
gap: 40px;
gap: 28px;
align-items: end;
min-height: 132px;
padding: 28px 30px;
min-height: 108px;
padding: 22px 28px;
border-bottom: 1px solid var(--line-strong);
}
@@ -679,7 +679,7 @@ h1 {
.module h2 {
margin: 7px 0 0;
font-size: clamp(1.8rem, 3vw, 3.3rem);
font-size: clamp(1.65rem, 2.5vw, 2.7rem);
font-weight: 500;
line-height: 1;
letter-spacing: -.05em;
@@ -868,7 +868,7 @@ h1 {
.service-row {
display: grid;
grid-template-columns: 1fr 1.2fr .65fr .55fr;
grid-template-columns: 1fr 1.25fr .7fr;
gap: 12px;
align-items: center;
min-height: 53px;
@@ -1331,7 +1331,7 @@ footer {
.service-row span:nth-child(3),
.service-head span:nth-child(3) {
display: none;
display: block;
}
.system-map {
@@ -1376,3 +1376,57 @@ footer {
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;
}
}