26 KiB
HiveGrid 2.0 — Agent-Regeln
Zentrale Regel-Datei für AI-Agents (Coding-Agents, ToolController-Worker), die an HiveGrid arbeiten.
Letzte Aktualisierung: 2026-06-19
Architektur-Quelle: Party-Mode-Diskussion mit Sally/Winston/Amelia, dokumentiert in docs/milestones/README.md.
Arbeitsmodus & Wo-finde-ich-was (Stand 16.06.)
Team — 2 Devs bauen PARALLEL (+ David = Screens/Subframe, Dejan = Website, Haris = Vertrieb):
- Raffael — kritische Kern-Kette, SEQUENZIELL: P1 → P2 → P5 → P6 → P7 → P8 → P9 → P11 → P12 → P13.
- Akeshan — unabhängige Trabanten parallel dazu: Infra, P3, P4, P17, P19, dann (nach P5) P14, P15, P16, P20, P21.
- Sync-Punkt: P14/P15/P16 brauchen Raffaels P5 (Apps-Engine). Parallel-Regel (AD-21): jedes Modul bekommt eine eigene
prisma/schema/<modul>.prisma; auf dem Feature-Branchprisma db push, Migration erst beim Merge — sonst Konflikte im Schema/in der Migrations-Historie.core.prisma/accounts.prismanur für Relationen zu Tenant/User anfassen. Siehe §„Prisma-Schema & Migrationen".
GSD = nur Infrastruktur, NICHT die Slash-Commands. Wir nutzen die .planning/-Struktur + Codebase-Konventionen, arbeiten aber ticket-getrieben — KEINE /gsd-plan-phase / /gsd-execute-phase-Befehle.
Ein Ticket bauen: Du bekommst eine Ticket-ID → lies .planning/ticket-docs/<ID>.md (self-contained Bau-Spec: Was/Screens/DoD/Technische-Bausteine/Quellen/Abhängigkeiten) und diese AGENTS.md. Voller Einstiegs-Prompt + Designer-first-Regel (UI wartet auf „Davids Delta" im Screen-Ticket): .planning/ticket-docs/README.md. Vor dem Bauen die blocked-by aus der Doc prüfen. Strikt im Ticket-/Ticket-Doc-Scope bleiben, Verbesserungen nur explizit ausgewiesen vorschlagen, Fortschritt als % der DoD melden → siehe §„Ticket-Treue, Verbesserungs-Vorschläge & Fortschritt".
Wo finde ich was:
| Was | Wo |
|---|---|
| Bau-Spec je Ticket (EINSTIEG) | .planning/ticket-docs/<ID>.md (157 Tickets, je 1 verlinkte Datei) |
| Datenmodell — LOCKED, Vorrang bei P6–P9 | .planning/ENTITY-MODEL.md (+ entity-model.dbml) |
| Phasen v1/v2 + Ziele/SC | .planning/ROADMAP.md · .planning/ROADMAP-V2.md |
| Phase → Milestone-Mapping | .planning/PHASE-SOURCES.md |
| Reihenfolge (Ticket an Start-Tag) | .planning/SPRINT-DAYPLAN.md |
| Requirements je Modul | .planning/REQUIREMENTS.md |
| Screen-Briefs (Designer) | .planning/designer-briefs/PXX.md |
| Architektur-Entscheidungen | docs/ARCHITECTURE-DECISIONS.md (u.a. AD-1 RLS · AD-17 PWA-only · AD-20 Projekt-zentrisch · AD-21 Prisma) |
| Live-Tickets/Status/Cycles | Plane: project.tool-ctrl.de, Projekt HiveGrid |
Pivot-Vorrang: Bei Widerspruch zwischen ENTITY-MODEL.md und den _bmad-output/specs/M0x (teils pre-pivot) gilt immer das ENTITY-MODEL (AD-20: ein Projekt-Kern, Pipelines=Views, „Deal"/„Auftrag"=Typen, Lead→Projekt, kein Won-Handoff). Die betroffenen Specs tragen oben einen 🔴 Pivot-Block.
Plane-Tracking (Ticket-System — gleicher Standard für beide Devs)
Wo: self-hosted Plane https://project.tool-ctrl.de, Workspace toolctrl, Projekt HiveGrid = 35d0d968-8ab3-40cc-97b8-b81d917dc5df (NICHT PowerLinked!). REST: {BASE}/api/v1/workspaces/{WORKSPACE}/projects/{PROJECT}/…, Auth-Header X-API-Key.
Zugang — kanonisch über Environment-Variablen (identische Namen bei Raffael + Akeshan):
PLANE_API_KEY (persönlich je Dev — nie ins Repo/Git) · PLANE_BASE_URL=https://project.tool-ctrl.de · PLANE_WORKSPACE=toolctrl · PLANE_PROJECT=35d0d968-….
Fallback, wenn Env leer: dieselben 4 Keys aus ~/.cli-tokens/plane (Zeilen KEY=VALUE).
Wer wird imitiert? (vor jeder Schreibaktion prüfen): Der PLANE_API_KEY ist persönlich → Kommentare/Assignee erscheinen unter diesem User. Identität verlässlich über GET {BASE}/api/v1/users/me/ (liefert den User des Keys). Nicht an der git-Mail festmachen (Maschine kann node1@… sein, Plane-User aber raffael@…). Ergebnis muss zum Dev der Maschine passen → bei Mismatch STOP + melden.
Member-IDs: raffael 8e34a88c… · akeshan 8bf43e86… · david 6c1fc63f… · dejan a5883f5e… · haris 48367c1f….
Skripte: .planning/plane-sync/ — dump_snapshot.py (read-only Snapshot), Pflege idempotent via scrub_plane.py. Module=Tracks, Cycles=Wochen, blocked-by=JIT.
Ticket abschließen (verbindliche Reihenfolge): 1) .planning/ticket-docs/<ID>.md: Umsetzungs-Notiz mit Datum + kurzem Proof (Commits/Tests/Deploy-Run) + DoD abhaken + %-Done-Stand (siehe §„Ticket-Treue, Verbesserungs-Vorschläge & Fortschritt"). 2) Plane-Kommentar — schlicht, 1. Person (= imitierter User), kein AI-Sprech, keine Em-Dashes (—). 3) Ticket auf Done — nur bei 100 % DoD.
Übersichten: Done-Tickets ausblenden, nur offene Arbeit zeigen.
Ticket-Änderungen dependency-aware (verbindlich)
Vor jeder maßgeblichen Ticket-Änderung (Start-/Zieldatum, Scope, Assignee/Owner) oder Code, der blocks-Tickets betrifft (Contracts aus R-P1a, core.prisma, Querschnitt-Services M001–M017):
- Beide Richtungen lesen:
blocked-byUNDblocks— in Plane und in den.planning/ticket-docs/-Docs der Abhängigen. - Abhängige nicht brechen: Änderung so wählen, dass blockierte/folgende Tickets konsistent bleiben (z.B. Start-Datum nie hinter Ziel-/Vorgänger-Datum schieben; keine Contract-/Schema-Änderung ohne Nachzug der Konsumenten).
- Auswirkung dokumentieren — in der eigenen Ticket-Doc und im betroffenen abhängigen Ticket (Muster: AD-23 → Eintrag in
AK-P4a). - „Fertig" heißt: Abhängige bleiben grün (Tests/Typecheck) — proaktiv prüfen, nicht erst bei Bruch reagieren.
Lokale Dev-Secrets (SOPS + age)
Geteilte Dev-.env-Werte liegen verschlüsselt in secrets/dev.sops.env (SOPS+age, beide Devs als Recipients). pnpm env:pull entschlüsselt nach ./.env, pnpm env:edit ändert sie. Onboarding/Regeln: secrets/README.md. Der age-Private-Key bleibt lokal (~/.config/sops/age/keys.txt), nie ins Repo. Nur geteilte API-Keys liegen im Blob; lokale DB/Redis = Defaults aus .env.example.
Die Boilerplate IST deine Codebase — kritisch
Du baust HiveGrid NICHT from scratch. Das HiveGrid-Cloud/-Repo enthält die EU-sterilisierte Boilerplate als Fundament. Das ist DEIN Code, du editierst, erweiterst und löschst ihn — du klonst nichts, du importierst nichts „von außen".
Konkret:
apps/web/,apps/api/,apps/worker/,packages/db/,packages/mail/,packages/queue/,packages/ui/, alles weitere → das ist deine Arbeitsbasispackage.jsonmit pnpm-Workspace, Prisma, BullMQ, MailerSend, shadcn/Radix → bestehender Stack, den du nutzt- Du erweiterst, was fehlt (z. B. neue
packages/view-models/,packages/ui-app/, neue Routes) - Du löschst, was nicht zu HiveGrid gehört (Affiliate-Reste, Marketing-Demo-Inhalte aus dem ToolCTRL-Boilerplate, falls noch vorhanden)
- Du baust neue Module in dieser Codebase, nicht neben ihr
Pre-Flight-Check beim Start (jedes Mal):
package.jsonim Repo-Root existiert mit pnpm-Workspace-Konfig → wenn nein: STOP, melde „Boilerplate-Inhalt fehlt"apps/,packages/,prisma/existieren → wenn nein: STOPpnpm typecheck && pnpm testläuft grün → wenn nein: STOP- Keine US-Provider-Imports mehr (
grep -rE "@ai-sdk/openai[^-]|@ai-sdk/anthropic|remix-auth-google" --include="*.ts"leer) → wenn nein: STOP, EU-Sterilisation nicht abgeschlossen. (Das[^-]lässt@ai-sdk/openai-compatibledurch — das ist der EU-taugliche provider-agnostische SDK für Mistral/Scaleway, KEIN US-Import.)
Erst danach beginnst du mit dem ersten Milestone.
Naming-Konvention (Stand 2026-06-04, siehe docs/ARCHITECTURE-DECISIONS.md AD-10)
Wichtige Korrektur zu „benenne frei um": Dieses Repo ist ein git-Downstream der Boilerplate
(upstream = git@git.tool-ctrl.de:toolctrl-labs/boilerplate.git). Boilerplate-Verbesserungen werden
via git merge upstream/main eingespielt. Deshalb wird NICHT umbenannt:
- Geteilte Boilerplate-Pakete behalten
@toolctrl/*(z.B.@toolctrl/foundation,@toolctrl/view-models,@toolctrl/db,@toolctrl/search) — mergebar mit upstream. - UI-Pakete heißen real
packages/ui-app,packages/ui-subframe,packages/ui-mock— NICHTpackages/ui-hivegrid. Wo Docs/PLANs „packages/ui-hivegrid" sagen, istpackages/ui-appgemeint. @hivegrid/*nur für genuin NEUE HiveGrid-Pakete, die upstream nie existieren (z.B. das neue Activity-Paket). Diese kollidieren beim Merge nicht.- Pfad-Korrekturen ggü. älteren Docs: Sidebar liegt in
apps/web/app/application/sidebar/(nichtsidebar.config.ts); Such-Index/indexedEntitiesgehört nachpackages/search/(nichtpackages/db/src/search/indexed-entities.ts).
Die DoD-, Anti-Pattern- und Workflow-Pfade unten nennen ab hier bereits die realen Pfade (packages/ui-app, apps/web/app/application/sidebar/, packages/search/); nur Punkt oben behält ui-hivegrid als Mapping-Hinweis für ältere Docs/PLANs.
Pflichtenheft als Quelle der Wahrheit
Verbindliches Pflichtenheft: _bmad-output/pflichtenheft/ v1.1 (Stand 2026-05-09).
Master-Milestone-Liste in docs/milestones/ ist die ausführungsreife Übersetzung in 176 Milestones. Pro Milestone ein Verzeichnis mit PLAN.md.
Progress-Tracking: docs/PROGRESS-TRACKER.md ist die Live-Übersicht. Du updatest sie nach JEDEM Status-Wechsel:
- Milestone-Start: Status auf
🔵 IN-ARBEIT, Detail-Sektion gemäß Vorlage anlegen - Slices abschließen: Slice-Liste abhaken mit Commit-Hashes
- Alle DoD-Punkte grün: Status auf
🟡 READY-TO-VERIFY, warten auf User-Sign-Off - User trägt
🟢 SIGNED-OFFein → erst DANN nächstes Milestone starten
Bei Konflikt zwischen Detail-Spec (_bmad-output/specs/M*.md) und Pflichtenheft gilt das Pflichtenheft v1.1.
Definition of Done — verbindlich für JEDES Milestone
Ein Milestone gilt nur dann als erledigt, wenn ALLE folgenden Punkte wahr sind:
A. Code-Layer-Trennung (PR-Block bei Verstoß)
- Loader/Action in
app/routes/**baut View-Model. KEIN Direkt-Import von~/dboder@prisma/clientinpackages/ui-app/**. - Domain-Logik in
app/domain/**importiert NIE React oder UI. - View-Models in
packages/view-models/**sind pure Funktionen ohne React/Prisma-Imports. - Subframe-Output in
packages/ui-subframe/**wird NIE direkt vonapp/routes/**importiert — nur via Adapter inpackages/ui-app/src/adapters/. - UI-Components rufen NIE
useLoaderData/useFetcherauf — Routes injizieren VM und Action-Callbacks.
B. Erreichbarkeit (Reachability — siehe docs/INTEGRATION-CONTRACTS.md)
- Sidebar-Eintrag in
apps/web/app/application/sidebar/(AppSidebar/AdminSidebar + SidebarItem) — oder Inline-Verlinkung aus bestehendem Modul, wenn das semantisch korrekt ist. - Permission-Gate auf dem Sidebar-Eintrag — Eintrag NUR sichtbar bei berechtigter Rolle.
- Route registriert unter dem korrekten URL-Pattern (siehe INTEGRATION-CONTRACTS.md §3).
- Breadcrumbs für Detail-Routes (siehe §4).
- i18n-Keys für ALLE UI-Texte (Pflicht via M003-Build-Lint).
- Mobile-Tab-Bar-Eintrag, falls das Modul mobile-relevant ist (§13).
- Customer-Portal-Konfiguration, falls Endkunden das sehen sollen (§14, Default unsichtbar).
C. Querschnitt-Wiring (Pflicht-Service-Aufrufe)
- Schreib-Aktion ist auditiert (auto via M001-Prisma-Middleware oder manuell via
auditEvent). - Activity-Stream-Eintrag auf relevanter Entität (Kontakt/Firma/Lead/Verkaufsfall/Auftrag) bei jeder relevanten Aktion via
logActivity. - Notifications via M011-Service (
notify({...})), niemals direkt Email/Push. - Search-Index registriert in
packages/search/(indexed-entities-Registry — M00-Neubau), falls suchbar. - Permission-Filter via
withTenantScope()+withPermission()(M004) — kein manueller Query-Filter im Modul-Code.
D. Tests (PR-Block ohne)
- Unit-Tests für View-Model-Builder (pure-function-test mit Fixture).
- Smoke-Test in
e2e/smoke/<modul>.spec.ts— Login → Route öffnen → Hauptaktion klicken → erwartetes Ergebnis sichtbar. - Hot-Swap-Drill (M017): Smoke-Tests müssen mit
packages/ui-mockals Drop-in-Replacement laufen. - Visual-Regression-Snapshot (M016) für die Hauptansicht.
E. Klartext-Hinweise (User-facing)
- ALLE Fehler-Texte aus M002-Catalog (kein nackter HTTP-Code, keine kryptische Stack-Trace im UI).
- Empty-State mit Klartext + nächster Aktion.
- Loading-State mit Klartext (kein leerer Spinner).
- Permission-Denied zeigt 404, nicht 403 (siehe Bauprinzip A.5.3).
F. Dokumentation
- PLAN.md des Milestones aktualisiert mit Lessons Learned, falls relevant.
- Rollback-Pfad dokumentiert im Slice-Plan (siehe
docs/MID-STREAM-CHANGES.md). - Forward-Only-DB-Migration mit Inverse-SQL als Kommentar im Migration-File.
Drei Anti-Patterns — sofortiger PR-Block
@prisma/clientoder~/dbinpackages/ui-app/**- Direktimport aus
packages/ui-subframeinapp/routes/** useLoaderData<typeof loader>()innerhalb vonpackages/ui-app/**
Daten-Fluss (verbindlich)
Synchron im Loader. Server bereitet das View-Model einmal auf, UI rendert. KEIN client-seitiges Re-Compute.
// app/routes/kontakte.$id.tsx
export async function loader({ params, context }: LoaderArgs) {
const entity = await context.db.kontakt.findUniqueOrThrow({ where: { id: params.id! } });
return json<KontaktDetailVM>(toKontaktDetailVM(entity, context.user));
}
export default function KontaktRoute() {
const vm = useLoaderData<typeof loader>();
return <KontaktDetailPage vm={vm} actions={{ onEdit, onArchive }} />;
}
Prisma-Schema & Migrationen (verbindlich — AD-21)
Das Schema ist ein Ordner (prisma/schema/, Prisma 7), nicht eine Datei. Bei parallelen Branches gilt:
- Ein Modul = eine eigene
prisma/schema/<modul>.prisma(viele existieren:appsEngine,email,workflows,notifications,permissions,marketingLeads…). Neue Modelle NIE incore.prisma/accounts.prisma— das ist der geteilte Kern (Tenant/User/Audit/File/ApiKey/Credential). Den nur für Relationen zuTenant/Userberühren, Rück-Relationsfelder minimal halten. - Feature-Branch:
prisma db push(kein Migrations-File). Die eine Migration pro Phase wird beim Merge aufmainerzeugt — Forward-only + Inverse-SQL als Kommentar (DoD 28). Verhindert divergierende Timestamp-Historie bei parallelen Branches. - Vor Merge:
prisma validate+prisma migrate statusgrün. URLs liegen inprisma.config.ts(DIRECT_URLMigrate,DATABASE_URL/PgBouncer Runtime). - Migration muss aus dem Nichts reproduzierbar sein (
infra/LESSONS.md §9): CI testetprisma migrate deploygegen eine leere DB — nur inkrementell auf Prod angewandte Migrations können bei Staging/DR/neuem Dev-Setup in falscher Reihenfolge brechen (gleicher Datums-Prefix sortiert lexikografisch, nicht nach Dependency → P3018). Order-abhängige DDL/DML inDO $$ … IF [NOT] EXISTS … $$-Blöcke guarden. Eine bereits auf Prod angewandte Migration nie umbenennen, ohne_prisma_migrations.migration_namenachzuziehen.
EU-Stack (nicht verhandelbar — Bauprinzip A.12)
- KEIN
@ai-sdk/anthropic,@ai-sdk/openai,openai - KEIN
remix-auth-google - KEIN Apple-/Google-/Microsoft-Login (Phase 1)
- JA Mistral primär, Scaleway sekundär, AlephAlpha tertiär (M083, M084)
- JA Email+Passwort + Magic-Link + TOTP (M020, M021, M022)
- Hosting: Hetzner + Coolify (EU); Datenbank: in EU; Storage: Hetzner Object Storage / S3 (EU) — vgl. ADR-009 (löst den früheren Scaleway-Hosting-Plan ab)
Querschnitt-Hülle nutzen, nicht nachbauen
| Concern | Querschnitt-Milestone | Service-Import |
|---|---|---|
| Audit-Log default | M001 | auto via Prisma-Middleware; manuell auditEvent |
| Klartext-Diagnostik | M002 | errorCatalog, ErrorBoundary |
| i18n | M003 | t('<modul>.<bereich>.<key>') |
| Tenant-Scope | M004 | withTenantScope(), withPermission() |
| Feature-Flag | M006 | featureFlag('<key>', tenant) |
| Idempotenz (BullMQ) | M007 | withIdempotency() |
| Apps-Engine-Adapter | M008-M010 | defineAdapter() |
| Notifications | M011 | notify({...}) |
| View-Model-Layer | M013 | Type + Zod-Schema in packages/view-models/src/<domain>/*.vm.ts |
| Action-Callback-Contract | M014 | Standard-Shape `{ onX: (input) => Promise<...> |
| Subframe-Adapter | M015 | Adapter in packages/ui-app/src/adapters/ |
| Visual-Regression | M016 | Playwright Component-Test mit Fixture-VM |
| Hot-Swap-Drill | M017 | pnpm test:hot-swap |
Wenn ein Modul Cross-Cutting-Concern selbst nachbaut → PR abgelehnt.
Estate-Infrastruktur — verbindliche Regeln (Quelle: infra/)
HiveGrid ist ein Workload in einem geteilten Estate (neben mITapp + Marketing-Sites). Quelle der Wahrheit ist das infra/-Repo (eine Ebene über diesem Repo): infra/README.md (Bestand), infra/STANDARDS.md (der „so wird jeder SaaS aufgesetzt"-Vertrag), infra/decisions/ (ADRs), infra/LESSONS.md (Footguns). Bei Widerspruch gewinnt infra/STANDARDS.md. Übersichts-Diagramm + Steckbriefe: local/infra-diagrams/06-estate-infrastructure.{mmd,md}.
Goldene Regel: geteilte Estate-Services NUTZEN, nie pro-Produkt nachbauen (analog zur Querschnitt-Hülle oben, nur eine Ebene tiefer — STANDARDS §1–§5/§13/§14). HiveGrid bekommt den Slug hivegrid (Sentry-Team, Meili-Index-Prefix, Cloudflare-Zone, Coolify-/Hetzner-Projekt HiveGrid).
| Concern | Zentral (mesh-only, wenn nicht anders genannt) | App-Env / Vertrag |
|---|---|---|
| Errors (STANDARDS §1) | Sentry sentry.saas-ctrl.com — 1 Team hivegrid, 1 Projekt je Codebase (web/api/worker) |
SENTRY_DSN_<APP> · SENTRY_ENVIRONMENT=staging|production · SENTRY_RELEASE=$GIT_SHA. Staging↔Prod = Tag, nicht eigenes Projekt. Browser-DSN als VITE_SENTRY_* Build-Arg (Coolify-Env ist nur Runtime). |
| FTS (STANDARDS §4, AD-5) | Meilisearch 10.42.0.4:7700 |
MEILI_URL=http://10.42.0.4:7700 · MEILI_API_KEY=<hivegrid-scoped>. Indizes hivegrid-*-prefixed, nie geteilt, nie Master-Key in der App. |
| Upload-AV (STANDARDS §13) | ClamAV 10.42.0.4:3310, INSTREAM (kein Path-Scan, kein shared FS) |
CLAMD_HOST=10.42.0.4 · CLAMD_PORT=3310. Failure-Policy explizit: fail-closed für untrusted Uploads. >100 MB vorab ablehnen. |
| NSFW-Bilder (STANDARDS §14) | nsfw-api 10.42.0.4:3000, POST /classify raw bytes |
NSFW_URL=http://10.42.0.4:3000. Failure-Policy: fail-open (Gegenteil von AV). |
| Logs (STANDARDS §2) | Loki 10.42.0.4:3100 via Promtail (per Host) |
App loggt strukturiertes JSON nach stdout/stderr, keine Secrets (Loki-Labels sind global queryable). |
| Metrics (STANDARDS §2/§3) | Prometheus+Grafana auf control (grafana.saas-ctrl.com) |
App-/metrics optional, aber bearer-token-geschützt. Pflicht-Labels project/environment/server/service. |
| Admin-SSO (STANDARDS §5, AD-3) | Authentik auth.tool-ctrl.de (OIDC) |
Nur Operator/Admin-Logins über Authentik. SaaS-Endkunden bleiben in der eigenen User-Tabelle. |
Mesh-only-Services (
10.42.0.4) haben keine Auth — Sicherheit = WireGuard-Mesh-Bind + UFW. Erreichbar nur als Mesh-Peer; nie einen Public-Port dafür fordern.
Deploy & Repo (STANDARDS §6–§9, ADR-002/005/010):
- Coolify ist das Deploy-Target (kein K8s/Terraform). Hierarchie: Projekt = Produkt (
HiveGrid, TitleCase) · Environment = Phase (production/staging, lowercase) · Resource = Service (hivegrid-web/-api/-worker, kebab-case). Ein zentrales Coolify aufcontrolsteuert alle Hosts. - Build-once / deploy-via-pull: CI (Gitea-Runner
toolctrl-ci) baut ein Image, pusht in die Gitea Package Registry (git.tool-ctrl.de/toolctrl-labs/<image>:<sha>immutable + Alias-Tags); Coolify pullt nur — kein Build in Coolify. Rollback = altes:<sha>neu deployen. - CI triggert Coolify mit
POST /api/v1/deploy?uuid=…&force=true— NICHT/restart(das reuset das gecachte Image und shipped still alten Code,infra/LESSONS.md §10). - Repo unter
toolctrl-labs/<name>in Gitea, private by default, mitDockerfile+.gitea/workflows/. Clone von Cloud-Hosts via HTTPS+PAT (Gitea-SSH:2222 ist von Hetzner unerreichbar, ADR-003). - DNS in Cloudflare (SSL-Mode strict): A-Record
proxied=falsebis das LE-Cert steht, danachtrue. Mail: OUT = Mailjet, IN = mailbox.org.
Secrets & Backups (STANDARDS §9/§10):
- Secrets nie ins Repo / in Chat / in CI-Logs. Per-User-Tokens in
~/.cli-tokens/(chmod 600); geteilte Dev-.envverschlüsselt via SOPS+age (secrets/dev.sops.env,pnpm env:pull). - Ein stateful Service (Postgres/Redis-Persistenz/Index) darf nicht Prod-Traffic bekommen, bevor das Backup in
infra/runbooks/dokumentiert ist (wohin, wie oft, Restore, letztes Restore-Drill-Datum).
Konkret tun (Host hinzufügen, Recovery, Secret-Rotation, neue Marketing-Site) → infra/runbooks/*.md.
Subframe-Workflow
- Designer baut Screen in Subframe
- User pulled Subframe-Code → landet in
packages/ui-subframe/src/** - AI-Coding-Agent integriert via Adapter-Layer in
packages/ui-app/src/adapters/** - Routes importieren nur
packages/ui-app, nieui-subframedirekt - Visual-Regression-CI (M016) prüft auf unbeabsichtigte Diffs
- Hot-Swap-Drill (M017) bestätigt: Tausch gegen
ui-mockbricht nichts
Anti-Liste respektieren — Bauprinzip A.9
Was nicht im Pflichtenheft v1.1 steht, ist nicht beauftragt. Vollständige Anti-Liste in _bmad-output/pflichtenheft/02-vision.md V.3.
Versucht ein Code-Vorschlag, einen Anti-Listen-Punkt umzusetzen → PR abgelehnt. Erweiterung nur über Change-Request-Workflow (docs/CHANGE-REQUESTS.md, M176).
Ticket-Treue, Verbesserungs-Vorschläge & Fortschritt (verbindlich)
1. Strikt am Ticket bauen — nichts erfinden. Gebaut wird ausschließlich, was in der Ticket-Doc
.planning/ticket-docs/<ID>.md (Was / Screens / DoD / Technische-Bausteine) und im Pflichtenheft v1.1
steht. Verboten sind: erfundene Tasks, „während ich hier bin"-Scope, ungefragte Refactors und vorgezogene
Arbeit aus Folge-Tickets/-Phasen (z.B. flächiger Roll-out, wo das Ticket nur den Nachweis verlangt). Ist die
Ticket-Doc lückenhaft, mehrdeutig oder widersprüchlich → Stop + Rückfrage (siehe §„Bei Unklarheit"), kein
Auto-Ausbau. Alles, was über das Ticket hinausginge, läuft über den Change-Request-Workflow
(docs/CHANGE-REQUESTS.md, M176). Maßstab ist die DoD der Ticket-Doc — nicht das, was technisch „auch noch
ginge".
2. Verbesserungen sind willkommen — aber IMMER explizit ausgewiesen, nie still gebaut. Du darfst (am Ende und gerne auch mittendrin) vorschlagen, was man besser/sicherer/sauberer machen könnte. Solche Hinweise müssen klar als Vorschlag außerhalb des Ticket-Scopes markiert sein — Format: eine Zeile/Block mit Präfix „💡 Vorschlag (außerhalb Ticket-Scope): …" + kurzer Begründung (Nutzen/Aufwand/Risiko). Erst nach explizitem OK des Users wird daraus Arbeit (i.d.R. neues Ticket / CR). Niemals einen Vorschlag direkt in Code/Commit ziehen, nur weil er sinnvoll wirkt — das ist ein PR-Block wie ein Anti-Listen-Verstoß.
3. Fortschritt in % ausweisen — bis das Ticket auf 100 % steht. Bei jeder Status- oder Abschluss-Meldung
zu einem Ticket den Stand als % done angeben, abgeleitet aus den DoD-Punkten der Ticket-Doc:
% = abgehakte DoD-Punkte / DoD-Punkte gesamt. Format z.B.: „R-P2a: 6/7 DoD = ~86 % done — offen: ".
DoD-Punkte, die extern blockiert sind (David-Screens, Partner-Input, Folge-Phase), als blockiert
kennzeichnen und vom selbst machbaren Rest trennen (z.B. „86 % done · 1 Punkt offen, davon 1 blockiert →
0 selbst machbar"). Den %-Stand zusätzlich in die Umsetzungs-Notiz der Ticket-Doc schreiben. Erst bei
100 % (alle DoD grün, nichts mehr selbst machbar offen) ist das Ticket abschlussreif → §„Ticket abschließen".
Klartext-Diagnostik — Bauprinzip A.1
- Kein
throw new Error("401 Unauthorized")— stattdessen Catalog-Fehler aus M002 - Kein hartkodierter UI-Text — stattdessen i18n-Key aus M003
- Jede Fehler-Meldung beschreibt: was passiert ist, was zu tun ist, welcher Knopf hilft
Kommentar-Sprache (Code = Englisch, Dokus = Deutsch)
Code-Kommentare werden auf Englisch geschrieben — passe dich der umgebenden Datei an, und
der Code-Bestand ist praktisch durchgaengig englisch kommentiert (Messung 2026-06-19: nur ~1% der
Quelldateien mit Kommentaren enthalten Deutsch, meist Alt-Bestand). Das gilt fuer *.ts/*.tsx,
*.prisma sowie SQL/Migrations in prisma/**. Grund: dies ist ein git-Downstream der
@toolctrl-Boilerplate (siehe Naming-Konvention) — englische Kommentare bleiben mergebar und
konsistent mit upstream.
Deutsch bleibt nur in den Projekt-Dokus: .planning/** (inkl. ticket-docs/),
docs/**, _bmad-output/**, local/**-Planungsartefakte sowie die Umsetzungs-Notizen und
Plane-Kommentare. Diese sind bewusst deutsch und bleiben deutsch.
Faustregel: liegt die Datei im ausfuehrbaren Code (apps/**, packages/**, prisma/**) →
Kommentare Englisch. Liegt sie in einem Doku-/Planungs-Ordner → Sprache der Doku (meist Deutsch).
RR7-Spezifika
.server.ts-Re-Export ist verboten (User-Memory). Nutze stattdessen Component-Extraktion.- Loader/Action sind die einzigen Pfade in
app/domain/**. Keine Direkt-DB-Calls aus Components.
Mid-Stream-Korrektur
Bei falschem Code: siehe docs/MID-STREAM-CHANGES.md für Eskalations-Stufen und Rollback-Pfad.
Bei Unklarheit
Stop, Frage an User, kein Auto-Refactor. Dokumentiere offene Frage in der PR-Beschreibung.