fix: Gitea CI/CD und Blank-Page-Fehler behoben
Build & Deploy Tippspiel / build (push) Successful in 15s

- Helmet CSP: upgrade-insecure-requests und HSTS für HTTP-Deployments deaktiviert
  (war die Ursache der leeren Seite - Browser versuchte JS über HTTPS zu laden)
- Backend: statische Dateien werden jetzt in allen NODE_ENV-Modi serviert
- Frontend: IS_DEV erkennt auch VITE_TEST_MODE=true (Build-Zeit Variable)
- Dockerfile: VITE_TEST_MODE=true beim Vite-Build, NODE_ENV=development
- docker-compose.yml: NODE_ENV=development, CORS_ORIGIN=*
- Gitea Workflow: Auth-Token für git clone, Build via Portainer API statt lokaler Docker CLI

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ronny
2026-04-06 11:46:56 +02:00
parent f500f5f900
commit 20f61a0417
6 changed files with 94 additions and 19 deletions
+23 -6
View File
@@ -28,6 +28,10 @@ app.use(
// Staffbase lädt das Plugin in einem iFrame
// X-Frame-Options muss daher SAMEORIGIN oder ALLOW-FROM erlauben
frameguard: false,
// HSTS nur aktivieren wenn wir über HTTPS laufen (z.B. hinter einem Reverse Proxy)
hsts: process.env.NODE_ENV === 'production' && process.env.PLUGIN_BASE_URL?.startsWith('https')
? { maxAge: 15552000, includeSubDomains: true }
: false,
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
@@ -35,6 +39,8 @@ app.use(
styleSrc: ["'self'", "'unsafe-inline'"], // für inline styles im Frontend
imgSrc: ["'self'", 'data:', 'https://crests.football-data.org'],
frameAncestors: ['https://app.staffbase.com', 'https://*.staffbase.com'],
// upgrade-insecure-requests nur wenn HTTPS verfügbar ist, sonst werden JS-Assets geblockt
upgradeInsecureRequests: process.env.PLUGIN_BASE_URL?.startsWith('https') ? [] : null,
},
},
})
@@ -48,6 +54,10 @@ const allowedOrigins = (process.env.CORS_ORIGIN ?? 'https://app.staffbase.com')
app.use(
cors({
origin: (origin, callback) => {
// Wildcard: alle Origins erlauben
if (allowedOrigins.includes('*')) {
return callback(null, true);
}
// Requests ohne Origin (z.B. direkte API-Calls) in Development erlauben
if (!origin && process.env.NODE_ENV !== 'production') {
return callback(null, true);
@@ -137,15 +147,22 @@ if (process.env.NODE_ENV === 'development') {
// ============================================================
// Frontend (React Build) statisches Serving
// In Production liefert das Backend auch das Frontend aus
// Wird in allen Modi aktiviert, wenn ein public-Ordner existiert
// (Docker-Container liefern Frontend immer über das Backend aus)
// ============================================================
if (process.env.NODE_ENV === 'production') {
{
// eslint-disable-next-line @typescript-eslint/no-var-requires
const path = require('path') as typeof import('path');
app.use(express.static(path.join(process.cwd(), 'public')));
app.get('*', (_req, res) => {
res.sendFile(path.join(process.cwd(), 'public', 'index.html'));
});
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fs = require('fs') as typeof import('fs');
const publicDir = path.join(process.cwd(), 'public');
if (fs.existsSync(publicDir)) {
logger.info('Serving frontend static files from', { publicDir });
app.use(express.static(publicDir));
app.get('*', (_req, res) => {
res.sendFile(path.join(publicDir, 'index.html'));
});
}
}
// ============================================================