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>
This commit is contained in:
2026-05-30 15:35:47 +02:00
commit 6290475ea3
34 changed files with 4115 additions and 0 deletions
+108
View File
@@ -0,0 +1,108 @@
# 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