.env: DATABASE_URL aus DB_*-Komponenten zusammenbauen (kein Doppel-Pflegen)
Bisher: DATABASE_URL und die DB_USER/PASSWORD/etc. mussten parallel
gepflegt werden – Werte konnten auseinanderlaufen.
Fix:
- dotenv-expand installiert (löst ${VAR}-Substitution in .env)
- .env.example: DATABASE_URL=mysql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}
- DB_HOST als neue Variable (Default localhost; Container überschreibt zu "db")
- Backend index.ts: dotenvExpand.expand() statt nur dotenv.config()
- Plus Fallback im Code: wenn DATABASE_URL leer aber DB_*-Werte vorhanden,
baut der Backend-Code die URL selbst zusammen (encodeURIComponent für
Sonderzeichen im Passwort).
docker-compose.yml setzt DATABASE_URL weiterhin explizit (Container-
internal Hostname "db") und überschreibt damit die Dev-Variante.
Live-verifiziert:
- Dev-Modus: mysql://root:***@localhost:3306/opencrm (substituiert)
- Container: mysql://root:***@db:3306/opencrm (compose explizit)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+6
-3
@@ -18,14 +18,17 @@ FACTORY_DEFAULTS_DIR=./data/factory-defaults
|
|||||||
BACKUPS_DIR=./data/backups
|
BACKUPS_DIR=./data/backups
|
||||||
|
|
||||||
# ============== DATENBANK ==============
|
# ============== DATENBANK ==============
|
||||||
|
DB_HOST=localhost # Im Container überschreibt docker-compose das auf "db"
|
||||||
DB_NAME=opencrm
|
DB_NAME=opencrm
|
||||||
DB_USER=opencrm
|
DB_USER=opencrm
|
||||||
DB_PASSWORD=change-this-password
|
DB_PASSWORD=change-this-password
|
||||||
DB_ROOT_PASSWORD=change-this-root-password
|
DB_ROOT_PASSWORD=change-this-root-password
|
||||||
|
|
||||||
# Connection-String fürs Backend (im Container = Service-Name `db`)
|
# Connection-String wird aus den DB_*-Komponenten zusammengebaut (dotenv-expand).
|
||||||
# Im Dev-Modus (npm run dev) lokal: localhost:DB_PORT
|
# Manuell überschreiben nur wenn Sonderfälle (z.B. extra Query-Parameter).
|
||||||
DATABASE_URL=mysql://root:change-this-root-password@localhost:3306/opencrm
|
# Hinweis: für lokales Dev mit MariaDB im Container nutze DB_HOST=localhost,
|
||||||
|
# weil docker-compose den DB-Port auf 127.0.0.1:DB_PORT mappt.
|
||||||
|
DATABASE_URL=mysql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}
|
||||||
|
|
||||||
# ============== SECURITY ==============
|
# ============== SECURITY ==============
|
||||||
# JWT-Secret: min. 32 Zeichen. Generieren: openssl rand -hex 64
|
# JWT-Secret: min. 32 Zeichen. Generieren: openssl rand -hex 64
|
||||||
|
|||||||
Generated
+30
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "opencrm-backend",
|
"name": "opencrm-backend",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "opencrm-backend",
|
"name": "opencrm-backend",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "^5.22.0",
|
"@prisma/client": "^5.22.0",
|
||||||
"adm-zip": "^0.5.16",
|
"adm-zip": "^0.5.16",
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
|
"dotenv-expand": "^13.0.0",
|
||||||
"express": "^4.21.1",
|
"express": "^4.21.1",
|
||||||
"express-rate-limit": "^8.4.0",
|
"express-rate-limit": "^8.4.0",
|
||||||
"express-validator": "^7.2.0",
|
"express-validator": "^7.2.0",
|
||||||
@@ -1463,6 +1464,33 @@
|
|||||||
"url": "https://dotenvx.com"
|
"url": "https://dotenvx.com"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dotenv-expand": {
|
||||||
|
"version": "13.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-13.0.0.tgz",
|
||||||
|
"integrity": "sha512-aBfBS8eYIeXmpHI9ThIlA7/WLq+SLt18iXUZhb52rW89QLKQFoIpPG1bPeewoPZsTyjSSO3T7234FBVUM1V2rA==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"dotenv": "^17.4.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://dotenvx.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dotenv-expand/node_modules/dotenv": {
|
||||||
|
"version": "17.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz",
|
||||||
|
"integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://dotenvx.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dunder-proto": {
|
"node_modules/dunder-proto": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
|
"dotenv-expand": "^13.0.0",
|
||||||
"express": "^4.21.1",
|
"express": "^4.21.1",
|
||||||
"express-rate-limit": "^8.4.0",
|
"express-rate-limit": "^8.4.0",
|
||||||
"express-validator": "^7.2.0",
|
"express-validator": "^7.2.0",
|
||||||
|
|||||||
+18
-3
@@ -3,6 +3,7 @@ import cors from 'cors';
|
|||||||
import helmet from 'helmet';
|
import helmet from 'helmet';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
|
import dotenvExpand from 'dotenv-expand';
|
||||||
|
|
||||||
// .env-Dateien laden – Root-.env hat Priorität (zentrale Konfiguration für
|
// .env-Dateien laden – Root-.env hat Priorität (zentrale Konfiguration für
|
||||||
// Dev + Docker), backend/.env als Legacy-Fallback. Im Container sind
|
// Dev + Docker), backend/.env als Legacy-Fallback. Im Container sind
|
||||||
@@ -10,9 +11,23 @@ import dotenv from 'dotenv';
|
|||||||
// existierende process.env-Werte nicht.
|
// existierende process.env-Werte nicht.
|
||||||
// __dirname zeigt auf src/ (dev via tsx) oder dist/ (build). In beiden Fällen
|
// __dirname zeigt auf src/ (dev via tsx) oder dist/ (build). In beiden Fällen
|
||||||
// liegt Root /.env zwei Ebenen darüber.
|
// liegt Root /.env zwei Ebenen darüber.
|
||||||
dotenv.config({ path: path.resolve(__dirname, '../../.env') }); // Root /.env
|
//
|
||||||
dotenv.config({ path: path.resolve(__dirname, '../.env') }); // backend/.env (Fallback)
|
// dotenvExpand löst ${VAR}-Substitution auf, sodass z.B.
|
||||||
dotenv.config(); // cwd-relativ (Container etc.)
|
// DATABASE_URL=mysql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}
|
||||||
|
// dynamisch aus den Komponenten zusammengebaut wird (kein Doppel-Pflegen).
|
||||||
|
dotenvExpand.expand(dotenv.config({ path: path.resolve(__dirname, '../../.env') }));
|
||||||
|
dotenvExpand.expand(dotenv.config({ path: path.resolve(__dirname, '../.env') }));
|
||||||
|
dotenvExpand.expand(dotenv.config());
|
||||||
|
|
||||||
|
// Fallback: wenn DATABASE_URL nicht direkt gesetzt ist (oder Substitution
|
||||||
|
// nicht funktioniert hat), aus den DB_*-Komponenten zusammenbauen.
|
||||||
|
if (!process.env.DATABASE_URL && process.env.DB_USER && process.env.DB_PASSWORD && process.env.DB_NAME) {
|
||||||
|
const u = encodeURIComponent(process.env.DB_USER);
|
||||||
|
const p = encodeURIComponent(process.env.DB_PASSWORD);
|
||||||
|
const h = process.env.DB_HOST || 'localhost';
|
||||||
|
const port = process.env.DB_PORT || '3306';
|
||||||
|
process.env.DATABASE_URL = `mysql://${u}:${p}@${h}:${port}/${process.env.DB_NAME}`;
|
||||||
|
}
|
||||||
|
|
||||||
import authRoutes from './routes/auth.routes.js';
|
import authRoutes from './routes/auth.routes.js';
|
||||||
import customerRoutes from './routes/customer.routes.js';
|
import customerRoutes from './routes/customer.routes.js';
|
||||||
|
|||||||
Reference in New Issue
Block a user