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>
54 lines
2.5 KiB
JavaScript
54 lines
2.5 KiB
JavaScript
// RAPPORT-HOST Backend-Entry.
|
|
import express from "express";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { env } from "./env.js";
|
|
import { authRouter } from "./routes/auth.js";
|
|
import { billingRouter } from "./routes/billing.js";
|
|
import { accountRouter } from "./routes/account.js";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const app = express();
|
|
|
|
// WICHTIG: Der Stripe-Webhook braucht den ROHEN Body für die Signaturprüfung.
|
|
// express.raw greift nur für diese Route und setzt req._body, sodass das danach
|
|
// registrierte express.json() den Webhook-Body NICHT erneut parst.
|
|
app.use("/api/billing/webhook", express.raw({ type: "application/json" }));
|
|
app.use(express.json());
|
|
|
|
app.get("/api/health", (_req, res) => res.json({ ok: true, service: "rapport-host" }));
|
|
app.use("/api/auth", authRouter);
|
|
app.use("/api/billing", billingRouter);
|
|
app.use("/api/account", accountRouter);
|
|
|
|
// ── Statische Auslieferung der RAPPORT-WEBSITE (Hugo-Build) ──────────────────
|
|
// Die komplette Frontend-Oberfläche (Marketing + Hosting + Login/Konto als
|
|
// Vanilla-JS-Seiten) kommt aus dem AGPL-Repo RAPPORT-WEBSITE. Dieses Backend
|
|
// liefert dessen gebautes public/ aus und stellt darunter /api bereit.
|
|
// Saubere Trennung: die Website enthält keinen Backend-Code, nur fetch('/api').
|
|
// Pfad per WEBSITE_PUBLIC_DIR überschreibbar (Default: Schwester-Repo).
|
|
const websitePublic = env.websitePublicDir;
|
|
|
|
app.use(express.static(websitePublic));
|
|
app.get("*", (req, res, next) => {
|
|
if (req.path.startsWith("/api/")) return next();
|
|
// Hugo erzeugt pro Seite eine eigene index.html → Clean-URLs funktionieren
|
|
// direkt über express.static. Unbekannte Pfade → 404-Seite.
|
|
res.status(404).sendFile(path.join(websitePublic, "404.html"), (err) => err && next());
|
|
});
|
|
|
|
// Express-Fehlerhandler: fängt synchron geworfene Fehler aus Routen → 500
|
|
// statt stiller Empty-Reply.
|
|
app.use((err, _req, res, _next) => {
|
|
console.error("Unbehandelter Routen-Fehler:", err);
|
|
if (!res.headersSent) res.status(500).json({ error: "Interner Fehler." });
|
|
});
|
|
|
|
// Letzte Verteidigungslinie: ein einzelner async-Fehler darf den Prozess nicht
|
|
// killen (im Dev-Test sonst "connection refused" für alle Folge-Requests).
|
|
process.on("unhandledRejection", (reason) => console.error("unhandledRejection:", reason));
|
|
|
|
app.listen(env.port, () => {
|
|
console.log(`RAPPORT-HOST API läuft auf :${env.port} (Base: ${env.publicBaseUrl})`);
|
|
});
|