326 lines
23 KiB
HTML
326 lines
23 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>HiveGrid Cloud – Entwicklungs-Regeln & 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>& <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 & 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 & Package-Namen</li>
|
||
<li>Grundprinzipien</li>
|
||
<li>Code-Qualität & Linting (0 Warnings)</li>
|
||
<li>TypeScript & Typsicherheit</li>
|
||
<li>Formatierung (Prettier)</li>
|
||
<li>Unit- & 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 & 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 & 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 & 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 & 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 & 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- & 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 & 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 & 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><Outlet/></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> & <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>
|