Files
HiveGrid-Wireframes/hivegrid-cloud/docs/entwicklungs-regeln-handbuch.html
T

326 lines
23 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>HiveGrid Cloud – Entwicklungs-Regeln &amp; Infrastruktur</title>
<style>
@page {
size: A4;
margin: 22mm 18mm 20mm 18mm;
@bottom-center { content: counter(page) " / " counter(pages); font-size: 9px; color: #9a958c; }
@bottom-left { content: "HiveGrid Cloud – Engineering Handbook"; font-size: 9px; color: #9a958c; }
}
@page :first { margin: 0; @bottom-center { content: ""; } @bottom-left { content: ""; } }
* { box-sizing: border-box; }
html { font-size: 11px; }
body { font-family: -apple-system, "Segoe UI", "Helvetica Neue", Arial, sans-serif; color: #231F20; line-height: 1.5; margin: 0; }
/* Cover */
.cover { height: 297mm; padding: 40mm 24mm 0 24mm; background: linear-gradient(158deg, #2b2521 0%, #1c1813 60%, #14110d 100%); color: #fff; page-break-after: always; position: relative; }
.cover .logo { width: 250px; margin-bottom: 46mm; }
.cover .kicker { font-size: 13px; letter-spacing: 3px; text-transform: uppercase; color: #F1B729; font-weight: 600; }
.cover h1 { font-size: 39px; line-height: 1.1; margin: 14px 0 10px 0; font-weight: 700; color: #fff; }
.cover h1 .accent { color: #F1B729; }
.cover h2 { font-size: 17px; font-weight: 400; color: #d8d3c8; margin: 0 0 32px 0; }
.cover .meta { font-size: 12px; color: #ddd8cd; line-height: 1.9; border-top: 2px solid #F1B729; padding-top: 18px; max-width: 122mm; }
.cover .meta strong { color: #F1B729; }
.cover .badge { display:inline-block; background: rgba(241,183,41,.12); border:1px solid rgba(241,183,41,.55); color:#F1B729; border-radius: 20px; padding: 4px 13px; font-size: 11px; margin: 2px 4px 2px 0; }
/* TOC */
.toc { page-break-after: always; }
.toc .logo-dark { width: 150px; display:block; margin: 4mm 0 8mm 0; }
.toc h2 { border:none; }
.toc ol { list-style: none; padding-left: 0; counter-reset: toc; }
.toc > ol > li { counter-increment: toc; padding: 6px 0; border-bottom: 1px dotted #ddd6c5; font-weight: 600; color:#231F20; font-size: 12px; }
.toc > ol > li::before { content: counter(toc) ". "; color:#c69412; font-weight:700; }
/* Headings */
h2.section { font-size: 19px; color: #231F20; border-bottom: 3px solid #F1B729; padding-bottom: 5px; margin-top: 28px; break-after: avoid; }
h3 { font-size: 14px; color: #9a720b; margin-top: 18px; break-after: avoid; }
p { margin: 6px 0; }
ul, ol { margin: 6px 0; padding-left: 20px; }
li { margin: 3px 0; }
code { font-family: "SF Mono", "Menlo", Consolas, monospace; background: #fbf1d4; padding: 1px 5px; border-radius: 3px; font-size: 9.5px; color: #82610a; }
strong { color: #231F20; }
.lead { font-size: 12.5px; color: #5a544a; }
/* Tables */
table { width: 100%; border-collapse: collapse; margin: 10px 0; font-size: 9.7px; break-inside: avoid; }
th { background: #231F20; color: #fff; text-align: left; padding: 6px 8px; font-weight: 600; border-bottom: 2px solid #F1B729; }
td { border-bottom: 1px solid #e7e1d2; padding: 5px 8px; vertical-align: top; }
tr:nth-child(even) td { background: #faf6ec; }
/* Callouts */
.callout { border-left: 4px solid #F1B729; background: #fdf6e2; padding: 9px 14px; margin: 12px 0; border-radius: 0 5px 5px 0; break-inside: avoid; }
.callout.warn { border-left-color: #c2410c; background: #fdf0e8; }
.callout.ok { border-left-color: #15803d; background: #edf8ef; }
.callout .t { font-weight: 700; display:block; margin-bottom: 2px; color:#231F20; }
.pill { display:inline-block; font-size:8.5px; font-weight:700; padding:1px 7px; border-radius:10px; vertical-align:middle; }
.pill.block { background:#fadddd; color:#9b1c1c; }
.pill.local { background:#fbe9b0; color:#82610a; }
.small { font-size: 9.5px; color:#6b665c; }
hr { border:none; border-top:1px solid #e7e1d2; margin: 18px 0; }
/* Page-break protection */
section.sw { break-inside: avoid; }
.group { break-inside: avoid; }
</style>
</head>
<body>
<div class="cover">
<img class="logo" src="assets/hivegrid-logo-white.svg" alt="HiveGrid">
<div class="kicker">Engineering Handbook</div>
<h1>Entwicklungs-Regeln<br>&amp; <span class="accent">Infrastruktur</span></h1>
<h2>Verbindliche Standards für die gemeinsame Entwicklung</h2>
<div>
<span class="badge">0 Warnings</span>
<span class="badge">TypeScript strict</span>
<span class="badge">Hohe Test-Coverage</span>
<span class="badge">Pflicht-E2E</span>
<span class="badge">Accessibility AA</span>
<span class="badge">EU-Stack</span>
<span class="badge">~80 Quality-Gates</span>
</div>
<div class="meta">
<strong>Produkt:</strong> HiveGrid 2.0 – B2B-SaaS für CRM &amp; projektbasiertes Arbeiten<br>
<strong>Codebasis:</strong> Git-Downstream des ToolCTRL-Boilerplates (pnpm-Monorepo)<br>
<strong>Stand:</strong> 14. Juni 2026<br>
<strong>Grundsatz:</strong> Regeln sind durch automatische Gates erzwungen, nicht durch
guten Willen. Was rot ist, wird nicht gemerged.
</div>
</div>
<div class="toc">
<img class="logo-dark" src="assets/hivegrid-logo.svg" alt="HiveGrid">
<h2 class="section">Inhalt</h2>
<ol>
<li>Was HiveGrid Cloud ist (Produktkontext)</li>
<li>Codebasis-Modell: Git-Downstream &amp; Package-Namen</li>
<li>Grundprinzipien</li>
<li>Code-Qualität &amp; Linting (0 Warnings)</li>
<li>TypeScript &amp; Typsicherheit</li>
<li>Formatierung (Prettier)</li>
<li>Unit- &amp; Integrationstests + Coverage</li>
<li>End-to-End-Tests (Playwright)</li>
<li>Accessibility (a11y)</li>
<li>Quality-Gates: Commit → Push → Merge → Deploy</li>
<li>CI/CD-Pipeline</li>
<li>Infrastruktur &amp; Hosting</li>
<li>Architektur-Konventionen (inkl. EU-Stack)</li>
<li>Onboarding-Checkliste</li>
</ol>
</div>
<!-- 1 -->
<section class="sw">
<h2 class="section">1. Was HiveGrid Cloud ist</h2>
<p class="lead">HiveGrid 2.0 ist ein B2B-SaaS für Kontaktmanagement (CRM) und projektbasiertes Arbeiten – mit konsequent europäischem Datenschutz- und Hosting-Anspruch.</p>
<ul>
<li><strong>Kern-Domäne:</strong> Kontakte/Leads → projektbasierte Pipelines (Vertrieb, HR-Onboarding, Kundenbetreuung) → Auftragsabwicklung.</li>
<li><strong>Datenmodell:</strong> typisierte First-Class-Tabellen (z. B. <code>Kontakt</code>, <code>Projekt</code>) statt generischer Entity-Builder.</li>
<li><strong>EU-Stack (nicht verhandelbar):</strong> AI über EU-Provider (Scaleway, Mistral, Aleph Alpha; keine US-Provider), EU-Hosting auf Hetzner/Coolify, Auth über E-Mail+Passwort / Magic-Link / TOTP (kein Apple/Google/Microsoft-OAuth), Per-Tenant-Envelope-Encryption, Postgres mit Row-Level-Security als Defense-in-Depth.</li>
<li><strong>Bauweise:</strong> aufgeteilt in 176 Milestones (Pflichtenheft v1.1), Phase 0 → Fundament → Wertschöpfung.</li>
</ul>
<div class="callout">
<span class="t">Begriffsklärung</span>
<strong>HiveGrid Cloud</strong> ist die SaaS-Anwendung (dieses Repo, in aktiver Entwicklung). Die Marketing-Website <code>hivegrid.de</code> ist ein separates Projekt auf einem anderen Host – nicht zu verwechseln.
</div>
</section>
<!-- 2 -->
<section class="sw">
<h2 class="section">2. Codebasis-Modell: Git-Downstream &amp; Package-Namen</h2>
<p>HiveGrid Cloud ist <strong>kein klassischer Fork</strong>, sondern ein <strong>Git-Downstream</strong> des ToolCTRL-Boilerplates: Verbesserungen aus dem Boilerplate werden per <code>git merge upstream/main</code> übernommen. Damit das funktioniert, bleiben Package-Namen und Konfiguration absichtlich kompatibel.</p>
<div class="callout warn">
<span class="t">Wichtig zu den Package-Namen (häufiges Missverständnis)</span>
Es gibt <strong>kein flächiges Rename</strong> auf <code>@hivegrid/*</code>. Geteilte Boilerplate-Pakete behalten <code>@toolctrl/*</code> – sonst brechen Upstream-Merges. Entscheidung dokumentiert in <code>docs/ARCHITECTURE-DECISIONS.md</code> und <code>AGENTS.md</code>.
</div>
<table>
<tr><th>Scope</th><th>Wofür</th><th>Beispiele</th></tr>
<tr><td><code>@toolctrl/*</code></td><td>Alle vom Boilerplate geteilten Pakete (bleiben so, für Mergebarkeit)</td><td><code>@toolctrl/web</code>, <code>@toolctrl/api</code>, <code>@toolctrl/db</code>, <code>@toolctrl/foundation</code>, <code>@toolctrl/ui-app</code>, …</td></tr>
<tr><td><code>@hivegrid/*</code></td><td><strong>Nur</strong> genuin neue HiveGrid-Pakete, die es upstream nie gibt</td><td><code>@hivegrid/activity</code> (Activity-Stream-Service)</td></tr>
</table>
<p class="small">Mapping-Hinweis: Wo ältere Docs/Pläne <code>packages/ui-hivegrid</code> oder <code>@hivegrid/foundation</code> sagen, ist real <code>packages/ui-app</code> bzw. <code>@toolctrl/foundation</code> gemeint. Ein späterer Naming-Drift-Fix ist in den ADRs als Option notiert, aber bewusst noch nicht umgesetzt.</p>
<p><strong>Neu in HiveGrid:</strong> <code>@hivegrid/activity</code> – zentraler Activity-Stream/Änderungs-Historie, hängt nur an <code>@toolctrl/db</code>. Weitere HiveGrid-spezifische Pakete folgen demselben Muster.</p>
<p><strong>Node-Version:</strong> HiveGrid nutzt <code>v22.12.0</code> (<code>.nvmrc</code>) – neuer als der Boilerplate. Vor der Arbeit <code>nvm use</code> ausführen.</p>
</section>
<!-- 3 -->
<section class="sw">
<h2 class="section">3. Grundprinzipien</h2>
<ul>
<li><strong>Linting:</strong> Kompromisslos – <code>--max-warnings=0</code>. Eine Warning bricht den Build.</li>
<li><strong>Typsicherheit:</strong> TypeScript <code>strict</code>. <code>any</code>/Type-Escapes nur über eine gedeckelte Baseline.</li>
<li><strong>Tests:</strong> Sehr hohe Coverage auf kritischen Pfaden (Auth, Billing, Tenant-Isolation ~99 %), erzwungen pro Verzeichnis.</li>
<li><strong>End-to-End:</strong> Pflicht. Kritische Flows müssen als Playwright-Specs existieren; ein Gate prüft wörtliche Test-Inhalte.</li>
<li><strong>Accessibility:</strong> WCAG 2.2 AA als Gate (Farbkontrast, Mobile-Overflow).</li>
<li><strong>EU-Datenschutz by design:</strong> RLS, Envelope-Encryption und EU-only-Provider sind Architektur-Vorgaben, kein Add-on.</li>
<li><strong>Automatisierung statt Disziplin:</strong> ~80 <code>verify:*</code>-Gates erzwingen die Regeln in Pre-Commit-Hooks und CI.</li>
</ul>
<div class="callout"><span class="t">Leitsatz</span>Fehler nach links schieben: Was lokal in Sekunden gefangen werden kann, läuft im Pre-Commit-Hook. CI ist Sicherheitsnetz, nicht erster Prüfer.</div>
</section>
<!-- 4 -->
<section class="sw">
<h2 class="section">4. Code-Qualität &amp; Linting</h2>
<p>ESLint mit <code>@typescript-eslint</code>, <code>import</code>, <code>jsx-a11y</code>, <code>react-hooks</code> (Basis <code>plugin:jsx-a11y/recommended</code>). Konfiguration identisch zum Boilerplate.</p>
<div class="callout warn"><span class="t">Die wichtigste Regel</span><code>pnpm run lint</code> = <code>eslint --max-warnings=0 --ext .tsx,.ts .</code> — <strong>Null Warnings.</strong> Es gibt keine „gelben" Builds.</div>
<div class="group">
<h3>Harte Regeln (Error-Level)</h3>
<table>
<tr><th>Regel</th><th>Wirkung</th></tr>
<tr><td><code>no-debugger</code></td><td>Kein <code>debugger</code>.</td></tr>
<tr><td><code>no-console</code> (Server)</td><td>In Server-Code (<code>*.server.ts</code>, <code>apps/api</code>, <code>apps/worker</code>, <code>packages/*/src</code>, Service-/DB-Layer) verboten; in UI/Tests/Skripten erlaubt.</td></tr>
<tr><td><code>no-restricted-imports</code></td><td>Kein direkter <code>@prisma/client</code> (nur über <code>@toolctrl/db</code>); keine direkten <code>src/*</code>-Imports zwischen Packages; <code>foundation</code>/<code>view-models</code> ohne React/UI; UI-Packages ohne DB.</td></tr>
<tr><td><code>no-restricted-syntax</code> (Phase-C-UI)</td><td>Keine hartkodierten nutzersichtbaren Strings in <code>ui-app</code>/<code>ui-subframe</code>/<code>ui-mock</code> – alles über i18n-Keys.</td></tr>
</table>
</div>
<div class="group">
<h3>Accessibility-Lint &amp; Escape-Hatch-Baseline</h3>
<p>jsx-a11y-Regeln „monoton fallend": bei 0 Verstößen werden sie auf <code>error</code> hochgestuft und können nie wieder regredieren. Type-/Lint-Ausnahmen sind gedeckelt (<code>verify:eslint-baseline</code>): max. <strong>262</strong> <code>eslint-disable</code>, <strong>35</strong> <code>@ts-ignore</code>, <strong>43</strong> <code>@ts-expect-error</code>. Neue brauchen Baseline-Erhöhung + Review.</p>
<p class="small">Datei-Limits: <code>apps/api/src/app.ts</code> ≤ 450 Zeilen, API-Route-Module ≤ 500 Zeilen (<code>verify:source-health</code>).</p>
</div>
</section>
<!-- 5 -->
<section class="sw">
<h2 class="section">5. TypeScript &amp; Typsicherheit</h2>
<ul>
<li><code>strict: true</code> (inkl. <code>noImplicitAny</code>, <code>strictNullChecks</code> …). <code>any</code> praktisch verboten.</li>
<li>Typecheck ist Pflicht nach Routen-Änderungen und läuft als Pre-Push-Hook.</li>
</ul>
<div class="callout"><span class="t">React-Router-v7-Regel</span>Routen-Typen <strong>immer</strong> aus <code>./+types/[routeName]</code> (nie relativ). Fehlen Typen → <code>pnpm run typecheck</code>, nie den Importpfad „reparieren".</div>
</section>
<!-- 6 -->
<section class="sw">
<h2 class="section">6. Formatierung (Prettier)</h2>
<table>
<tr><th>Einstellung</th><th>Wert</th><th>Einstellung</th><th>Wert</th></tr>
<tr><td>printWidth</td><td>160</td><td>semi</td><td>true</td></tr>
<tr><td>singleQuote</td><td>false (Double Quotes)</td><td>tabWidth</td><td>2 (Spaces)</td></tr>
<tr><td>trailingComma</td><td>es5</td><td>arrowParens</td><td>always</td></tr>
<tr><td>endOfLine</td><td>lf</td><td>Plugin</td><td>prettier-plugin-tailwindcss</td></tr>
</table>
</section>
<!-- 7 -->
<section class="sw">
<h2 class="section">7. Unit- &amp; Integrationstests + Coverage</h2>
<p>Vitest + Testing Library (jsdom), Coverage-Provider v8. Schwellen identisch zum Boilerplate und <strong>pro Verzeichnis</strong> erzwungen (<code>verify:test-coverage</code> gegen <code>scripts/coverage-targets.json</code>).</p>
<table>
<tr><th>Kritischer Pfad</th><th>Statements</th><th>Branches</th></tr>
<tr><td>API Auth</td><td>99 %</td><td>92 %</td></tr>
<tr><td>Billing</td><td>99 %</td><td>97 %</td></tr>
<tr><td>Tenant-Isolation</td><td>99 %</td><td>99 %</td></tr>
<tr><td>Session / Permissions</td><td>99 %</td><td>98 %</td></tr>
<tr><td>Stripe</td><td>95 %</td><td>90 %</td></tr>
<tr><td>Basis-Targets (z. B. apps/api)</td><td>70 %</td><td>60 %</td></tr>
</table>
<p><strong>Test-Dichte-Gate</strong> (Pre-Commit): Mindestverhältnis Tests/Quelldateien je Workspace (z. B. <code>apps/api</code> ≥ 0,18; App-Routes ≥ 0,05; <code>packages/brand</code>/<code>config</code> ≥ 0,50). Neue HiveGrid-Pakete (z. B. <code>@hivegrid/activity</code>) brauchen eigene Tests.</p>
<p class="small">Konventionen: <code>*.test.ts(x)</code> / <code>*.spec.ts</code>; Boundary <code>*boundary.test.ts</code>; a11y <code>*.a11y.test.tsx</code> / <code>*.axe.test.tsx</code>.</p>
</section>
<!-- 8 -->
<section class="sw">
<h2 class="section">8. End-to-End-Tests (Playwright)</h2>
<p>Verzeichnis <code>tests/e2e</code> (~39 Specs). Chromium, optional Mobile-Matrix (Pixel 5 + iPhone 13). Seriell, Timeout 120 s, Traces bei Fehlern. E2E laufen nächtlich gegen die Live-Staging-Umgebung; Basis ist ein deterministischer Readiness-Tenant (<code>seed:e2e-readiness</code>).</p>
<div class="group">
<h3>a11y-Coverage-Gate (pinnt Tests wörtlich)</h3>
<p><code>verify:a11y-coverage</code> verlangt ≥ 12 Component-a11y-Tests und ≥ 7 E2E-a11y-Specs und prüft wörtliche Snippets kritischer Flows (z. B. <code>expectNoCriticalA11yViolations(</code>, <code>expectNoHorizontalOverflow(</code>).</p>
<div class="callout warn"><span class="t">Nach E2E-Refactors</span>Das Gate matcht <strong>literale Strings</strong>. Tests umbenennen/umbauen → <code>verify:a11y-coverage</code> erneut laufen lassen.</div>
</div>
<div class="group">
<h3>RR7 Single-Fetch-Interceptor-Contract</h3>
<p>Form-POST-Interceptoren müssen das <code>.data</code>-Ziel matchen und <strong>turbo-stream</strong> zurückgeben (kein rohes JSON), inkl. <code>X-Remix-Response: yes</code>. Helfer in <code>tests/e2e/utils/navigation.ts</code>.</p>
<p class="small">Pflicht-Flows (Auszug): Registration/Onboarding, Golden-Path, Subscription-Smoke, Plugin-Settings/-Lifecycle, Workflow-Builder+Run, Members, Audit, Profile-Security, Privacy, API-Keys, Mobile-Shell.</p>
</div>
</section>
<!-- 9 -->
<section class="sw">
<h2 class="section">9. Accessibility</h2>
<p>jsx-a11y-Lint · <code>verify:color-contrast</code> (WCAG 2.2 AA) · axe-core-Suite (<code>test:a11y</code>) · Mobile-Overflow-/Violation-Checks in E2E · Lighthouse-a11y als Warnung.</p>
</section>
<!-- 10 -->
<section class="sw">
<h2 class="section">10. Quality-Gates: Commit → Push → Merge → Deploy</h2>
<div class="group">
<h3>Beim Commit <span class="pill local">lefthook pre-commit · parallel</span></h3>
<p>lint-staged (ESLint auf geänderten Dateien) · <code>verify-secrets</code> · <code>verify-eslint-baseline</code> · <code>verify-test-density</code>.</p>
</div>
<div class="group">
<h3>Beim Push <span class="pill local">lefthook pre-push · seriell</span></h3>
<p><code>typecheck</code> · <code>verify-hardcoded-strings</code> (i18n). Notfall-Bypass nur mit <code>LEFTHOOK=0</code>, nie auf <code>main</code>.</p>
</div>
<div class="group">
<h3>Beim Merge (CI) <span class="pill block">blockiert</span></h3>
<p>Jobs <code>quality</code> + <code>api</code> + <code>worker</code> + <code>database</code> + <code>docker-smoke</code> müssen grün sein (Typecheck, Lint, Tests, Build, Bundle-Size, a11y, ~18+ Baseline-Gates).</p>
</div>
<div class="group">
<h3>Beim Deploy <span class="pill block">blockiert</span></h3>
<p>Preflight-Gates (<code>deploy-readiness</code>, <code>docker-baseline</code>, <code>docker-non-root</code>). Produktions-Promote erfordert <code>backup_confirmed=true</code>.</p>
</div>
</section>
<!-- 11 -->
<section class="sw">
<h2 class="section">11. CI/CD-Pipeline</h2>
<p>Zwei parallele Welten mit gleichen Gates: GitHub Actions und <strong>Gitea</strong> (self-hosted Runner). Eigene Gates sichern die Parität. <code>ci.yml</code>-Jobs: <code>quality</code>, <code>api</code>, <code>worker</code>, <code>database</code>, <code>docker-smoke</code>.</p>
<p>Die ~80 <code>verify:*</code>-Gates sind <strong>Baseline-/Anti-Regressions-Gates</strong>. Gruppen: Security/Auth · Mandantentrennung/Boundaries · Docker/Deploy · i18n/a11y · API/Specs · CI-Struktur · Docs.</p>
<div class="callout"><span class="t">Lighthouse &amp; SEO</span>Performance ≥ 95 % ist hart gegated; a11y/Best-Practices/PWA nur Warnung. <strong>SEO ist bewusst nicht gegated</strong> (B2B-SaaS).</div>
</section>
<!-- 12 -->
<section class="sw">
<h2 class="section">12. Infrastruktur &amp; Hosting</h2>
<p>HiveGrid Cloud läuft im gemeinsamen Hetzner-Estate (EU/Deutschland), zentral über Coolify gesteuert. Detail-Inventar im separaten Dokument „Server-Struktur". Das Wesentliche:</p>
<ul>
<li><strong>Control-Plane:</strong> Coolify v4 auf der <code>control</code>-VM (Dashboard <code>saas-ctrl.com</code>) steuert alle Hosts per SSH.</li>
<li><strong>Staging:</strong> Ein gemeinsamer Host <code>staging-1</code> trägt mehrere Produkt-Stagings nebeneinander – nicht eine VM pro Produkt.</li>
<li><strong>Produktion:</strong> Laut ADR-009 erhält jedes SaaS-Produkt ein <strong>eigenes Hetzner-Projekt</strong> für Prod (eigene DB/App). Das HiveGrid-Cloud-Prod-Projekt wird bei Reife angelegt; die SaaS-App ist aktuell in Entwicklung und noch nicht deployt.</li>
<li><strong>Zentrale Dienste (geteilt über WireGuard-Mesh, auf <code>node1</code>):</strong> Sentry (Errors), Loki (Logs), Meilisearch (Suche, per-Produkt-Scoped-Key), ClamAV (Virenscan), mCaptcha; Prometheus + Grafana auf <code>control</code>.</li>
<li><strong>Services pro App-Stack:</strong> web (8080), api (8080), worker ×5 Queue-Gruppen (general/mail/import/webhook/plugin), Postgres 16, PgBouncer (Transaction-Pooling), Redis 7, Authentik (Admin-SSO).</li>
<li><strong>Deploy:</strong> build-once-deploy-many über die Gitea-Registry; Coolify zieht das fertige Image und startet die Container neu (~30 s). Rollback = altes SHA-Image neu deployen.</li>
</ul>
<div class="callout ok"><span class="t">EU-Hosting</span>Compute, Daten und Object-Storage (S3) liegen in der EU – auf Hetzner (Deutschland), orchestriert über Coolify. Das stützt die EU-Datenschutz-Vorgaben aus Abschnitt 13.</div>
</section>
<!-- 13 -->
<section class="sw">
<h2 class="section">13. Architektur-Konventionen</h2>
<ul>
<li><strong>Upstream-Disziplin:</strong> Geteilten Code so lassen, dass <code>git merge upstream/main</code> sauber bleibt. Neues HiveGrid-Verhalten in <code>@hivegrid/*</code>-Paketen oder klar abgegrenzten Modulen.</li>
<li><strong>Package-Grenzen:</strong> Immer öffentliche Paketnamen importieren, nie fremdes <code>src/*</code>. Server-DB nur über <code>@toolctrl/db/client.server</code>, Env über <code>@toolctrl/config</code>, Queues über <code>@toolctrl/queue</code>.</li>
<li><strong>EU-Stack erzwingen:</strong> Keine US-AI-Provider (nur EU-Provider: Scaleway, Mistral, Aleph Alpha); kein Social-OAuth (nur E-Mail/Passwort, Magic-Link, TOTP); Per-Tenant-Envelope-Encryption; Postgres-RLS als zusätzliche Mandanten-Grenze.</li>
<li><strong>URLs:</strong> host-aware Helfer (<code>href()</code>, <code>appPath</code>/<code>adminPath</code>/<code>apiPath</code>), keine handgebauten Pfade.</li>
<li><strong>Secrets:</strong> nie in UI-Code; nur über <code>@toolctrl/config</code> / Server-Boundaries. Tenant-Filter bei jedem Datenzugriff erhalten.</li>
<li><strong>RR7:</strong> Typen aus <code>./+types/...</code>; <code>&lt;Outlet/&gt;</code> in Layouts; <code>typecheck</code> nach Routen-Änderungen.</li>
<li><strong>Doku mitführen:</strong> bei Feature-/Provider-/Worker-Änderungen <code>docs/feature-manifests/*.json</code>; bei mutierenden Routen <code>docs/security/csrf-inventory.md</code>; bei Rollen/Permissions <code>docs/roles-matrix.md</code>. HiveGrid-Fortschritt in <code>docs/PROGRESS-TRACKER.md</code>, Entscheidungen in <code>docs/ARCHITECTURE-DECISIONS.md</code>.</li>
</ul>
</section>
<!-- 14 -->
<section class="sw">
<h2 class="section">14. Onboarding-Checkliste</h2>
<div class="callout ok">
<span class="t">Vor dem ersten Commit</span>
<ol style="margin:4px 0 0 0;">
<li><code>nvm use</code> (Node <code>v22.12.0</code>), dann <code>pnpm install</code> – installiert die Hooks automatisch.</li>
<li><code>AGENTS.md</code> + <code>docs/ARCHITECTURE-DECISIONS.md</code> lesen (Package-Modell, EU-Stack, Milestone-Struktur).</li>
<li><code>pnpm run dev</code> starten – generiert die RR7-Routen-Typen.</li>
<li><code>pnpm run typecheck</code> &amp; <code>pnpm run lint</code> sauber (0 Warnings); vor Push <code>pnpm test</code> grün.</li>
<li>Für E2E: <code>seed:e2e-readiness</code>, <code>.env.e2e-readiness</code> sourcen, dann <code>verify:a11y-coverage</code> + Playwright.</li>
</ol>
</div>
<p class="small">Goldene Regel: Wenn ein Gate rot ist, ist die Lösung der Code – nicht das Umgehen des Gates.</p>
<hr>
<p class="small">Stand 14. Juni 2026. Quellen: HiveGrid-Cloud <code>package.json</code>, <code>.eslintrc</code>, <code>.prettierrc</code>, <code>tsconfig.json</code>, <code>vitest.config.ts</code>, <code>playwright.config.ts</code>, <code>lefthook.yml</code>, <code>scripts/coverage-targets.json</code>, <code>AGENTS.md</code>, <code>docs/ARCHITECTURE-DECISIONS.md</code> sowie das <code>infra</code>-Repository. Konfiguration ist – bis auf Node-Version und HiveGrid-spezifische Pakete/Docs – identisch zum ToolCTRL-Boilerplate.</p>
</section>
</body>
</html>