Add full application: receipt scanning, auth, billing, and account deletion
Brings the working codebase (Next.js app, auth system, Stripe billing, Docker/deploy config, tests, docs) into version control on top of the placeholder initial commit, and adds account self-deletion (Danger Zone in Settings, password + typed-email confirmation, cascading DB cleanup, Stripe cancellation) per GDPR right-to-erasure. Excludes local build caches, node_modules, and internal agent scratch files; .gitignore hardened to keep those out going forward. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
108
next.config.ts
Normal file
108
next.config.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
// Umami's script origin, derived from NEXT_PUBLIC_UMAMI_SRC so the CSP below
|
||||
// only needs the one env var to stay in sync with the <Script> tag in the
|
||||
// root layouts — no separate CSP-domain variable to keep updated by hand.
|
||||
const umamiOrigin = (() => {
|
||||
if (!process.env.NEXT_PUBLIC_UMAMI_SRC) return null;
|
||||
try {
|
||||
return new URL(process.env.NEXT_PUBLIC_UMAMI_SRC).origin;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
})();
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
output: "standalone",
|
||||
serverExternalPackages: ["exceljs", "sharp", "pdfjs-dist", "@napi-rs/canvas", "heic-convert", "heic-decode", "libheif-js"],
|
||||
// pdfjs-dist lädt @napi-rs/canvas zur Laufzeit dynamisch (createRequire),
|
||||
// daher findet der Standalone-Trace das native Modul nicht von selbst. Ohne
|
||||
// diesen Include fehlt @napi-rs/canvas im Docker-Image und PDF-Rasterisierung
|
||||
// schlägt mit "Cannot load @napi-rs/canvas" fehl. Hier explizit einschließen.
|
||||
outputFileTracingIncludes: {
|
||||
"/api/scan": [
|
||||
"./node_modules/@napi-rs/canvas/**/*",
|
||||
"./node_modules/heic-convert/**/*",
|
||||
"./node_modules/heic-decode/**/*",
|
||||
"./node_modules/libheif-js/**/*",
|
||||
"./node_modules/jpeg-js/**/*",
|
||||
"./node_modules/pngjs/**/*",
|
||||
],
|
||||
},
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: "http",
|
||||
hostname: "localhost",
|
||||
},
|
||||
{
|
||||
protocol: "https",
|
||||
hostname: "localhost",
|
||||
},
|
||||
],
|
||||
},
|
||||
async redirects() {
|
||||
return [
|
||||
{
|
||||
// The bare domain has no page of its own (only /de and /en are
|
||||
// pre-rendered) — without this it 404s, which kills every backlink,
|
||||
// social share, and type-in visit to the naked root URL.
|
||||
source: "/",
|
||||
destination: "/en",
|
||||
permanent: true,
|
||||
},
|
||||
];
|
||||
},
|
||||
async headers() {
|
||||
return [
|
||||
{
|
||||
// Unconditional security headers — applied to every response.
|
||||
source: "/(.*)",
|
||||
headers: [
|
||||
{ key: "X-Frame-Options", value: "DENY" },
|
||||
{ key: "X-Content-Type-Options", value: "nosniff" },
|
||||
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
|
||||
{ key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=(), payment=()" },
|
||||
{
|
||||
// Static CSP, applied to every response via next.config headers().
|
||||
// NOTE on `script-src 'self' 'unsafe-inline'`: the /de and /en
|
||||
// landing pages are statically generated (SSG), so Next.js cannot
|
||||
// inject a per-request nonce into their pre-built HTML. A strict
|
||||
// `'self'`-only script-src would block Next.js's inline hydration
|
||||
// scripts and break the pages. This is the pattern Next.js
|
||||
// documents for statically rendered apps ("Without Nonces").
|
||||
// 'unsafe-inline' is required for scripts, but every other
|
||||
// directive stays strict (no eval, no external objects, etc.).
|
||||
key: "Content-Security-Policy",
|
||||
value: [
|
||||
"default-src 'self'",
|
||||
`script-src 'self' 'unsafe-inline'${umamiOrigin ? ` ${umamiOrigin}` : ""}`,
|
||||
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
|
||||
"img-src 'self' data: blob: https:",
|
||||
"font-src 'self' data: https://fonts.gstatic.com",
|
||||
`connect-src 'self'${umamiOrigin ? ` ${umamiOrigin}` : ""}`,
|
||||
"object-src 'none'",
|
||||
"base-uri 'self'",
|
||||
"frame-ancestors 'none'",
|
||||
"form-action 'self'",
|
||||
].join("; "),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
// HSTS is emitted only when the request actually arrived over HTTPS
|
||||
// (x-forwarded-proto: https). Emitting it on plain-HTTP responses would
|
||||
// let an HTTP server promise an upgrade it cannot deliver and poison
|
||||
// HTTP clients' upgrade expectations. The directive itself is unchanged:
|
||||
// max-age=63072000 (2 years), includeSubDomains, preload.
|
||||
source: "/(.*)",
|
||||
has: [{ type: "header", key: "x-forwarded-proto", value: "https" }],
|
||||
headers: [
|
||||
{ key: "Strict-Transport-Security", value: "max-age=63072000; includeSubDomains; preload" },
|
||||
],
|
||||
},
|
||||
];
|
||||
},
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
Reference in New Issue
Block a user