diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 3218608..f57845d 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -23,6 +23,12 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 + - name: Setup Node.js (22.12.0) for auxiliary scripts + uses: actions/setup-node@v4 + with: + node-version: '22.12.0' + check-latest: true + - name: Log in to CitySensor Container Registry uses: docker/login-action@v3 with: diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..1d9b783 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +22.12.0 diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..df4dbb2 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +node 22.12.0 diff --git a/NODEJS_README.md b/NODEJS_README.md index f613540..b00cdde 100644 --- a/NODEJS_README.md +++ b/NODEJS_README.md @@ -33,6 +33,22 @@ A complete modern web application built with Node.js, TypeScript, React, and MyS ## � Quick Start +### ⚙️ Node Version + +Empfohlene Node Version: **22.12.0** (oder LTS 20.19.x). Projekt liefert `.nvmrc`. + +Mit nvm aktivieren: +```bash +nvm install 22.12.0 +nvm use 22.12.0 +``` +Automatisch beim Wechsel ins Verzeichnis: +```bash +nvm use +``` + +Falls ohne nvm: Offizielles Binary oder Paketmanager (Node >=22.12.0) installieren. + ### 1. Start the Database (existing Docker setup) ```bash # From main project directory @@ -42,6 +58,7 @@ docker-compose up -d ### 2. Start the Node.js Backend ```bash cd backend +nvm use # optional, falls nvm npm install npm run build node dist/app.js @@ -50,6 +67,7 @@ node dist/app.js ### 3. Start the React Frontend ```bash cd frontend +nvm use # optional npm install npm run dev ``` diff --git a/README.md b/README.md index a3b4314..ffcbdeb 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,83 @@ -# Rezepte - Docker Setup +# Rezepte - Docker & Modern Stack -Eine dockerisierte Version der Rezepte-Verwaltungsanwendung mit PHP, MySQL und phpMyAdmin. +Dieses Repository enthält zwei Welten: den modernen Node.js / React Stack sowie die historische PHP Legacy-App. Über Docker Compose Profile kannst du gezielt nur die benötigten Teile starten. -## Komponenten +## Services & Ports -- **PHP-App**: Rezepte-Anwendung (Port 8082) -- **MySQL**: Datenbankserver (Port 3307) -- **phpMyAdmin**: Datenbankadministration (Port 8083) +| Service | Profil | Port Host -> Container | Beschreibung | +|--------------|-----------|------------------------|--------------| +| mysql | default | 3307 -> 3306 | MySQL 8 Datenbank | +| backend | default | 3001 -> 3001 | Node.js API (Express + Prisma) | +| frontend | default | 3000 -> 80 | React Build via nginx | +| php-app | legacy | 8082 -> 80 | Altes PHP Frontend | +| phpmyadmin | admin | 8083 -> 80 | DB Verwaltung | -## Schnellstart +## Node / Modern Stack +Empfohlene Node Version: **22.12.0** (`.nvmrc`, `.tool-versions`). -1. **Docker starten:** - ```bash - docker-compose up -d - ``` +Lokal ohne Docker (Entwicklung Hot Reload): +```bash +nvm use +cd backend && npm install && npm run dev # startet API auf :3001 +cd ../frontend && npm install && npm run dev # startet Vite auf :5173 +``` -2. **Anwendung öffnen:** - - Rezepte-App: http://localhost:8082 - - phpMyAdmin: http://localhost:8083 +## Docker Nutzung -3. **Container stoppen:** - ```bash - docker-compose down - ``` +### Standard (nur moderner Stack: DB + API + Frontend) +```bash +docker compose up -d +``` +Öffnen: http://localhost:3000 + +### Mit Legacy PHP zusätzlich +```bash +docker compose --profile legacy up -d +``` +Öffnen: http://localhost:8082 + +### Mit phpMyAdmin zusätzlich +```bash +docker compose --profile admin up -d +``` +Öffnen: http://localhost:8083 + +### Beide Zusatz-Profile +```bash +docker compose --profile legacy --profile admin up -d +``` + +### Alles stoppen +```bash +docker compose down +``` + +### Neu bauen (z.B. nach Codeänderungen Backend/Frontend) +```bash +docker compose build backend frontend +docker compose up -d +``` + +### Nur Backend neu bauen +```bash +docker compose build backend && docker compose up -d backend +``` + +### Logs +```bash +docker compose logs -f backend +docker compose logs -f frontend +docker compose logs -f mysql +``` + +## CORS Hinweis +Aktuell ist `CORS_ORIGIN="*"` (Testphase). Für Produktion einschränken, z.B.: +```yaml +CORS_ORIGIN: http://esprimo:3000,http://localhost:3000 +``` +Danach Backend neu bauen. + +## Datenbankzugang ## Datenbankzugang @@ -41,23 +96,16 @@ Eine dockerisierte Version der Rezepte-Verwaltungsanwendung mit PHP, MySQL und p - Username: root - Password: rezepte123 -## Entwicklung +## Entwicklung innerhalb Docker -### Container neu bauen: +Status: ```bash -docker-compose build --no-cache -docker-compose up -d +docker compose ps ``` -### Logs anzeigen: +Direktes DB Login (Host hat mysql Client): ```bash -docker-compose logs -f php-app -docker-compose logs -f mysql -``` - -### Container Status: -```bash -docker-compose ps +mysql -h 127.0.0.1 -P 3307 -u rezepte_user -p'rezepte_pass' rezepte ``` ## Datenvolumes @@ -66,4 +114,9 @@ Die MySQL-Daten werden in einem Docker-Volume gespeichert und bleiben auch nach ## Datenbankinitialisierung -Beim ersten Start werden automatisch alle Tabellen und Daten aus den SQL-Dateien importiert. \ No newline at end of file +Beim ersten Start importiert MySQL automatisch SQL-Skripte aus `sql-init/`. + +## Weiterführend +- Moderne Stack Doku: `NODEJS_README.md` +- Traefik / Registry Deploy: siehe entsprechende `*_SETUP.md` Dateien +- Sicherheitshärtung TODO: CORS einschränken, CSP Header, chown Migration verbessern \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile index 941de5d..6cd56f2 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,5 +1,5 @@ # Backend Dockerfile -FROM node:18-alpine AS builder +FROM node:22.12.0-alpine AS builder # Install OpenSSL for Prisma compatibility RUN apk add --no-cache openssl openssl-dev @@ -20,7 +20,7 @@ COPY . . RUN npm run build # Production stage -FROM node:18-alpine AS production +FROM node:22.12.0-alpine AS production # Install required system dependencies for Prisma and health checks RUN apk add --no-cache \ diff --git a/backend/dist/app.d.ts.map b/backend/dist/app.d.ts.map index 8f69e50..11a16fe 100644 --- a/backend/dist/app.d.ts.map +++ b/backend/dist/app.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAgBA,QAAA,MAAM,GAAG,6CAAY,CAAC;AA2GtB,eAAe,GAAG,CAAC"} \ No newline at end of file +{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAgBA,QAAA,MAAM,GAAG,6CAAY,CAAC;AA0HtB,eAAe,GAAG,CAAC"} \ No newline at end of file diff --git a/backend/dist/app.js b/backend/dist/app.js index 48590ef..9eb395a 100644 --- a/backend/dist/app.js +++ b/backend/dist/app.js @@ -32,13 +32,22 @@ const allowedOrigins = [ 'http://localhost:3000', config_1.config.cors.origin ].filter(Boolean); -app.use((0, cors_1.default)({ - origin: allowedOrigins, - credentials: true, -})); +const corsConfig = config_1.config.cors.origin === '*' + ? { + origin: true, + credentials: true, + } + : { + origin: allowedOrigins, + credentials: true, + }; +app.use((0, cors_1.default)(corsConfig)); app.use((req, res, next) => { const origin = req.headers.origin; - if (origin && allowedOrigins.includes(origin)) { + if (config_1.config.cors.origin === '*') { + res.header('Access-Control-Allow-Origin', origin || '*'); + } + else if (origin && allowedOrigins.includes(origin)) { res.header('Access-Control-Allow-Origin', origin); } res.header('Access-Control-Allow-Credentials', 'true'); @@ -52,6 +61,7 @@ app.use((req, res, next) => { app.use(express_1.default.json({ limit: '10mb' })); app.use(express_1.default.urlencoded({ extended: true, limit: '10mb' })); app.use(requestLogger_1.requestLogger); +app.use('/uploads', express_1.default.static(path_1.default.join(process.cwd(), 'uploads'))); app.use('/api/health', health_1.default); app.use('/api/recipes', recipes_1.default); app.use('/api/ingredients', ingredients_1.default); diff --git a/backend/dist/app.js.map b/backend/dist/app.js.map index 95dbcc7..9915f5c 100644 --- a/backend/dist/app.js.map +++ b/backend/dist/app.js.map @@ -1 +1 @@ -{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/backend/dist/config/config.js.map b/backend/dist/config/config.js.map index 26a806f..b964743 100644 --- a/backend/dist/config/config.js.map +++ b/backend/dist/config/config.js.map @@ -1 +1 @@ -{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config/config.ts"],"names":[],"mappings":";;;;;;AAAA,oDAA4B;AAE5B,gBAAM,CAAC,MAAM,EAAE,CAAC;AAEH,QAAA,MAAM,GAAG;IACpB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI;IAC9B,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa;IAE9C,QAAQ,EAAE;QACR,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,gEAAgE;KAClG;IAED,GAAG,EAAE;QACH,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,2BAA2B;QAC7D,SAAS,EAAE,KAAK;KACjB;IAED,MAAM,EAAE;QACN,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,WAAW;QAC5C,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,SAAS,CAAC;QAC7D,YAAY,EAAE,CAAC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,CAAC;KACrE;IAED,IAAI,EAAE;QACJ,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,uBAAuB;KAC3D;CACO,CAAC"} \ No newline at end of file +{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config/config.ts"],"names":[],"mappings":";;;;;;AAAA,oDAA4B;AAE5B,gBAAM,CAAC,MAAM,EAAE,CAAC;AAEH,QAAA,MAAM,GAAG;IACpB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI;IAC9B,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa;IAE9C,QAAQ,EAAE;QACR,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,0DAA0D;KAC5F;IAED,GAAG,EAAE;QACH,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,2BAA2B;QAC7D,SAAS,EAAE,KAAK;KACjB;IAED,MAAM,EAAE;QACN,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,WAAW;QAC5C,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,SAAS,CAAC;QAC7D,YAAY,EAAE,CAAC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,CAAC;KACrE;IAED,IAAI,EAAE;QACJ,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,uBAAuB;KAC3D;CACO,CAAC"} \ No newline at end of file diff --git a/backend/dist/routes/health.js.map b/backend/dist/routes/health.js.map index f409565..f39843a 100644 --- a/backend/dist/routes/health.js.map +++ b/backend/dist/routes/health.js.map @@ -1 +1 @@ -{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/routes/health.ts"],"names":[],"mappings":";;AAAA,qCAAoD;AAEpD,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AAGxB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IAC9C,GAAG,CAAC,IAAI,CAAC;QACP,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,+BAA+B;QACxC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ;KAClC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAGH,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IACtD,IAAI,CAAC;QAEH,GAAG,CAAC,IAAI,CAAC;YACP,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,gCAAgC;YACzC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACnB,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,4BAA4B;YACrC,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;SAChE,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,kBAAe,MAAM,CAAC"} \ No newline at end of file +{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/routes/health.ts"],"names":[],"mappings":";;AAAA,qCAAoD;AAEpD,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AAGxB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IAC9C,GAAG,CAAC,IAAI,CAAC;QACP,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,yBAAyB;QAClC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ;KAClC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAGH,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IACtD,IAAI,CAAC;QAEH,GAAG,CAAC,IAAI,CAAC;YACP,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,gCAAgC;YACzC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACnB,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,4BAA4B;YACrC,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;SAChE,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,kBAAe,MAAM,CAAC"} \ No newline at end of file diff --git a/backend/dist/routes/images.d.ts.map b/backend/dist/routes/images.d.ts.map index 47bf143..fef4eba 100644 --- a/backend/dist/routes/images.d.ts.map +++ b/backend/dist/routes/images.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"images.d.ts","sourceRoot":"","sources":["../../src/routes/images.ts"],"names":[],"mappings":"AAOA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAqQxB,eAAe,MAAM,CAAC"} \ No newline at end of file +{"version":3,"file":"images.d.ts","sourceRoot":"","sources":["../../src/routes/images.ts"],"names":[],"mappings":"AAOA,QAAA,MAAM,MAAM,4CAAW,CAAC;AA0RxB,eAAe,MAAM,CAAC"} \ No newline at end of file diff --git a/backend/dist/routes/images.js b/backend/dist/routes/images.js index 74a394c..8d31ee1 100644 --- a/backend/dist/routes/images.js +++ b/backend/dist/routes/images.js @@ -11,13 +11,21 @@ const fs_1 = __importDefault(require("fs")); const config_1 = require("../config/config"); const router = (0, express_1.Router)(); const prisma = new client_1.PrismaClient(); +const getUploadsDir = (subPath) => { + const localUploadsDir = path_1.default.join(process.cwd(), 'uploads'); + const legacyUploadsDir = path_1.default.join(process.cwd(), '../../uploads'); + const baseDir = fs_1.default.existsSync(localUploadsDir) + ? localUploadsDir + : legacyUploadsDir; + return subPath ? path_1.default.join(baseDir, subPath) : baseDir; +}; const storage = multer_1.default.diskStorage({ destination: (req, file, cb) => { const recipeNumber = req.body.recipeNumber || req.params.recipeNumber; if (!recipeNumber) { return cb(new Error('Recipe number is required'), ''); } - const uploadDir = path_1.default.join(process.cwd(), '../../uploads', recipeNumber); + const uploadDir = getUploadsDir(recipeNumber); if (!fs_1.default.existsSync(uploadDir)) { fs_1.default.mkdirSync(uploadDir, { recursive: true }); } @@ -28,7 +36,7 @@ const storage = multer_1.default.diskStorage({ if (!recipeNumber) { return cb(new Error('Recipe number is required'), ''); } - const uploadDir = path_1.default.join(process.cwd(), '../../uploads', recipeNumber); + const uploadDir = getUploadsDir(recipeNumber); const existingFiles = fs_1.default.existsSync(uploadDir) ? fs_1.default.readdirSync(uploadDir).filter(f => f.match(new RegExp(`^${recipeNumber}_\\d+\\.jpg$`))) : []; @@ -171,7 +179,7 @@ router.get('/serve/:imagePath(*)', (req, res, next) => { }); } const cleanPath = imagePath.replace(/^uploads\//, ''); - const fullPath = path_1.default.join(process.cwd(), '../../uploads', cleanPath); + const fullPath = path_1.default.join(getUploadsDir(), cleanPath); console.log(`Serving image: ${imagePath} -> ${fullPath}`); if (!fs_1.default.existsSync(fullPath)) { console.log(`Image not found: ${fullPath}`); @@ -182,8 +190,13 @@ router.get('/serve/:imagePath(*)', (req, res, next) => { resolvedPath: fullPath }); } + const allowedOrigins = ['http://localhost:5173', 'http://localhost:3000']; + const origin = req.headers.origin; + const corsOrigin = process.env.CORS_ORIGIN === '*' + ? (origin || '*') + : (origin && allowedOrigins.includes(origin)) ? origin : 'http://localhost:3000'; res.set({ - 'Access-Control-Allow-Origin': 'http://localhost:5173', + 'Access-Control-Allow-Origin': corsOrigin, 'Access-Control-Allow-Credentials': 'true', 'Cache-Control': 'public, max-age=31536000', }); diff --git a/backend/dist/routes/images.js.map b/backend/dist/routes/images.js.map index ffaf549..78039e1 100644 --- a/backend/dist/routes/images.js.map +++ b/backend/dist/routes/images.js.map @@ -1 +1 @@ -{"version":3,"file":"images.js","sourceRoot":"","sources":["../../src/routes/images.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"images.js","sourceRoot":"","sources":["../../src/routes/images.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/backend/package-lock.json b/backend/package-lock.json index aecb76f..779cf21 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -39,6 +39,9 @@ "ts-node": "^10.9.2", "tsx": "^4.1.4", "typescript": "^5.2.2" + }, + "engines": { + "node": ">=20.19.0 <21 || >=22.12.0" } }, "node_modules/@babel/code-frame": { diff --git a/backend/package.json b/backend/package.json index 5d6d007..7958c58 100644 --- a/backend/package.json +++ b/backend/package.json @@ -55,4 +55,7 @@ ], "author": "Recipe Admin", "license": "MIT" + ,"engines": { + "node": ">=20.19.0 <21 || >=22.12.0" + } } diff --git a/backend/src/app.ts b/backend/src/app.ts index 4039119..c25054b 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -30,32 +30,37 @@ const limiter = rateLimit({ }); app.use(limiter); -// CORS configuration - Allow both development and production origins -const allowedOrigins = [ - 'http://localhost:5173', // Vite dev server - 'http://localhost:3000', // Docker frontend - config.cors.origin // Environment configured origin -].filter(Boolean); +// CORS configuration - support comma separated origins in CORS_ORIGIN +// NOTE: In docker-compose we temporarily set CORS_ORIGIN="*" for troubleshooting. +// Narrow this down for production: e.g. CORS_ORIGIN="http://esprimo:3000,http://localhost:3000". +let allowedOrigins: string[] = []; +if (config.cors.origin === '*') { + allowedOrigins = ['*']; +} else if (config.cors.origin.includes(',')) { + allowedOrigins = config.cors.origin.split(',').map(o => o.trim()).filter(Boolean); +} else { + allowedOrigins = [config.cors.origin]; +} -// Add local network origins if CORS_ORIGIN is "*" (for local network access) -const corsConfig = config.cors.origin === '*' - ? { - origin: true, // Allow all origins for local network - credentials: true, - } - : { - origin: allowedOrigins, - credentials: true, - }; +// Always add defaults if not already present +['http://localhost:5173','http://localhost:3000'].forEach(def => { + if (!allowedOrigins.includes(def) && !allowedOrigins.includes('*')) allowedOrigins.push(def); +}); -app.use(cors(corsConfig)); +app.use(cors({ + origin: (origin, callback) => { + if (!origin) return callback(null, true); // non-browser (curl, server-side) + if (allowedOrigins.includes('*') || allowedOrigins.includes(origin)) return callback(null, true); + return callback(new Error(`CORS blocked for origin ${origin}`)); + }, + credentials: true, +})); // Additional CORS headers for all requests app.use((req, res, next) => { const origin = req.headers.origin; - if (config.cors.origin === '*') { - // Allow all origins for local network access + if (allowedOrigins.includes('*')) { res.header('Access-Control-Allow-Origin', origin || '*'); } else if (origin && allowedOrigins.includes(origin)) { res.header('Access-Control-Allow-Origin', origin); @@ -107,8 +112,12 @@ app.get('/serve/*', (req, res, next) => { } // Set headers for images + const requestOrigin = req.headers.origin as string | undefined; + const chosenOrigin = allowedOrigins.includes('*') + ? (requestOrigin || '*') + : (requestOrigin && allowedOrigins.includes(requestOrigin) ? requestOrigin : allowedOrigins[0] || 'http://localhost:3000'); res.set({ - 'Access-Control-Allow-Origin': 'http://localhost:5173', + 'Access-Control-Allow-Origin': chosenOrigin, 'Access-Control-Allow-Credentials': 'true', 'Cache-Control': 'public, max-age=31536000', }); diff --git a/docker-compose.yml b/docker-compose.yml index 2b94826..5f1a999 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,6 +4,8 @@ services: image: mysql:8.0 container_name: rezepte_mysql restart: always + profiles: + - default environment: MYSQL_ROOT_PASSWORD: rezepte123 MYSQL_DATABASE: rezepte @@ -22,6 +24,8 @@ services: build: . container_name: rezepte_app restart: always + profiles: + - legacy ports: - "8082:80" volumes: @@ -41,6 +45,8 @@ services: image: phpmyadmin:latest container_name: rezepte_phpmyadmin restart: always + profiles: + - admin ports: - "8083:80" environment: @@ -53,8 +59,55 @@ services: networks: - rezepte_network + # Node.js Backend API + backend: + build: + context: ./backend + dockerfile: Dockerfile + container_name: rezepte-backend + profiles: + - default + environment: + NODE_ENV: production + PORT: 3001 + DATABASE_URL: mysql://rezepte_user:rezepte_pass@mysql:3306/rezepte + JWT_SECRET: your-super-secret-jwt-key-change-in-production + UPLOAD_PATH: /app/uploads + MAX_FILE_SIZE: 5242880 + # CORS_ORIGIN: Restrict in production (example: http://esprimo:3000,http://localhost:3000) + CORS_ORIGIN: "*" + ports: + - "3001:3001" + volumes: + - uploads_data:/app/uploads + - ./uploads:/app/legacy-uploads:ro + networks: + - rezepte_network + depends_on: + - mysql + restart: unless-stopped + + # Frontend (React + Vite build served by nginx) + frontend: + build: + context: ./frontend + dockerfile: Dockerfile + args: + VITE_API_URL: http://localhost:3001/api + container_name: rezepte-frontend + profiles: + - default + ports: + - "3000:80" + networks: + - rezepte_network + depends_on: + - backend + restart: unless-stopped + volumes: mysql_data: + uploads_data: networks: rezepte_network: diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 4db3db2..2e14c02 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,5 +1,5 @@ # Frontend Dockerfile -FROM node:18-alpine AS builder +FROM node:22.12.0-alpine AS builder # Set working directory WORKDIR /app diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 126ec6c..a8a3459 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -26,6 +26,9 @@ "typescript": "~5.8.3", "typescript-eslint": "^8.43.0", "vite": "^7.1.6" + }, + "engines": { + "node": ">=20.19.0 <21 || >=22.12.0" } }, "node_modules/@babel/code-frame": { diff --git a/frontend/package.json b/frontend/package.json index 82ac056..b932934 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,6 +3,9 @@ "private": true, "version": "0.0.0", "type": "module", + "engines": { + "node": ">=20.19.0 <21 || >=22.12.0" + }, "scripts": { "dev": "vite", "build": "tsc -b && vite build", diff --git a/frontend/src/components/RecipeEdit.css b/frontend/src/components/RecipeEdit.css index 98a3ddf..d147fee 100644 --- a/frontend/src/components/RecipeEdit.css +++ b/frontend/src/components/RecipeEdit.css @@ -140,6 +140,15 @@ font-family: inherit; transition: all 0.3s ease; background: white; + color: #333; /* Ensure visible text color (fix for invisible typed characters) */ + caret-color: #333; +} + +/* Placeholder visibility */ +.form-group input::placeholder, +.form-group textarea::placeholder { + color: #888; + opacity: 1; /* Override browser lower opacity */ } .form-group input:focus, diff --git a/frontend/src/index.css b/frontend/src/index.css index 08a3ac9..1aa5642 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -23,11 +23,12 @@ a:hover { } body { + /* Removed global flex centering (display:flex + place-items:center) because it created a layout + that could interfere with stacking/focus of interactive form elements ("Neues Rezept" Eingabeproblem). */ margin: 0; - display: flex; - place-items: center; min-width: 320px; min-height: 100vh; + /* Let the app container (see App.css .App) handle layout instead. */ } h1 {