Files
stack/infra/gitea/custom/templates/home.tmpl
kert 58f49cb293 fix(observability): finish Jaeger→Tempo migration across satellite files
The Jaeger→Tempo swap landed in the authoritative places (compose.yml,
stack.toml, infra/grafana) but several satellites still referenced the
removed `jaeger` service:

- deploy.sh Tier-4 ran `up jaeger loki prometheus` — `jaeger` no longer
  exists, so `docker compose up` errored ("no such service") and aborted
  the observability tier, taking loki/prometheus on that line with it.
- bootstrap_certs.py provisioned a cert for the dead jaeger.fhirworx.io
  and never provisioned tempo.fhirworx.io.
- README (template + generated), the nginx dashboard tile, and the Gitea
  home tile all advertised a Jaeger URL that no longer resolves.
- dev/seeds/grafana/ was a stale, unmounted, unreferenced duplicate of
  infra/grafana still carrying a jaeger datasource — removed as dead.

All now point at tempo. README regenerated from the template.
2026-07-08 10:08:08 -04:00

424 lines
14 KiB
Cheetah

{{template "base/head" .}}
<style>
/* HTI-5 dashboard tokens — defined locally so the inline template is self-contained.
gitea.css maps Gitea's --color-* vars to hti5 tokens at load time. */
.homelab-dashboard {
max-width: 1180px;
margin: 0 auto;
padding: 3rem 1.5rem;
font-family: "Source Serif 4", Georgia, serif;
}
/* Rule lines */
.homelab-dashboard .rule-line {
border: none;
border-top: 3px solid var(--color-text);
margin-bottom: 1rem;
}
.homelab-dashboard .rule-line-thin {
border: none;
border-top: 1px solid var(--color-border);
margin-bottom: 1rem;
}
/* Masthead */
.homelab-dashboard .masthead {
margin-bottom: 1.5rem;
}
.homelab-dashboard .masthead-row {
display: flex;
align-items: baseline;
justify-content: space-between;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 1rem;
}
.homelab-dashboard .masthead-brand {
display: flex;
align-items: center;
gap: 1rem;
}
.homelab-dashboard .masthead-logo {
width: clamp(48px, 6vw, 80px);
height: clamp(48px, 6vw, 80px);
display: block;
flex: 0 0 auto;
}
.homelab-dashboard .masthead-row h1 {
font-family: "Playfair Display", Georgia, serif !important;
font-size: clamp(2.5rem, 5vw, 3.5rem) !important;
font-weight: 800 !important;
color: var(--color-text) !important;
letter-spacing: -0.02em !important;
line-height: 1.1 !important;
border: none !important;
margin: 0 !important;
}
.homelab-dashboard .masthead-eyebrow {
font-family: "JetBrains Mono", "Fira Code", monospace;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--color-text-light);
align-self: flex-end;
padding-bottom: 0.35rem;
}
.homelab-dashboard .tagline {
font-family: "Source Serif 4", Georgia, serif;
font-size: 1.125rem;
color: var(--color-text-light);
max-width: 65ch;
line-height: 1.65;
margin-bottom: 1.5rem;
}
/* Section header */
.homelab-dashboard .section-header {
margin-bottom: 1.5rem;
background: transparent !important;
padding: 0 !important;
border: none !important;
}
.homelab-dashboard .section-eyebrow {
font-family: "JetBrains Mono", "Fira Code", monospace;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--color-text-light);
margin-bottom: 0.4rem;
display: block;
}
.homelab-dashboard .section-header h2 {
font-family: "Playfair Display", Georgia, serif !important;
font-size: 1.75rem !important;
font-weight: 700 !important;
letter-spacing: -0.01em !important;
color: var(--color-text) !important;
line-height: 1.2 !important;
border: none !important;
background: transparent !important;
padding: 0 !important;
margin: 0 !important;
display: block !important;
}
/* Grid */
.homelab-dashboard .grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.25rem;
margin-bottom: 3rem;
}
/* Tiles */
.homelab-dashboard .tile {
background: var(--color-box-body);
border: 1px solid var(--color-border) !important;
border-top: 3px solid var(--color-text) !important;
padding: 1.5rem;
position: relative;
overflow: hidden;
transition: border-color 0.15s ease, background 0.15s ease;
cursor: pointer;
text-decoration: none !important;
display: block;
border-radius: 0 !important;
}
.homelab-dashboard .tile:hover {
border-color: var(--color-primary) !important;
background: var(--color-body);
}
.homelab-dashboard .tile .icon {
font-size: 1.5rem;
margin-bottom: 0.75rem;
display: block;
line-height: 1;
}
.homelab-dashboard .tile.storage .icon,
.homelab-dashboard .tile.database .icon { color: var(--color-warning); }
.homelab-dashboard .tile.git .icon { color: var(--color-primary); }
.homelab-dashboard .tile.ci .icon { color: var(--color-primary); }
.homelab-dashboard .tile.notebook .icon,
.homelab-dashboard .tile.research .icon { color: var(--color-text); }
.homelab-dashboard .tile.catalog .icon { color: var(--color-primary); }
.homelab-dashboard .tile.query .icon { color: var(--color-primary); }
.homelab-dashboard .tile.observability .icon { color: var(--color-warning); }
.homelab-dashboard .tile.metrics .icon { color: var(--color-primary); }
.homelab-dashboard .tile.logs .icon { color: var(--color-primary); }
.homelab-dashboard .tile.proxy .icon { color: var(--color-text); }
/* Tile eyebrow — mono metadata label */
.homelab-dashboard .tile-eyebrow {
font-family: "JetBrains Mono", "Fira Code", monospace;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--color-text-light);
margin-bottom: 0.25rem;
}
/* Tile title — Playfair Display */
.homelab-dashboard .tile-title {
font-family: "Playfair Display", Georgia, serif !important;
font-size: 1.25rem !important;
font-weight: 700 !important;
line-height: 1.2 !important;
letter-spacing: -0.01em !important;
color: var(--color-text) !important;
margin: 0.25rem 0 0.5rem !important;
border: none !important;
text-transform: none !important;
transition: color 0.15s ease;
}
.homelab-dashboard .tile:hover .tile-title {
color: var(--color-primary) !important;
}
/* Tile description — Source Serif 4 */
.homelab-dashboard .tile-desc {
font-family: "Source Serif 4", Georgia, serif;
font-size: 0.95rem;
color: var(--color-text-light);
line-height: 1.55;
margin-bottom: 1rem;
}
/* Tile port — mono metadata */
.homelab-dashboard .tile-port {
font-family: "JetBrains Mono", "Fira Code", monospace;
font-size: 0.65rem;
color: var(--color-text-light);
opacity: 0.7;
display: inline-block;
}
/* Status dot */
.homelab-dashboard .status-dot {
position: absolute;
top: 1rem;
right: 1rem;
width: 8px;
height: 8px;
background: var(--color-success);
border-radius: 50%;
}
/* Badge */
.homelab-dashboard .tile-badge {
position: absolute;
top: -1px;
left: 1.25rem;
font-family: "JetBrains Mono", "Fira Code", monospace;
color: var(--color-primary-foreground, #F7F5F0);
font-size: 0.6rem;
padding: 3px 7px;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.homelab-dashboard .tile-badge.new { background: var(--color-warning); }
.homelab-dashboard .tile-badge.gpu { background: var(--color-primary); }
.homelab-dashboard .tile-badge.data { background: var(--color-primary); }
/* Bottom accent */
.homelab-dashboard .stripe {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 2px;
background: var(--color-border);
}
/* Footer */
.homelab-dashboard .ftr {
padding-top: 1rem;
border-top: 3px solid var(--color-text);
color: var(--color-text-light);
font-family: "JetBrains Mono", "Fira Code", monospace;
font-size: 0.65rem;
letter-spacing: 0.08em;
}
.homelab-dashboard .ftr span { color: var(--color-warning); }
</style>
<div class="homelab-dashboard">
<div class="masthead">
<div class="rule-line"></div>
<div class="masthead-row">
<div class="masthead-brand">
<img src="/assets/img/logo.svg" alt="fhirworx" class="masthead-logo">
<h1>Homelab</h1>
</div>
<span class="masthead-eyebrow">git.fhirworx.io</span>
</div>
<p class="tagline">
Self-hosted infrastructure for FHIR data engineering — version control, CI/CD,
notebooks, and the full lakehouse stack.
</p>
<div class="rule-line-thin"></div>
</div>
<div class="section-header">
<span class="section-eyebrow">Services</span>
<h2>Infrastructure</h2>
</div>
<div class="grid">
<a data-subdomain="traefik" target="_blank" class="tile proxy">
<span class="tile-badge new">New</span>
<span class="status-dot"></span>
<span class="icon">&#128279;</span>
<div class="tile-eyebrow">Networking</div>
<div class="tile-title">Traefik</div>
<p class="tile-desc">Cloud-native reverse proxy and load balancer</p>
<span class="tile-port"></span>
<div class="stripe"></div>
</a>
<a data-subdomain="s3console" target="_blank" class="tile storage">
<span class="status-dot"></span>
<span class="icon">&#128190;</span>
<div class="tile-eyebrow">Storage</div>
<div class="tile-title">RustFS</div>
<p class="tile-desc">S3-compatible object storage for all your data needs</p>
<span class="tile-port"></span>
<div class="stripe"></div>
</a>
<a data-subdomain="git" class="tile git">
<span class="status-dot"></span>
<span class="icon">&#128025;</span>
<div class="tile-eyebrow">Version Control</div>
<div class="tile-title">Gitea</div>
<p class="tile-desc">Self-hosted Git service with packages and CI</p>
<span class="tile-port"></span>
<div class="stripe"></div>
</a>
<a data-subdomain="notebooks" target="_blank" class="tile notebook">
<span class="tile-badge gpu">GPU</span>
<span class="status-dot"></span>
<span class="icon">&#128209;</span>
<div class="tile-eyebrow">Analysis</div>
<div class="tile-title">Notebooks</div>
<p class="tile-desc">Marimo reactive notebooks with CUDA acceleration</p>
<span class="tile-port"></span>
<div class="stripe"></div>
</a>
<a data-subdomain="zotero" target="_blank" class="tile research">
<span class="tile-badge gpu">GPU</span>
<span class="status-dot"></span>
<span class="icon">&#128218;</span>
<div class="tile-eyebrow">Research</div>
<div class="tile-title">Zotero</div>
<p class="tile-desc">Research reference manager in the cloud</p>
<span class="tile-port"></span>
<div class="stripe"></div>
</a>
<a data-subdomain="docs" target="_blank" class="tile research">
<span class="tile-badge new">New</span>
<span class="status-dot"></span>
<span class="icon">&#128214;</span>
<div class="tile-eyebrow">Documentation</div>
<div class="tile-title">Docs</div>
<p class="tile-desc">API reference and CMS bibliography browser</p>
<span class="tile-port"></span>
<div class="stripe"></div>
</a>
<a data-subdomain="nessie" data-path="/api/v2/config" target="_blank" class="tile catalog">
<span class="tile-badge data">Data</span>
<span class="status-dot"></span>
<span class="icon">&#127795;</span>
<div class="tile-eyebrow">Catalog</div>
<div class="tile-title">Nessie</div>
<p class="tile-desc">Git-like versioned data catalog for Apache Iceberg</p>
<span class="tile-port"></span>
<div class="stripe"></div>
</a>
<a data-subdomain="trino" target="_blank" class="tile query">
<span class="tile-badge data">Data</span>
<span class="status-dot"></span>
<span class="icon">&#128269;</span>
<div class="tile-eyebrow">Query</div>
<div class="tile-title">Trino</div>
<p class="tile-desc">Distributed SQL query engine for the lakehouse</p>
<span class="tile-port"></span>
<div class="stripe"></div>
</a>
<a data-subdomain="polaris" target="_blank" class="tile catalog">
<span class="tile-badge new">New</span>
<span class="status-dot"></span>
<span class="icon">&#11088;</span>
<div class="tile-eyebrow">Catalog</div>
<div class="tile-title">Polaris</div>
<p class="tile-desc">Apache Iceberg catalog with governance and Unity-style access</p>
<span class="tile-port"></span>
<div class="stripe"></div>
</a>
<a data-subdomain="grafana" target="_blank" class="tile observability">
<span class="status-dot"></span>
<span class="icon">&#128202;</span>
<div class="tile-eyebrow">Observability</div>
<div class="tile-title">Grafana</div>
<p class="tile-desc">Observability dashboards for metrics, logs, and traces</p>
<span class="tile-port"></span>
<div class="stripe"></div>
</a>
<a data-subdomain="tempo" target="_blank" class="tile metrics">
<span class="status-dot"></span>
<span class="icon">&#128065;</span>
<div class="tile-eyebrow">Tracing</div>
<div class="tile-title">Tempo</div>
<p class="tile-desc">Distributed tracing for microservices</p>
<span class="tile-port"></span>
<div class="stripe"></div>
</a>
<a data-subdomain="prometheus" target="_blank" class="tile logs">
<span class="status-dot"></span>
<span class="icon">&#128200;</span>
<div class="tile-eyebrow">Metrics</div>
<div class="tile-title">Prometheus</div>
<p class="tile-desc">Metrics collection and alerting</p>
<span class="tile-port"></span>
<div class="stripe"></div>
</a>
<a data-subdomain="loki" data-path="/ready" target="_blank" class="tile database">
<span class="status-dot"></span>
<span class="icon">&#128203;</span>
<div class="tile-eyebrow">Logs</div>
<div class="tile-title">Loki</div>
<p class="tile-desc">Log aggregation system by Grafana</p>
<span class="tile-port"></span>
<div class="stripe"></div>
</a>
</div>
<div class="ftr">
<span>fhirworx.io</span> &mdash; self-hosted data lakehouse &mdash; &copy; 2025
</div>
</div>
<script>
(function() {
var parts = location.hostname.split('.');
var base = parts.length > 2 ? parts.slice(1).join('.') : location.hostname;
document.querySelectorAll('.homelab-dashboard [data-subdomain]').forEach(function(el) {
var sub = el.dataset.subdomain;
var path = el.dataset.path || '';
var fqdn = sub + '.' + base;
el.href = location.protocol + '//' + fqdn + path;
el.target = '_blank';
var port = el.querySelector('.tile-port');
if (port) port.textContent = fqdn;
});
})();
</script>
{{template "base/footer" .}}