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.
52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
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)
|