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,51 @@
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import type { NextConfig } from 'next'
|
||||
import bundleAnalyzer from '@next/bundle-analyzer'
|
||||
|
||||
const withBundleAnalyzer = bundleAnalyzer({ enabled: process.env.ANALYZE === 'true' })
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
// Standalone-Build fuer das Container-Image, siehe docker/web.Dockerfile.
|
||||
output: 'standalone',
|
||||
// fileURLToPath statt URL.pathname: der Projektpfad enthält ein Leerzeichen,
|
||||
// das pathname als %20 stehen ließe. Der Standalone-Build landete dadurch in
|
||||
// einem falsch benannten Unterordner.
|
||||
outputFileTracingRoot: path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'),
|
||||
|
||||
reactStrictMode: true,
|
||||
poweredByHeader: false,
|
||||
|
||||
// Der Cloudflare Tunnel komprimiert, im Stack ist dafuer nichts zu tun.
|
||||
compress: false,
|
||||
|
||||
experimental: {
|
||||
// Autoren-, Rollen- und Vorlagendaten werden prozesslokal gecacht,
|
||||
// siehe docs/09-performance-und-ux.md.
|
||||
staleTimes: { dynamic: 30, static: 180 },
|
||||
},
|
||||
|
||||
async headers() {
|
||||
return [
|
||||
{
|
||||
source: '/:path*',
|
||||
headers: [
|
||||
{ key: 'X-Content-Type-Options', value: 'nosniff' },
|
||||
{ key: 'Referrer-Policy', value: 'same-origin' },
|
||||
{ key: 'X-Frame-Options', value: 'DENY' },
|
||||
{
|
||||
key: 'Permissions-Policy',
|
||||
value: 'camera=(), microphone=(), geolocation=(), interest-cohort=()',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
// Selbst gehostete Schriften sind unveraenderlich.
|
||||
source: '/fonts/:file*',
|
||||
headers: [{ key: 'Cache-Control', value: 'public, max-age=31536000, immutable' }],
|
||||
},
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
export default withBundleAnalyzer(nextConfig)
|
||||
Reference in New Issue
Block a user