Web-Anwendung: Design-Tokens, Texte, Gesundheitsendpunkt
Design-Tokens aus docs/10-design-system.md als CSS-Variablen: Grundpalette, die sechs Klassifizierungsfarben, Eckenradius durchgehend 2 px, keine Schatten ausser dem Fokusring. Der Schwärzungsbalken mit dem einmaligen Durchwischen respektiert prefers-reduced-motion. Vier Tests halten die Tokens gegen das Dokument. IBM Plex selbst gehostet als woff2, latin und latin-ext getrennt über unicode-range, font-display: swap, immutable-Cache. Alle Oberflächentexte in lib/i18n/de.ts. Ein Test durchsucht app/ und components/ nach Umlauten im JSX und schlägt fehl, wenn dort deutscher Text steht. Er hat beim ersten Lauf gleich einen Verstoss gefunden. /api/health prüft Datenbank, Discord-Gateway und ClamAV. Die Gesamtbewertung fällt nur auf "down", wenn die Datenbank weg ist: die anderen Dienste haben eigene Healthchecks im Stack, und ein ausgefallener Virenscanner soll nicht den Web-Container als tot markieren. Strikte CSP mit Nonce, kein unsafe-inline für Skripte. Die erste Route liegt bei 100 kB JavaScript nach Kompression, Budget sind 120 kB. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
51984f17d4
commit
6b0cd331bb
@@ -0,0 +1,72 @@
|
||||
import { Suspense } from 'react'
|
||||
import { collectHealth, type ComponentState } from '@/lib/health/check'
|
||||
import { de } from '@/lib/i18n/de'
|
||||
import { SkeletonLine } from '@/components/Skeleton'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const STATE_LABEL: Record<ComponentState, string> = {
|
||||
up: de.health.ok,
|
||||
degraded: de.health.degraded,
|
||||
down: de.health.down,
|
||||
}
|
||||
|
||||
async function SystemState() {
|
||||
const report = await collectHealth()
|
||||
return (
|
||||
<table className="w-full max-w-(--container-measure) border-collapse text-sm">
|
||||
<caption className="pb-2 text-left font-condensed text-xs text-text-dim">
|
||||
{de.health.checkedAt(new Date(report.checkedAt).toLocaleString('de-DE'))}
|
||||
</caption>
|
||||
<thead>
|
||||
<tr className="border-b border-line text-left text-xs text-text-dim">
|
||||
<th scope="col" className="py-1.5 pr-4 font-normal">
|
||||
{de.health.service}
|
||||
</th>
|
||||
<th scope="col" className="py-1.5 font-normal">
|
||||
{de.health.state}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{Object.entries(report.components).map(([key, value]) => (
|
||||
<tr key={key} className="border-b border-line/60">
|
||||
<td className="py-2 pr-4">{de.health.components[key] ?? key}</td>
|
||||
<td className="py-2">
|
||||
{/* Zustand als Text, nicht nur als Farbe. */}
|
||||
<span className="font-condensed">{STATE_LABEL[value.status]}</span>
|
||||
{value.detail ? (
|
||||
<span className="ml-2 font-mono text-2xs text-text-dim">{value.detail}</span>
|
||||
) : null}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
)
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main id="inhalt" className="mx-auto max-w-(--container-measure) px-6 py-12">
|
||||
<h1 className="font-condensed">{de.app.name}</h1>
|
||||
<p className="mt-2 max-w-(--container-measure) text-text-dim">{de.app.description}</p>
|
||||
|
||||
<hr className="my-8 border-line" />
|
||||
|
||||
<h2 className="mb-4 font-condensed">{de.health.heading}</h2>
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className="max-w-(--container-measure)">
|
||||
<SkeletonLine width="14rem" />
|
||||
<SkeletonLine />
|
||||
<SkeletonLine />
|
||||
<SkeletonLine />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<SystemState />
|
||||
</Suspense>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user