Files
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

4.9 KiB

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