Files
windwiderstand/src/lib/maintenance.server.ts
T
Peter Meier 56084ac542
Deploy / verify (push) Successful in 43s
Deploy / deploy (push) Successful in 1m4s
feat(maintenance): static fallback when the CMS is unreachable
Adds a self-contained maintenance page that the SvelteKit handle hook
serves before the first CMS call when `isCmsAvailable()` returns
false. The probe hits `/api-docs/openapi.json` with a short timeout
and caches the result (10s healthy, 3s unhealthy) so we don't pay a
round-trip per request. `/maintenance` and `?cms_down=1` simulate
the page without taking the CMS down — useful for previewing the
copy.

The maintenance HTML is fully inline (no CMS calls, no layout, no
external CSS) so it survives even when every dependency is down.
Returned with 503 + Retry-After:60 + noindex headers.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 14:47:15 +02:00

62 lines
2.0 KiB
TypeScript

/**
* Statisches Maintenance-HTML für CMS-Ausfälle.
* Selbsttragend: keine CMS-Calls, kein Layout, inline CSS.
*/
const MAINTENANCE_HTML = `<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="robots" content="noindex,nofollow">
<title>Wartungsarbeiten — windwiderstand.de</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<style>
:root { color-scheme: light; }
html, body { margin: 0; padding: 0; height: 100%; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
background: #f8f7f3;
color: #18181b;
display: flex; align-items: center; justify-content: center;
min-height: 100vh; padding: 1.5rem;
}
.card { max-width: 36rem; text-align: center; }
.badge {
display: inline-block; padding: 0.25rem 0.75rem; border-radius: 9999px;
background: #e7f2ea; color: #2d7a45;
font-size: 0.875rem; font-weight: 600; letter-spacing: 0.025em;
margin-bottom: 1.25rem;
}
h1 {
font-size: clamp(1.75rem, 4vw, 2.5rem);
margin: 0 0 0.75rem; color: #18181b; font-weight: 700;
}
p {
font-size: 1.0625rem; line-height: 1.6; color: #52525b;
margin: 0 0 0.75rem;
}
.small { font-size: 0.875rem; color: #71717a; margin-top: 1.5rem; }
a { color: #2d7a45; }
</style>
</head>
<body>
<main class="card" role="main">
<span class="badge">Wartungsmodus</span>
<h1>Wir sind gleich zurück.</h1>
<p>Diese Seite wird gerade aktualisiert oder ist vorübergehend nicht erreichbar. Bitte versuche es in wenigen Minuten erneut.</p>
<p class="small">Vielen Dank für deine Geduld.</p>
</main>
</body>
</html>
`;
export function maintenanceResponse(status: 200 | 503 = 503): Response {
const headers: Record<string, string> = {
'content-type': 'text/html; charset=utf-8',
'cache-control': 'no-store',
'x-robots-tag': 'noindex, nofollow',
};
if (status === 503) headers['retry-after'] = '60';
return new Response(MAINTENANCE_HTML, { status, headers });
}