From 08032c004bdd838323169dc1c6f099f27cf58787 Mon Sep 17 00:00:00 2001 From: Till JS Date: Tue, 31 Mar 2026 18:47:55 +0200 Subject: [PATCH] feat(manascore): add live uptime badges from status.mana.how MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - generate-status-page.sh now also writes status.json alongside index.html Format: { updated, summary: {up, total}, services: { appName: bool } } - nginx status.mana.how serves status.json with CORS headers (public read) and explicit location block to avoid rewrite to index.html - ManaScore index page fetches status.json client-side on load and injects green ● LIVE / red ● DOWN badge next to each app's status chip Co-Authored-By: Claude Sonnet 4.6 --- .../landing/src/pages/manascore/index.astro | 22 +++++++++++++++ docker/nginx/landings.conf | 12 ++++++++ scripts/generate-status-page.sh | 28 +++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/apps/manacore/apps/landing/src/pages/manascore/index.astro b/apps/manacore/apps/landing/src/pages/manascore/index.astro index fb20ae84b..24e60a81a 100644 --- a/apps/manacore/apps/landing/src/pages/manascore/index.astro +++ b/apps/manacore/apps/landing/src/pages/manascore/index.astro @@ -170,6 +170,7 @@ const statuses = [...new Set(sortedAudits.map((a) => a.data.status))]; {data.app} + {data.date.toLocaleDateString('de-DE', { day: '2-digit', @@ -547,4 +548,25 @@ const statuses = [...new Set(sortedAudits.map((a) => a.data.status))]; // Sort select sortSelect.addEventListener('change', applySort); + + // Live uptime badges from status.mana.how/status.json + (async () => { + try { + const res = await fetch('https://status.mana.how/status.json', { cache: 'no-store' }); + if (!res.ok) return; + const data = await res.json(); + const services: Record = data.services ?? {}; + + document.querySelectorAll('.live-badge').forEach((badge) => { + const app = badge.dataset.app; + if (!app || !(app in services)) return; + const up = services[app]; + badge.innerHTML = up + ? '● LIVE' + : '● DOWN'; + }); + } catch { + // status.mana.how unreachable — silently skip badges + } + })(); diff --git a/docker/nginx/landings.conf b/docker/nginx/landings.conf index c43a72a31..b965542a7 100644 --- a/docker/nginx/landings.conf +++ b/docker/nginx/landings.conf @@ -118,10 +118,22 @@ server { add_header X-Content-Type-Options "nosniff" always; add_header Cache-Control "no-store" always; + # Allow ManaScore page to fetch status.json + add_header Access-Control-Allow-Origin "*" always; + add_header Access-Control-Allow-Methods "GET" always; + location / { try_files $uri /index.html; } + # Serve status.json directly (do not rewrite to index.html) + location = /status.json { + add_header Content-Type "application/json" always; + add_header Cache-Control "no-store" always; + add_header Access-Control-Allow-Origin "*" always; + try_files $uri =404; + } + location /health { access_log off; return 200 "healthy\n"; diff --git a/scripts/generate-status-page.sh b/scripts/generate-status-page.sh index 9976cef70..a27ef8638 100755 --- a/scripts/generate-status-page.sh +++ b/scripts/generate-status-page.sh @@ -368,3 +368,31 @@ HTMLEOF mv "${OUTPUT}.tmp" "$OUTPUT" echo "$(date '+%H:%M:%S') Status-Seite generiert → $OUTPUT (${total_up}/${total_all} online)" + +# ── status.json für ManaScore Live-Badge ───────────────────────────────────── + +JSON_OUTPUT="$(dirname "$OUTPUT")/status.json" +TIMESTAMP_ISO="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" + +echo "$SUCCESS_JSON" | jq \ + --arg ts "$TIMESTAMP_ISO" \ + --argjson total_up "$total_up" \ + --argjson total_all "$total_all" \ + '{ + updated: $ts, + summary: { up: $total_up, total: $total_all }, + services: ( + .data.result | map({ + key: ( + .metric.instance + | ltrimstr("https://") + | if . == "mana.how" then "manacore" + else (. | rtrimstr(".mana.how") | rtrimstr("/health")) + end + ), + value: (.value[1] == "1") + }) | from_entries + ) + }' > "${JSON_OUTPUT}.tmp" && mv "${JSON_OUTPUT}.tmp" "$JSON_OUTPUT" + +echo "$(date '+%H:%M:%S') status.json generiert → $JSON_OUTPUT"