Files
RAPPORT-HOST/server/env.js
T
karim 6290475ea3 Initial: RAPPORT-HOST Iteration 1 (proprietär)
Kommerzielle Hosting-/Abo-Plattform für Rapport-Instanzen.

- React-Frontend (Vite/JSX): Landing, Register, Login, Plans, Dashboard
- Node/Express-Backend: Auth (bcrypt+JWT), Stripe-Billing, Provisioning
- HOST-Postgres-Schema: accounts, subscriptions, instances
- Provisioning-Interface + Modell-A-Adapter (Studio im geteilten Stack)
- MOCK-Modus: voller End-to-End-Flow ohne Stripe/Rapport-Stack testbar
- Idempotentes Fulfillment (Upsert auf stripe_subscription_id)
- docker-compose für lokale host-db; identisch auf Hetzner deploybar

E2E lokal verifiziert: Register -> Checkout(mock) -> Instanz -> Idempotenz.

Lizenz: proprietär (kein AGPL-Code eingebunden, nur Netzwerk-API zur Familie).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 15:37:33 +02:00

57 lines
2.2 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:5273").replace(/\/+$/, ""),
jwtSecret: e.JWT_SECRET || "dev-insecure-secret-change-me",
databaseUrl: e.DATABASE_URL || "postgres://rapport_host:rapport_host@localhost:55432/rapport_host",
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.
export const stripeEnabled = !!env.stripe.secretKey && env.stripe.secretKey.startsWith("sk_");
export const provisioningMock = !env.rapport.apiUrl || !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.");