Files
kalendartool/next.config.mjs

73 lines
2.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/** @type {import('next').NextConfig} */
// MultiToolApp-Plattform (module-plan.md):
// HUB_URL – Basis-URL des Hubs (JWKS-Abruf für Token-Validierung)
// HUB_BASE_PATH – Pfad, unter dem der Hub diese App routet (z. B. /apps/kalender).
// Setzt Next.js basePath → alle Routen hängen darunter.
// Ohne HUB_BASE_PATH läuft die App standalone (basePath: '').
const hubUrl = (process.env.HUB_URL ?? '').replace(/\/$/, '');
const hubBasePath = (process.env.HUB_BASE_PATH ?? '').replace(/\/$/, '');
const nextConfig = {
// Standalone-Ausgabe für einen schlanken Docker-Container
output: 'standalone',
reactStrictMode: true,
// Proxy-Modus: App läuft unter /apps/<slug> innerhalb der Hub-Domain.
// basePath '' (falsy) = Standalone-Betrieb ohne Pfad-Präfix.
...(hubBasePath ? { basePath: hubBasePath } : {}),
// Manifest-Route: /.well-known/app-manifest → /api/manifest
// (Next.js App Router routed keine Dot-Ordner; mit beforeFiles-Phase
// fangen wir den Pfad ab, bevor basePath zuschlägt.)
async rewrites() {
return {
beforeFiles: [
{
source: '/.well-known/app-manifest',
destination: '/api/manifest',
},
],
};
},
// Security-Header (Next.js setzt keine davon by default):
// - X-Content-Type-Options: verhindert MIME-Sniffing
// - Referrer-Policy: keine URLs/Token an Dritte leaken
// - Permissions-Policy: Browser-Features, die die App nicht nutzt
// - CSP: Skripte nur 'self' + Inline (Next.js Hydration-Snippet);
// style-src 'unsafe-inline' ist fuer Tailwind noetig.
// - frame-ancestors: nur der Hub darf einbetten (statt X-Frame-Options,
// das Subdomain-Embedding blockieren wuerde – platform-plan.md §4).
async headers() {
return [
{
source: '/:path*',
headers: [
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
{
key: 'Permissions-Policy',
value: 'camera=(), microphone=(), geolocation=()',
},
{
key: 'Content-Security-Policy',
value: [
"default-src 'self'",
"script-src 'self' 'unsafe-inline'",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data:",
"font-src 'self'",
// JWKS-Abruf vom Hub (Token-Validierung in /auth/hub)
hubUrl ? `connect-src 'self' ${hubUrl}` : "connect-src 'self'",
// Proxy-Modus: kein Framing mehr nötig – aber der Hub darf
// weiterhin einbetten (Rückwärtskompatibilität).
hubUrl ? `frame-ancestors ${hubUrl}` : "frame-ancestors 'none'",
"base-uri 'self'",
"form-action 'self'",
].join('; '),
},
],
},
];
},
};
export default nextConfig;