Reverts61ccce5, which revertedecbda3f. The decision came back to Vercel, so the two platform accommodations return: output: "standalone" is conditional on VERCEL again, and /api/import goes back to 60 seconds, the free tier's ceiling. The Docker path is unaffected and stays documented — including the internal network notes and deploy/Caddyfile written in between, which remain correct for anyone taking that road. DEPLOYMENT.md conflicted at the top and now carries both introductions instead of one replacing the other. Verified with VERCEL=1: builds clean and emits no standalone directory. Stated once and recorded here rather than repeated: Vercel's Hobby plan excludes commercial use, and this is a company's HR system. Defensible while the database holds nothing but the 852 invented people from the seed; Pro at $20/month is the licensed path once real personnel data is in it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
73 lines
3.1 KiB
TypeScript
73 lines
3.1 KiB
TypeScript
import type { NextConfig } from "next";
|
|
|
|
// Report-only rather than enforcing, deliberately: the policy is derived from
|
|
// what this app is known to load — its own bundle, the self-hosted Nunito
|
|
// files from next/font, and nothing else — but an unenforced policy that logs
|
|
// violations is worth more than a guessed one that blanks the app for every
|
|
// HR user. Promote it to `Content-Security-Policy` once the reports come back
|
|
// clean.
|
|
//
|
|
// 'unsafe-inline' on script-src is not laziness: Next.js inlines its
|
|
// bootstrap and hydration payload as inline <script> tags, so a nonce-based
|
|
// policy means threading a per-request nonce through proxy.ts — a separate
|
|
// change, and the reason this starts in report-only.
|
|
function contentSecurityPolicy(): string {
|
|
// Die Anmeldung schickt ein Formular an /api/auth/signin/…, und von dort
|
|
// geht es per Weiterleitung zum Anmeldeserver. `form-action` gilt auch für
|
|
// die Weiterleitungen nach einem Formularversand — steht der Aussteller
|
|
// nicht darin, bricht der Browser die Anmeldung ab. Genau hier wäre die
|
|
// Nur-Bericht-Fassung später eine böse Überraschung.
|
|
let issuerOrigin = "";
|
|
try {
|
|
issuerOrigin = new URL(process.env.AUTH_MICROSOFT_ENTRA_ID_ISSUER ?? "").origin;
|
|
} catch {
|
|
issuerOrigin = "";
|
|
}
|
|
const formAction = ["'self'", issuerOrigin].filter(Boolean).join(" ");
|
|
|
|
return [
|
|
"default-src 'self'",
|
|
"script-src 'self' 'unsafe-inline'",
|
|
"style-src 'self' 'unsafe-inline'",
|
|
"img-src 'self' data: blob:",
|
|
"font-src 'self'",
|
|
// Die Anwendung spricht im Browser mit niemandem ausser sich selbst: die
|
|
// Datenbank erreicht nur der Server, und seit die API-Schicht weg ist,
|
|
// gibt es keine Gegenstelle mehr, die von aussen angesprochen würde.
|
|
"connect-src 'self'",
|
|
"frame-ancestors 'self'",
|
|
"base-uri 'self'",
|
|
`form-action ${formAction}`,
|
|
"object-src 'none'",
|
|
].join("; ");
|
|
}
|
|
|
|
const nextConfig: NextConfig = {
|
|
// Emits a self-contained .next/standalone server (only the deps actually
|
|
// used at runtime, no full node_modules) — what the Dockerfile copies in.
|
|
//
|
|
// Auf Vercel ist das falsch: dort baut die Plattform selbst und erwartet
|
|
// die übliche Ausgabe. `VERCEL` setzt sie in jeder Baustrecke, die Angabe
|
|
// entfällt dort also von selbst — und der Docker-Weg bleibt unberührt.
|
|
output: process.env.VERCEL ? undefined : "standalone",
|
|
// Baseline security headers (clickjacking, MIME-sniffing, referrer leakage,
|
|
// browser feature access) plus the report-only CSP described above.
|
|
async headers() {
|
|
return [
|
|
{
|
|
source: "/:path*",
|
|
headers: [
|
|
{ key: "X-Frame-Options", value: "SAMEORIGIN" },
|
|
{ key: "X-Content-Type-Options", value: "nosniff" },
|
|
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
|
|
{ key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=()" },
|
|
{ key: "Strict-Transport-Security", value: "max-age=63072000; includeSubDomains" },
|
|
{ key: "Content-Security-Policy-Report-Only", value: contentSecurityPolicy() },
|
|
],
|
|
},
|
|
];
|
|
},
|
|
};
|
|
|
|
export default nextConfig;
|