


In einem TypeScript-Frontend-Monorepo arbeiten, ohne Paketgrenzen zu verletzen
Für eine KI, die ein modulares TypeScript-Frontend ändert. Behandelt Paketgrenzen und einen frameworkfreien Kern, Zustandsänderungen nur über die zuständige Action, Ablage von Dateien und Tests, Prüfungen vor dem Commit, den Release-Ablauf und UI-Schichten.
Diese KI-Regeln verwenden
## Paketgrenzen nur über öffentliche Exporte überschreiten
- In einem Multi-Paket-Workspace sollte jedes Paket genau eine Verantwortung haben; Grenzen dürfen nur über öffentliche Paket-Exporte überschritten werden. Interne Strukturen eines anderen Pakets dürfen niemals direkt aus Anwendungscode importiert werden, da solche internen Importe Aufrufer eng an private Strukturen koppeln und bei Änderungen brechen. Grenzen werden durch automatisierte Lint- und Architekturprüfungen durchgesetzt, nicht durch manuelle Reviews; existiert kein passender Ort, wird bewusst einer geschaffen und die dokumentierten Konventionen entsprechend aktualisiert.
- Der gemeinsame Kern bleibt framework-unabhängig und frei vom Browser-DOM: UI-Framework-Bindings und die DOM-/CSS-Projektion gehören in eigene Schichten. Schwergewichtige Laufzeitabhängigkeiten wie WASM-Module oder große SDKs werden über ein zentrales Modul geladen, das Aufrufern eine injizierte Instanz übergibt, statt sie an jeder Aufrufstelle ad hoc zu importieren.
- Keine Re-Export-Shim-Dateien erstellen, deren einziger Zweck die Weiterleitung der API eines anderen Pakets ist; das besitzende Paket wird direkt an der Aufrufstelle importiert. Ein Kompatibilitäts-Barrel darf einen Besitzer nur dann re-exportieren, wenn dadurch eine etablierte öffentliche API erhalten bleibt.
- Schmale, gezielte Subpath-Exports sind einem einzigen Sammel-Barrel vorzuziehen, wenn kleinere Importe die Abhängigkeitsabsicht deutlicher machen.
## Gemeinsamen Zustand nur über die zuständige Action ändern
- Große Subsysteme werden aus einem gemeinsamen Kontext plus domänenspezifischen Aktionsmodulen (Viewport, Selektion, History, Struktur usw.) zusammengesetzt, statt aus einer einzigen, stetig wachsenden Datei. Vor dem Hinzufügen von Verhalten wird der bestehende Ordner und die dortigen Muster geprüft und die Änderung im am besten passenden Domänenmodul platziert; fachfremde Logik wird nicht einfach in die gerade geöffnete Datei gehäuft.
- Jede Zustandsänderung läuft über den zuständigen Setter oder die zuständige Aktion, damit Nebeneffekte — Events, Undo-Batching, abgeleitete Updates — zuverlässig ausgelöst werden. Felder gemeinsam genutzten Zustands werden niemals direkt zugewiesen, da diese Effekte sonst stillschweigend ausbleiben; Komponenten dürfen keinen veränderlichen Zustand auf Modulebene halten — gemeinsamer Zustand gehört in den Store.
- Änderungen werden über ein typisiertes Event-System nach außen sichtbar gemacht; Subscriber reagieren auf Events statt zu pollen. Domänenmodule teilen sich Zustand über das Kontextobjekt, nicht durch den Import von Anwendungs- oder Framework-Code.
- Anwendungs-Wrapper dürfen reaktiven Zustand, Persistenz und Plattform-I/O um den Kern herum ergänzen, doch der Kern selbst bleibt framework-unabhängig; jede Browser-API im gemeinsamen Code wird vor der Nutzung durch eine explizite Laufzeitprüfung abgesichert.
## any und Non-Null-Assertions in TypeScript verbieten
- `any` ist verboten: stattdessen präzise Typen, Generics und Declaration Merging verwenden. Non-Null-Assertions sind ebenfalls verboten: stattdessen Guards, Optional Chaining und Nullish Coalescing verwenden. Beide Regeln halten den Type-Checker in der Lage, echte Fehler zu erkennen, statt sie zu verdecken.
- Präzise Union-Typen sind losen Primitiven vorzuziehen — etwa eine kleine String-Literal-Union statt `number | string | null` — und eine Typdefinition wird nicht inline geschrieben, wenn bereits ein benannter, gemeinsam genutzter Typ existiert; dieser wird importiert und wiederverwendet.
- Wiederkehrende oder featureübergreifende Konstanten werden in einem gemeinsamen Konstanten-Modul benannt, statt Literale über die gesamte Codebasis hinweg zu duplizieren.
- Für Identifikatoren oder sicherheitsrelevante Zwecke wird niemals eine nicht-kryptografische Zufallsquelle verwendet; überall kommt ein kryptografischer Zufallsgenerator zum Einsatz. Verschachtelte Objekte werden beim Ändern verschachtelter Daten per Structured Clone tief kopiert, niemals per flachem Spread.
## Ordner nach Domäne benennen und jede Testart an ihren festen Ort legen
- Die Organisation erfolgt nach Domänen-Namensräumen statt nach tiefer struktureller Zeremonie; Anwendungsservices, Route- oder Layout-Views und UI erhalten jeweils eigene Top-Level-Bereiche.
- Für eine Domäne mit mehreren Dateien wird ein Unterordner verwendet, statt gleichrangige Dateien mit einem wiederholten Präfix zu versehen. Sobald eine Domäne ihre zweite Datei erhält, wird sofort der Ordner angelegt statt Namen zu präfixieren — `selection/hit-test` ist `selection-hit-test` vorzuziehen.
- Konventionelle Einstiegsdateinamen wie `index`, `types` und `context` bleiben kleingeschrieben; für Komponentendateien gilt die Schreibweise des jeweiligen Ökosystems. Code oder Tests werden nicht ad hoc platziert; existiert kein passender Ort, wird bewusst einer geschaffen und dokumentiert.
- Die Platzierung von Tests ist strikt und ortsbezogen: Jeder Testtyp gehört in sein etabliertes Verzeichnis (End-to-End, Integration, Unit, gemeinsame Helfer, pro Paket). Für den Nutzer sichtbares Verhalten gehört in End-to-End-Tests; Prüfungen von internem Zustand und Daten gehören in Unit-Tests. Temporäre Test- oder Profiling-Dateien werden niemals committet.
## Eine vorhandene Bibliothek nutzen, statt denselben Code selbst zu schreiben
- Was eine Abhängigkeit bereits leistet, wird nicht selbst nachgebaut. Zuerst werden vorhandene Abhängigkeiten geprüft; passt keine, wird eine hochwertige Bibliothek eingebunden, statt eine eigene Implementierung inline zu schreiben — etwa eine Diff-Bibliothek für Unified Diffs oder eine Farbbibliothek für Farbberechnungen statt einer handgeschriebenen Schleife.
- Bevor eigene UI, Controls oder Composables gebaut werden, wird die Upstream-Dokumentation der Abhängigkeit gelesen, statt aus der lokalen Nutzung zu raten; maschinenlesbare Doku-Einstiegspunkte werden bevorzugt, sofern verfügbar. Widerspricht die Upstream-Dokumentation lokalen Mustern, gelten die aktuellen Upstream-APIs, und lokale Wrapper werden bewusst entsprechend aktualisiert.
- Wartbare Programme und Helfer gehören in einen eigenen, nach Domäne organisierten Tools-Bereich mit jeweils fokussierten Tests, nicht als Ad-hoc-Skripte im Wurzelverzeichnis. Ein Scripts-Bereich ist ausschließlich für winzige Kompatibilitäts-Einstiegs-Shims reserviert, die aus dem Tools-Bereich importieren; Implementierungslogik gehört nicht in diese Shims.
- Tests für das Tooling sowie Lint- und Format-Abdeckung sind Teil der Standardprüfungen, damit der Tools-Bereich denselben Maßstab erfüllt wie der Produktcode.
## Vor dem Commit alle Qualitätsprüfungen bestehen und Conventional Commits schreiben
- Die vollständige Qualitätsschranke läuft vor jedem Commit und erneut vor dem Öffnen eines Reviews: typsensitives Lint und Typecheck ohne Fehler, der Formatter mit Import-Sortierung, Copy-Paste- und Duplikatserkennung ohne Klone sowie die relevanten Unit- und End-to-End-Suiten.
- Vor der Einreichung erfolgt eine Selbstprüfung: Steigt die Duplikation, werden gemeinsame Helfer extrahiert oder bestehende Typen wiederverwendet; Inline-Typdefinitionen, die benannte Typen duplizieren, sowie kopierte Logik werden entfernt; Dateien bleiben unter ein paar hundert Zeilen und werden bei Wachstum nach Domäne aufgeteilt.
- Commit-Nachrichten folgen Conventional Commits (`feat`, `fix`, `refactor`, `perf`, `docs`, `test`, `build`, `ci`, `chore`): eine kurze, imperative, optional mit Scope versehene erste Zeile mit kleingeschriebenem Typ, gefolgt von der Begründung im Body, wobei jede Body-Zeile mit einem großgeschriebenen Wort beginnt.
- Produkt- und Akronym-Schreibweise bleibt in Betreff und Body erhalten, statt Akronyme zu kleingeschriebenem Fließtext zu verflachen; es wird der engstmögliche ehrliche Scope verwendet — oder der Scope entfällt, wenn eine Änderung mehrere fachfremde Bereiche betrifft.
## Releases in fester Reihenfolge erstellen und das Changelog aktuell halten
- Es gilt ein fester, geordneter Release-Ablauf: Die Version wird in jeder Datei erhöht, die sie trägt; Changelog-Einträge wandern aus dem Abschnitt „Unreleased" unter eine neue, datierte Versionsüberschrift; anschließend wird mit einer Release-Nachricht committet und danach der Tag erstellt und gepusht. Vor dem Taggen wird bestätigt, dass alle Signatur- oder Release-Secrets vorhanden sind.
- Der Build- und Release-Workflow gilt als einzige verbindliche Quelle für Paketierung und Veröffentlichung; doppelt geführte Paketlisten werden mit ihm synchron gehalten. Produktions-Deploys werden an Release-Tags oder einen expliziten manuellen Dispatch gekoppelt, niemals an gewöhnliche Pushes auf den Standard-Branch, damit das Ausliefern stets bewusst geschieht.
- Die Dokumentation bleibt aktuell: Der Abschnitt „Unreleased" im Changelog sowie nutzerseitige Dokumentation werden bei jeder Verhaltensänderung aktualisiert, die Referenz für Mitwirkende bzw. Agenten bei jeder Änderung an Architektur oder Konventionen.
- Veröffentlichte Dokumentation bleibt frei von spekulativen oder internen Umsetzungsplänen — temporäre Pläne gehören in einen ignorierten Scratch-Bereich, dauerhafte Richtungsentscheidungen werden in die kanonischen Dokumente destilliert. Es werden keine Platzhalter-Übersetzungen erstellt; die lokalisierte Navigation verweist auf die kanonische Seite, bis eine echte Übersetzung existiert.
## Gemeinsame UI-Grundbausteine keinen App-Code importieren lassen
- Eine gemeinsame, wiederverwendbare UI-Primitive-Schicht wird von Feature- und Shell-Schichten getrennt. Gemeinsame Primitives und Low-Level-Styled-Controls dürfen keine Anwendungsservices, Stores oder Feature-Panels importieren; feature-spezifische Controls gehören den jeweiligen Feature-Komponenten.
- Styling wird über statische, typisierte Theme-Varianten aufgelöst, die an einer Stelle definiert und pro Instanz zusammengeführt werden, statt bedingte Utility-Class-Verzweigungen oder Einweg-Class-Props pro Slot zu verstreuen. Visueller Zustand wird über semantische Data-Attribute gebunden, und die typisierten Varianten werden im Skript aufgelöst.
- Für Test-Locators werden nutzerseitige Rolle, Label und Text bevorzugt; für Identität werden scoped semantische Attribute bereitgestellt, und dedizierte Test-IDs bleiben seltenen Integrationsgrenzen vorbehalten, statt innerhalb gemeinsamer Komponenten global eindeutige IDs zu erzeugen.
- Imperative Setter oder Aktionen werden nicht über Slots weitergereicht, es sei denn, eine Komponente ist explizit ein renderloses Primitive; bevorzugt werden Model-Bindings, emittierte Events und normale Props. Für Icons wird eine Icon-Bibliothek verwendet statt rohem Inline-SVG oder Unicode-Symbolen, und Labels bleiben semantisch, indem Tastenkombinationen aus Command-Metadaten gerendert werden, statt Shortcut-Text fest in die Labels zu backen.
