build: Docker-Betrieb und Standalone-Betrieb gleichwertig unterstuetzen
Dieselbe Codebasis laeuft nativ auf dem Rechner oder komplett im Container. docker-compose.yml mit Profilen statt mehrerer Dateien: - "db" laeuft immer -> docker compose up -d db, App dann lokal per npm - --profile full -> zusaetzlich der App-Container - --profile tools -> Adminer als Datenbankoberflaeche Dockerfile als Multi-Stage-Build auf dem Next-Standalone-Output. In die Laufzeitschicht wandern zusaetzlich Prisma-CLI, Engines und Schema, damit der Entrypoint beim Start "migrate deploy" ausfuehren kann. Das Alpine-Image bekommt openssl fuer die Prisma-Engines, der Client wird zusaetzlich fuer linux-musl-openssl-3.0.x erzeugt. Der Container laeuft als unprivilegierter Benutzer und meldet seinen Zustand ueber /api/health. Der Entrypoint wartet in einer Schleife auf die Datenbank, ergaenzend zum pg_isready-Healthcheck und der depends_on-Bedingung. scripts/setup.mjs legt die .env aus der Vorlage an und erzeugt dabei ein zufaelliges APP_SECRET, damit die Tokens nicht mit dem Standardschluessel verschluesselt werden. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Nebula – Ersteinrichtung.
|
||||
*
|
||||
* Legt eine .env auf Basis von .env.example an und erzeugt dabei einen
|
||||
* zufaelligen APP_SECRET. Vorhandene .env-Dateien werden nicht angefasst.
|
||||
*
|
||||
* node scripts/setup.mjs bzw. npm run setup
|
||||
*/
|
||||
|
||||
import { randomBytes } from "node:crypto";
|
||||
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const envPath = join(root, ".env");
|
||||
const examplePath = join(root, ".env.example");
|
||||
|
||||
const c = {
|
||||
reset: "[0m",
|
||||
dim: "[2m",
|
||||
green: "[32m",
|
||||
yellow: "[33m",
|
||||
cyan: "[36m",
|
||||
};
|
||||
|
||||
function log(message) {
|
||||
console.log(message);
|
||||
}
|
||||
|
||||
if (!existsSync(examplePath)) {
|
||||
console.error(`${c.yellow}.env.example nicht gefunden – abgebrochen.${c.reset}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (existsSync(envPath)) {
|
||||
log(`${c.yellow}·${c.reset} .env existiert bereits – sie wird nicht ueberschrieben.`);
|
||||
} else {
|
||||
const secret = randomBytes(32).toString("base64");
|
||||
const content = readFileSync(examplePath, "utf8").replace(
|
||||
/^APP_SECRET=.*$/m,
|
||||
`APP_SECRET="${secret}"`,
|
||||
);
|
||||
writeFileSync(envPath, content, "utf8");
|
||||
log(`${c.green}✓${c.reset} .env angelegt (APP_SECRET wurde zufaellig erzeugt).`);
|
||||
}
|
||||
|
||||
log("");
|
||||
log(`${c.cyan}Naechste Schritte${c.reset}`);
|
||||
log(`${c.dim}─────────────────────────────────────────────${c.reset}`);
|
||||
log("Standalone (App lokal, Datenbank im Container):");
|
||||
log(` ${c.dim}1.${c.reset} docker compose up -d db`);
|
||||
log(` ${c.dim}2.${c.reset} npm install`);
|
||||
log(` ${c.dim}3.${c.reset} npm run db:migrate`);
|
||||
log(` ${c.dim}4.${c.reset} npm run db:seed ${c.dim}(optional, Beispieldaten)${c.reset}`);
|
||||
log(` ${c.dim}5.${c.reset} npm run dev ${c.dim}→ http://localhost:3000${c.reset}`);
|
||||
log("");
|
||||
log("Alles in Docker:");
|
||||
log(` ${c.dim}1.${c.reset} docker compose --profile full up -d --build`);
|
||||
log(` ${c.dim}2.${c.reset} ${c.dim}→ http://localhost:3000${c.reset}`);
|
||||
log("");
|
||||
log("Eigene, bereits laufende PostgreSQL:");
|
||||
log(` DATABASE_URL in der .env anpassen, dann npm run db:migrate`);
|
||||
log("");
|
||||
Reference in New Issue
Block a user