feat: add Docker support with demo mode and database reset functionality

This commit is contained in:
Paul Schoeneck committed 2026-11-03 08:50:48 +01:00
1 parent 75af38a4b6
commit 373b9278d1
12 files changed
+248 -5

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
#!/bin/sh
# SPDX-FileCopyrightText: 2026 Paul Schoeneck
#
# SPDX-License-Identifier: AGPL-3.0-only AND LicenseRef-KIBU-Additional-Terms
set -eu
node node_modules/tsx/dist/cli.mjs scripts/prepare-container.ts
exec node node_modules/next/dist/bin/next start --hostname 0.0.0.0 --port "${PORT:-3000}"
+45
View File
@@ -0,0 +1,45 @@
// SPDX-FileCopyrightText: 2026 Paul Schoeneck
//
// SPDX-License-Identifier: AGPL-3.0-only AND LicenseRef-KIBU-Additional-Terms
import { spawnSync } from "node:child_process";
import { createRequire } from "node:module";
import { fileURLToPath } from "node:url";
import { demoLogin, isDemoDatabase } from "../src/lib/demo";
function prepare() {
if (!process.env.DATABASE_URL) throw new Error("DATABASE_URL fehlt.");
if (process.env.DEMO_MODE && !["true", "false"].includes(process.env.DEMO_MODE)) {
throw new Error("DEMO_MODE muss true oder false sein.");
}
const demo = demoLogin();
if (demo) {
const target = new URL(process.env.DATABASE_URL);
if (!isDemoDatabase(target) || !["postgres:", "postgresql:"].includes(target.protocol)) {
throw new Error("Demo-Start erfordert DEMO_RESET_ON_START=true und die separate Datenbank demo-db/kibu_demo. Nichts wurde veraendert.");
}
process.env.BOOTSTRAP_EMAIL = demo.email;
process.env.BOOTSTRAP_PASSWORD = demo.password;
console.log("DEMOMODUS: Gemeinsamer oeffentlicher Zugang; alle Demodaten werden bei jedem App-Start ersetzt.");
} else if (process.env.DEMO_RESET_ON_START === "true") {
throw new Error("DEMO_RESET_ON_START erfordert DEMO_MODE=true.");
}
const tsx = createRequire(import.meta.url).resolve("tsx/cli");
const commands = demo
? [["setup.ts"], ["reset-instance.ts", "demo", "--confirm-reset"]]
: [["setup.ts"]];
for (const [script, ...args] of commands) {
const result = spawnSync(process.execPath, [tsx, fileURLToPath(new URL(script, import.meta.url)), ...args], {
env: process.env, stdio: "inherit",
});
if (result.error) throw result.error;
if (result.status !== 0) throw new Error(`${script} fehlgeschlagen; App wird nicht gestartet.`);
}
}
try {
prepare();
} catch (error) {
console.error("Container-Vorbereitung fehlgeschlagen:", error);
process.exitCode = 1;
}
+2 -1
View File
@@ -7,6 +7,7 @@ import { spawnSync } from "node:child_process";
import { createRequire } from "node:module";
import { fileURLToPath } from "node:url";
import { db } from "../src/lib/db";
import { isDemoDatabase } from "../src/lib/demo";
async function reset() {
const [mode, confirmation, ...extra] = process.argv.slice(2);
@@ -16,7 +17,7 @@ async function reset() {
if (!process.env.DATABASE_URL) throw new Error("DATABASE_URL fehlt. Zuerst npm run configure ausfuehren.");
const target = new URL(process.env.DATABASE_URL);
if (!["postgres:", "postgresql:"].includes(target.protocol)
|| !["localhost", "127.0.0.1", "[::1]"].includes(target.hostname)
|| (!["localhost", "127.0.0.1", "[::1]"].includes(target.hostname) && !isDemoDatabase(target))
|| !target.pathname.slice(1) || ["/postgres", "/template0", "/template1"].includes(target.pathname)) {
throw new Error("Reset nur fuer eine ausdruecklich konfigurierte lokale Anwendungsdatenbank erlaubt.");
}