# RAPPORT-HOST — Architektur ## 1 · Mentales Modell RAPPORT-HOST ist die **kommerzielle Schicht** über der Rapport-Familie. Es verkauft und provisioniert Rapport-Instanzen, berührt aber die Tenant-Daten der Kunden nicht direkt — es spricht mit dem Rapport-Stack nur über dessen API. ``` Browser ──/api──▶ Node/Express (server/) ──▶ HOST-Postgres (Konten/Abos/Instanzen) │ │ │ ├──▶ Stripe (Checkout + Webhook) │ └──▶ Rapport-Stack-API (Provisioning, service_role) └── React (src/) ``` ## 2 · Lizenz-Abgrenzung (wichtig) RAPPORT-HOST ist **proprietär**. Die übrigen Repos sind **AGPL-3.0**. Damit die AGPL nicht auf HOST „überspringt", gilt eine harte Regel: **kein AGPL-Code wird importiert oder kopiert.** Die Kommunikation läuft ausschließlich über Netzwerk-APIs (HTTP/REST). So bleibt HOST ein eigenständiges Werk. ## 3 · Verzeichnis-Karte ``` RAPPORT-HOST/ ├── src/ React-Frontend (JSX, kein TS — wie APP) │ ├── App.jsx Mini-Pfad-Router │ ├── api.js fetch-Client + Token-Handling │ └── views/ Landing, Register, Login, Plans, Dashboard ├── server/ Node/Express-Backend │ ├── index.js Entry; Webhook-Raw-Body vor json() │ ├── env.js Env laden + MOCK-Flags │ ├── db.js pg-Pool (HOST-DB) │ ├── auth.js bcrypt + JWT + requireAuth │ ├── plans.js Plan-Definitionen (Preise, Limits, Stripe-Price) │ ├── stripe.js Stripe-Client (null im Mock) │ ├── routes/ auth · billing · account │ ├── provisioning/ index (Interface) + studio-adapter (Modell A) │ ├── migrations/0001_init.sql HOST-Schema │ └── migrate.js Migrations-Runner ├── docker-compose.yml host-db (+ app für Prod, auskommentiert) └── .env.example ``` ## 4 · Datenmodell (HOST-DB) - **accounts** — zahlende Büros (Email + bcrypt-Hash). NICHT die Endnutzer. - **subscriptions** — Plan, Status, Stripe-IDs, Periodenende. `stripe_subscription_id` ist der Idempotenz-Key fürs Fulfillment. - **instances** — provisionierte Rapport-Instanzen (Modell A: `studio_id` + `studio_slug` im geteilten Stack, `instance_url`, Status). Bewusst **getrennt** von der Rapport-/Kunden-Datenbank. ## 5 · Zahlungs-/Provisioning-Flow ``` Plan wählen ─▶ POST /api/billing/checkout │ Stripe? ──┤── nein (MOCK): fulfill() sofort ─▶ Erfolgs-URL │── ja: Stripe-Checkout-Session ─▶ Redirect zu Stripe │ Stripe ─POST /api/billing/webhook (checkout.session.completed) │ fulfill() ├─ subscriptions upsert └─ provision() ─▶ instances insert ``` `fulfill()` ist idempotent (Upsert auf `stripe_subscription_id`, Instanz nur wenn noch keine existiert) — Stripe kann Webhooks mehrfach senden. ## 6 · Provisioning-Modelle Hinter dem Interface `provisioning/index.js`: - **Modell A (jetzt, `studio-adapter.js`)**: ein isoliertes Studio im geteilten Rapport-Stack. Vermarktet als „eigene Instanz", technisch RLS-Mandant. Millisekunden, solo-betreibbar. - Echtes Provisioning braucht im Rapport-Schema noch ein server-seitiges RPC `create_studio_for_user(p_user_id, p_name, p_slug)` (da `create_studio_with_admin` auf `auth.uid()` baut). Bis dahin: MOCK-Modus. - **Modell B (später)**: eigener Container/Stack pro Kunde (volle Isolation, „Dedicated"-Tier). Neuer Adapter mit identischer Signatur — hier käme `SERVER-PROXMOX-LXC` als Provisioning-Backend ins Spiel. ## 7 · MOCK-Modus Zwei unabhängige Schalter (in `env.js`): - `stripeEnabled` — false ohne `sk_…`-Key ⇒ Checkout schaltet sofort frei. - `provisioningMock` — true ohne `RAPPORT_API_URL`/`SERVICE_KEY` ⇒ Instanz wird nur als DB-Eintrag mit synthetischer `studioId` simuliert. So ist der komplette Flow lokal testbar, bevor Stripe-Account und Rapport-Stack stehen. In Produktion sind beide Schalter aus. ## 8 · Roadmap - [ ] Iteration 1: Register/Login, Stripe-Checkout, Webhook, Dashboard (MOCK-fähig) - [ ] `create_studio_for_user`-RPC im Rapport-Schema → echtes Modell-A-Provisioning - [ ] Stripe Customer-Portal (Abo verwalten/kündigen) - [ ] Super-Admin (Kundenübersicht, Umsatz, sperren) - [ ] QR-Rechnung für Geschäftskunden - [ ] Modell B: Container-Provisioning-Adapter - [ ] Deploy auf Hetzner