Files
florian.wildeandClaude Opus 5 c781c5d19d 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>
2026-07-25 19:35:04 +02:00

66 lines
2.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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: "",
dim: "",
green: "",
yellow: "",
cyan: "",
};
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("");