13173dddc5
Das Frontend (Marketing + Login/Konto) ist in RAPPORT-WEBSITE umgezogen (Hugo + Vanilla-JS). RAPPORT-HOST liefert dessen gebautes public/ statisch aus und stellt /api bereit. - server/index.js: serviert RAPPORT-WEBSITE/public + /api (eine Origin) - server/env.js: websitePublicDir (WEBSITE_PUBLIC_DIR, Default Schwester-Repo); PUBLIC_BASE_URL Default auf einheitliche Origin :8787 - billing.js: Checkout-Redirects auf /konto/ bzw. /hosting-preise/ - entfernt: src/ (React), marketing/ (Hugo-Kopie), index.html, vite.config.js - package.json: nur noch server/migrate/build:website-Scripts E2E verifiziert: /, /hosting/, /login/, /konto/, /js + Font = 200; register→checkout(mock)→Instanz; Redirect → /konto/?provisioned=1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
64 lines
2.7 KiB
JavaScript
64 lines
2.7 KiB
JavaScript
// Zentrales Laden + Validieren der Umgebungsvariablen.
|
|
// Liest .env (einfacher Parser, keine Dependency) und fällt sonst auf
|
|
// process.env zurück — so läuft es lokal mit Datei und auf Hetzner mit
|
|
// echten Env-Vars, ohne Code-Änderung.
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const envPath = path.resolve(__dirname, "..", ".env");
|
|
|
|
if (fs.existsSync(envPath)) {
|
|
for (const line of fs.readFileSync(envPath, "utf8").split("\n")) {
|
|
const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)\s*$/);
|
|
if (!m) continue;
|
|
const key = m[1];
|
|
let val = m[2].replace(/^["']|["']$/g, "");
|
|
if (process.env[key] === undefined) process.env[key] = val;
|
|
}
|
|
}
|
|
|
|
const e = process.env;
|
|
|
|
export const env = {
|
|
port: parseInt(e.PORT || "8787", 10),
|
|
publicBaseUrl: (e.PUBLIC_BASE_URL || "http://localhost:8787").replace(/\/+$/, ""),
|
|
jwtSecret: e.JWT_SECRET || "dev-insecure-secret-change-me",
|
|
databaseUrl: e.DATABASE_URL || "postgres://rapport_host:rapport_host@localhost:55432/rapport_host",
|
|
// Gebautes public/ der RAPPORT-WEBSITE (Hugo). Default: Schwester-Repo lokal.
|
|
websitePublicDir: e.WEBSITE_PUBLIC_DIR ||
|
|
new URL("../../RAPPORT-WEBSITE/public", import.meta.url).pathname,
|
|
|
|
stripe: {
|
|
secretKey: e.STRIPE_SECRET_KEY || "",
|
|
webhookSecret: e.STRIPE_WEBHOOK_SECRET || "",
|
|
prices: {
|
|
solo: e.STRIPE_PRICE_SOLO || "",
|
|
studio: e.STRIPE_PRICE_STUDIO || "",
|
|
business: e.STRIPE_PRICE_BUSINESS || "",
|
|
},
|
|
},
|
|
|
|
rapport: {
|
|
apiUrl: e.RAPPORT_API_URL || "",
|
|
serviceKey: e.RAPPORT_SERVICE_KEY || "",
|
|
instanceUrlTemplate: e.RAPPORT_INSTANCE_URL_TEMPLATE || "http://localhost:8080/?studio={slug}",
|
|
},
|
|
};
|
|
|
|
// MOCK-Modus: ohne echte Stripe-/Rapport-Keys läuft alles lokal simuliert,
|
|
// damit der End-to-End-Flow ohne externe Dienste testbar ist.
|
|
// WICHTIG: Platzhalter-Werte aus .env.example (…CHANGE-ME) zählen als NICHT
|
|
// gesetzt — sonst würde ein sk_test_CHANGE-ME als echter Key durchgehen und
|
|
// echte Stripe-Calls mit ungültigem Key abfeuern (401 → Crash).
|
|
const isPlaceholder = (v) => !v || v.includes("CHANGE-ME");
|
|
export const stripeEnabled = !isPlaceholder(env.stripe.secretKey) && env.stripe.secretKey.startsWith("sk_");
|
|
export const provisioningMock = isPlaceholder(env.rapport.apiUrl) || isPlaceholder(env.rapport.serviceKey);
|
|
|
|
if (env.jwtSecret === "dev-insecure-secret-change-me") {
|
|
console.warn("⚠ JWT_SECRET nicht gesetzt — unsicheres Dev-Secret in Verwendung.");
|
|
}
|
|
if (!stripeEnabled) console.warn("⚠ STRIPE_SECRET_KEY fehlt — Billing läuft im MOCK-Modus.");
|
|
if (provisioningMock) console.warn("⚠ RAPPORT_API_URL/SERVICE_KEY fehlen — Provisioning läuft im MOCK-Modus.");
|