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
+65
View File
@@ -0,0 +1,65 @@
:root {
--bg: #ebe7e1;
--card: #fdfcfa;
--ink: #1a1a18;
--muted: #8c8880;
--line: #ddd8d0;
--accent: #9a7858;
--accent-ink: #f0ede8;
}
* { box-sizing: border-box; }
body {
margin: 0;
background: var(--bg);
color: var(--ink);
font-family: "DM Mono", "Courier New", monospace;
}
a { color: var(--accent); }
.wrap { max-width: 1000px; margin: 0 auto; padding: 0 20px; }
.center { min-height: 100vh; display: flex; align-items: center; justify-content: center; }
.brand { font-family: "Krungthep", "Archivo Black", sans-serif; font-size: 32px; letter-spacing: -0.02em; }
.card {
background: var(--card);
border: 1px solid var(--line);
border-radius: 16px;
padding: 32px;
box-shadow: 0 8px 40px rgba(0,0,0,0.08);
}
.card-sm { width: 100%; max-width: 380px; }
label { display: block; font-size: 9px; letter-spacing: 0.15em; color: var(--muted); margin-bottom: 6px; text-transform: uppercase; }
input {
width: 100%; background: #f7f4f0; border: 1.5px solid var(--line);
border-radius: 10px; padding: 11px 14px; font-family: inherit; font-size: 13px;
color: var(--ink); outline: none; margin-bottom: 14px;
}
input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(154,120,88,0.14); }
button.primary {
width: 100%; padding: 13px; background: var(--ink); color: var(--accent-ink);
border: none; border-radius: 10px; font-family: inherit; font-size: 13px;
font-weight: 500; letter-spacing: 0.04em; cursor: pointer;
}
button.primary:hover { background: #2e2e28; }
button.ghost {
background: none; border: none; color: var(--accent);
font-family: inherit; font-size: 12px; cursor: pointer; text-decoration: underline;
}
.err { background: #fff5f0; border: 1px solid #f5c9b0; color: #b5621e;
padding: 9px 14px; border-radius: 8px; font-size: 11px; margin-bottom: 14px; }
.ok { background: #e8f5ee; border: 1px solid #b8dbc4; color: #2d6a4f;
padding: 9px 14px; border-radius: 8px; font-size: 11px; margin-bottom: 14px; }
.nav { display: flex; justify-content: space-between; align-items: center; padding: 24px 0; }
.muted { color: var(--muted); }
.plan-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; }
.plan { position: relative; }
.plan.rec { border-color: var(--accent); }
.plan .badge { position: absolute; top: -10px; right: 16px; background: var(--accent);
color: var(--accent-ink); font-size: 9px; padding: 3px 8px; border-radius: 6px; letter-spacing: 0.1em; }
.plan .price { font-size: 28px; margin: 8px 0; }
.plan ul { list-style: none; padding: 0; font-size: 12px; color: #555; }
.plan li { padding: 4px 0; border-bottom: 1px solid var(--line); }