


Backend-Code und passende Tests zu einer Anwendung mit mehreren Diensten hinzufügen
Für einen KI-Agenten, der eine Anwendung aus mehreren Diensten mit Hintergrundarbeitern ändert. Er prüft Umgebung und Dienste, legt Datenbank- und Aufgabencode richtig ab, definiert Aufgaben und Fehler nach Projektvorgaben, wählt eine passende Testart und plant vor dem Programmieren.
Diese KI-Regeln verwenden
## Umgebung einrichten und prüfen, ob die Dienste laufen
- Die Abhängigkeiten des Backends liegen in einer virtuellen Umgebung im Wurzelverzeichnis des Repositorys, die über eine Sperrdatei verwaltet wird. Falls sie noch nicht existiert, erstelle sie aus der eingefrorenen Sperrdatei und aktiviere sie, bevor du irgendetwas ausführst.
- Zugangsdaten und Schlüssel, die für Tests benötigt werden, stehen in der lokalen Umgebungsdatei des Repositorys. Lies sie dort aus, statt Werte zu erfinden oder neue anzufordern.
- Gehe davon aus, dass alle Dienste der Anwendung bereits laufen, aber prüfe es nach, statt darauf zu vertrauen: Sieh im Protokollverzeichnis nach und bestätige, dass der betreffende Dienst weiterhin Einträge schreibt.
- Erreiche die Datenbank über den laufenden Container mit dem im Projekt dokumentierten Aufruf des Clients, nicht über eine selbst improvisierte Verbindung.
- Wenn du die Webanwendung per Browserautomatisierung durchspielst, melde dich mit dem Konto an, das die Ende-zu-Ende-Einrichtung anlegt. Falls es nicht existiert, registriere es über die Registrierungsseite, denn das zuerst registrierte Konto wird zum Administrator.
## Datenbankabfragen in einer Schicht halten und Testaufrufe über das Frontend schicken
- Lege jede Datenbankoperation in die dafür vorgesehenen Verzeichnisse für den Datenzugriff. Führe von keiner anderen Stelle aus Abfragen aus, damit das Wissen über das Schema in einer Schicht bleibt und an einer Stelle geprüft werden kann.
- Wenn du das Backend bei manuellen oder skriptgesteuerten Tests aufrufst, gehe immer über den Ursprung des Frontends und nicht direkt über den Port des Backends. Eine Anfrage, die das Frontend überspringt, überspringt auch das Verhalten von Proxy, Sitzung und Authentifizierung, das echter Verkehr durchläuft; das Ergebnis ist deshalb nicht aussagekräftig.
## Neue Arbeit in den passenden Arbeiterpool im Hintergrund legen
Asynchrone Arbeit wird auf spezialisierte Arbeiterpools verteilt statt auf eine einzige allgemeine Warteschlange. Ordne neue Arbeit dem Pool zu, dessen Profil dazu passt.
- Ein Hauptpool koordiniert systemweite Operationen: Löschen von Ressourcen, Synchronisierung, Bereinigung und regelmäßige Prüfungen.
- Abrufpools holen Daten aus externen Quellen und erzeugen pro Stapel eine Verarbeitungsaufgabe, mit einer Überwachung durch einen Wächterprozess, sodass eine ins Stocken geratene Quelle erkannt wird.
- Verarbeitungspools führen die Aufnahmestrecke aus: Datensätze dauerhaft speichern, in Abschnitte zerlegen, anreichern, einbetten, in den Suchindex schreiben und Metadaten aktualisieren.
- Ein leichter Pool bearbeitet kurze Operationen mit hoher Nebenläufigkeit. Ein schwerer Pool bearbeitet ressourcenintensive Operationen mit geringer Nebenläufigkeit.
- Ein Überwachungspool, der einsträngig arbeitet, weil Überwachung keine Parallelität braucht, sammelt Kennzahlen zu Warteschlangenlänge, Speicher und Zustand.
- Ein Planerpool verantwortet die regelmäßigen Auslöser, von Intervallprüfungen im Sekundenbereich bis zu stündlichen Aufräumläufen, und ermittelt den Mandanten für jede geplante Aufgabe.
Gemeinsame Eigenschaften aller Pools: Pools von Ausführungssträngen statt von Prozessen zugunsten der Stabilität, Trennung je Mandant, Prioritätswarteschlangen, Herzschlag- und Lebendigkeitsprüfung, automatische Wiederholung und Fehlerbehebung, ein schneller gemeinsamer Speicher zur Abstimmung zwischen Prozessen und die relationale Datenbank für den dauerhaften Aufgabenzustand.
## Jeder Hintergrundaufgabe eine Ablaufzeit und ein eigenes Zeitlimit geben
- Deklariere Aufgaben mit dem anwendungsunabhängigen Dekorator des Rahmenwerks, statt sie an eine konkrete Anwendungsinstanz zu binden, damit der Import einer Aufgabe niemals den Aufbau der Anwendung mitzieht.
- Halte Aufgabenmodule in den dafür vorgesehenen Aufgabenverzeichnissen der jeweiligen Edition oder Stufe.
- Stelle niemals eine Aufgabe ohne Ablaufzeit in die Warteschlange. Gib eine an, gleich ob die Aufgabe aus dem Zeitplan oder aus einer anderen Aufgabe heraus abgeschickt wird. Code einzureichen, der ohne Ablaufzeit in die Warteschlange stellt, ist nicht zulässig, weil die Warteschlange dadurch unbegrenzt wachsen kann.
- Da Aufgaben in Pools von Ausführungssträngen laufen, sind die eigenen Funktionen des Rahmenwerks zur Zeitbegrenzung stillschweigend abgeschaltet. Setze die Logik für Zeitüberschreitungen innerhalb der Aufgabe selbst um.
- Arbeiter laden bei einer Codeänderung nicht neu. Bitte nach einer Änderung am Arbeitercode die betreuende Person, den Arbeiter vor dem Testen neu zu starten, und gehe nicht davon aus, dass der neue Code aktiv ist.
## Endpunkte hinzufügen und Fehler mit dem eigenen Fehlertyp des Projekts auslösen
- Wenn du einen Endpunkt hinzufügst, typisiere die Behandlungsfunktion direkt, statt ein eigenes Feld für das Antwortmodell zu deklarieren.
- Löse den eigenen Fehlertyp des Projekts aus statt der allgemeinen HTTP-Ausnahme des Rahmenwerks, und schreibe Statuscodes niemals fest in den Code und importiere niemals Statuskonstanten aus dem Rahmenwerk.
- Eine globale Behandlungsroutine wandelt den Projektfehler in einen einheitlichen Antwortkörper um, der einen Fehlercode und eine Detailangabe trägt. Das beseitigt wiederkehrenden Standardcode und hält die Fehlerbehandlung im gesamten Backend einheitlich.
- Fehlercodes stammen aus einem zentralen Register. Wird eine neue Kategorie gebraucht, füge sie zuerst dem Register hinzu; erfinde niemals einen Code an der Aufrufstelle.
- Wenn du einen vorgelagerten Fehler weiterreichst, dessen Status aus der vorgelagerten Antwort stammt, gib diesen Status über das Argument des Fehlertyps zum Überschreiben des Status weiter, statt den Fehlertyp aufzugeben.
## Streng typisiert bleiben und nur Kommentare schreiben, die nützlich bleiben
- Installiere die Prüfhaken des Repositorys, die vor dem Einchecken greifen, und führe sie über alle Dateien aus, bevor du eine Änderung vorschlägst.
- Halte sowohl im Backend als auch im Frontend alles streng typisiert. Untypisierte Schlupflöcher sind keine zulässige Abkürzung.
- Halte Kommentare kurz und beschränke sie auf Angaben, die langfristig relevant bleiben. Schreibe keine Kommentare, die die gerade laufende Änderung nacherzählen, etwa was soeben hinzugefügt, entfernt oder umgebaut wurde; sie werden in dem Moment zu Rauschen, in dem die Änderung übernommen wird.
## Datenbankmigrationen von Hand schreiben, für das Standard- und das private Schema
- Erzeuge die Revisionsdatei mit dem Migrationswerkzeug und schreibe den Inhalt der Migration anschließend von Hand in die dabei erzeugte Datei. Verlasse dich nicht auf die automatische Erzeugung, um die Absicht auszudrücken.
- Bei mandantenfähigen Installationen muss die Migration zusätzlich zur Standardkonfiguration auch gegen die Konfiguration des privaten Schemas angewendet werden; dieselbe Unterscheidung gilt beim Erstellen der Revision.
- Behandle die Migration als Teil der zu prüfenden Änderung und nicht als nachträglichen Einfall, der hinterher nachgereicht wird.
## Die eine Testart wählen, die die Änderung belegt, mit wenigen Attrappen
Es gibt vier Stufen. Bevorzuge die realitätsnäheren Stufen gegenüber umfangreichen Attrappen und wähle diejenige, die das Verhalten tatsächlich belegt.
- Modultests setzen voraus, dass kein Dienst erreichbar ist, und bilden jede Interaktion mit der Außenwelt durch Attrappen nach. Schreibe sie nur für komplexe, isolierte Module, deren Logik es wert ist, für sich allein festgeschrieben zu werden.
- Modultests mit echten Abhängigkeiten setzen voraus, dass die externen Abhängigkeiten laufen – Datenbank, Zwischenspeicher, Objektspeicher, Suchindex, ausgehendes Netzwerk –, die Container der Anwendung dagegen nicht. Funktionen werden direkt aufgerufen, und ausgewählte Komponenten dürfen weiterhin durch Attrappen ersetzt werden. Nutze sie, um Attrappen möglichst gering zu halten und dabei die Möglichkeit zu behalten, unzuverlässiges Verhalten zu steuern oder zu überprüfen, dass ein interner Aufruf mit bestimmten Argumenten erfolgt ist – was ein reiner Integrationstest nicht leisten kann.
- Integrationstests laufen gegen eine echte Installation und verwenden keinerlei Attrappen. Bevorzuge sie und weiche auf Modultests mit echten Abhängigkeiten aus, wenn Attrappen oder eine interne Überprüfung wirklich nötig sind.
- Browsergesteuerte Tests ergänzen die vollständige Installation um den Webserver. Nutze sie für Verhalten, das ein erhebliches Zusammenspiel zwischen Frontend und Backend erfordert.
Teste nicht übermäßig. Eine bestimmte Änderung braucht in der Regel eine Testart, nicht alle vier.
## Beim Schreiben von Integrationstests vorhandene Fixtures und Hilfsfunktionen nutzen
- Lies vor dem Schreiben eines Integrationstests die Testkonfiguration im Wurzelverzeichnis nach verfügbaren Testvorrichtungen und das Verzeichnis der gemeinsamen Hilfsmittel nach Hilfsfunktionen durch.
- Bevorzuge die Verwaltungshilfsfunktionen aus diesen Hilfsmitteln gegenüber direkten Endpunktaufrufen mit einer rohen HTTP-Bibliothek, und bevorzuge Testvorrichtungen gegenüber dem Aufruf der Hilfsfunktionen von Hand. Einen Administrator von Hand anzulegen, obwohl es eine Testvorrichtung für Administratoren gibt, dupliziert die Einrichtung und entfernt sich vom Rest der Testsammlung.
- Tests werden auf Ebene der Verzeichnisse parallelisiert; Dateien innerhalb eines Verzeichnisses dürfen deshalb nicht von gemeinsam genutztem veränderlichem Zustand abhängen.
- Wenn ein Test einen echten Modellaufruf macht, nutze die günstige und schnelle Stufe des jeweiligen Anbieters statt eines Spitzenmodells. Die Testkosten wachsen mit der Testsammlung, und das, was überprüft wird, hängt nicht von der Stärke des Modells ab.
- Übernimm die Form eines vorhandenen, vorbildlichen Tests derselben Kategorie, statt eine neue Struktur zu erfinden.
## Die Protokolle jedes Dienstes lesen, bevor man die Fehlerursache errät
- Wenn du Integrationstests schreibst oder das laufende System von Hand bedienst, lies die Fehlersuchprotokolle der einzelnen Dienste im Protokollverzeichnis. Jeder Dienst schreibt seine Ausgabe fortlaufend dorthin.
- Lies die Protokolle, bevor du eine Theorie über einen Fehler bildest. Eine unbeteiligte Ursache, etwa ein Dienst, der nicht läuft, sieht genauso aus wie ein echter Defekt, solange das Protokoll nicht gelesen wurde.
## API-Schlüssel aus dem Repository heraushalten und neue Endpunkte schützen
- Übernimm niemals API-Schlüssel oder Geheimnisse in das Repository.
- Speichere Zugangsdaten für Integrationen über den verschlüsselten Zugangsdatenspeicher, niemals in einfacher Konfiguration.
- Halte dich beim Hinzufügen einer Funktion an die etablierten Muster der rollenbasierten Zugriffssteuerung. Ein neuer Endpunkt erbt standardmäßig keinen Schutz.
- Prüfe Eingaben an der Grenze mit Schemamodellen.
- Verwende parametrisierte Abfragen, damit Einschleusung konstruktionsbedingt unmöglich ist, und setze eine Abfrage niemals durch Aneinanderhängen von Zeichenketten zusammen.
## Jeden KI-Modellaufruf für die Ablaufverfolgung mit einem registrierten Vorgangsnamen markieren
Jeder Aufruf eines Sprachmodells, eines Einbettungsmodells, eines Neusortierungsmodells, eines Bildgenerators, einer Sprachkomponente oder eines Absichtsklassifikators muss ein Verfolgungssegment für die Generierung öffnen, das mit einem Wert aus dem zentralen Ablaufregister gekennzeichnet ist. Verwende die Hülle, die zum Aufrufweg passt: eine für Aufrufe über die Modellabstraktion, eine andere für direkte Anbieter- oder HTTP-Aufrufe, die sie umgehen.
- Füge einen neuen Wert im Register hinzu, bevor du eine neue Operation instrumentierst. Übergib niemals eine rohe Zeichenkette als Kennzeichnung.
- Kennzeichnungen benennen die Operation, etwa Neusortierung von Suchergebnissen oder Bildbearbeitung, nicht den Anbieter. Der Anbieter gehört in die Metadaten der Modellkonfiguration.
- Die automatische Ausweichlogik gibt ungekennzeichnete Wächterwerte für Aufrufe aus, die ohne ausdrückliches Verfolgungssegment bei der Abstraktion ankommen. Diese Wächterwerte sind in den Übersichtsanzeigen sichtbar und bedeuten, dass die Instrumentierung fehlt. Behebe das an der Aufrufstelle, statt dich auf diese Ausweichlogik zu verlassen.
## Erst den Code erkunden, dann einen Plan ohne Zeitplan und ohne Code schreiben
Recherchiere, bevor du schreibst. Erkunde zuerst die betreffenden Teile der Codebasis; ein aus Annahmen geschriebener Plan ist schlechter als gar kein Plan.
Ein Plan enthält mindestens diese Bestandteile:
- Zu behandelnde Punkte: was die Änderung bewirken soll.
- Wichtige Hinweise: bei der Recherche gefundene Dinge, die für die Umsetzung von Bedeutung sind.
- Umsetzungsstrategie: das grobe Vorgehen, mit dem die Änderung zustande kommt.
- Tests: welche Tests das richtige Verhalten überprüfen – bewusst ausgewählt und auf das Nötigste beschränkt.
Nimm keinen Abschnitt zum Zeitplan auf und behandle auch keine Schritte zum Zurückrollen. Schreibe im Rahmen des Plans keinen Code; halte ihn grob, wobei der Verweis auf bestimmte Dateien oder Funktionen nützlich ist. Dies ist eine Mindestliste, ergänze also mehr, wenn es hilft.
## Vor der Arbeit in einem Teilprojekt dessen eigene Regeln lesen
- Die Vorgaben im Wurzelverzeichnis decken die gemeinsamen Belange ab. Jedes Teilprojekt führt neben seinem Code ein eigenes Standarddokument, und dieses Dokument regelt seinen eigenen Verzeichnisbaum.
- Lies das jeweils zuständige Dokument, bevor du in diesem Bereich arbeitest. Gehe nicht davon aus, dass die Regeln eines Clients für einen anderen gelten: Ein mobiler Client ohne Dokumentobjektmodell, mit Gestaltungsbausteinen, deren Abstandswerte absolut sind statt einer relativen Stufenskala zu folgen, und mit eigenen Bausteinen für Wegeführung und Ansichten folgt anderen Regeln als ein Webclient.
- Weiter gefasste Entwicklungspraktiken stehen im Beitragsleitfaden des Repositorys. Lies ihn und befolge ihn zusätzlich zu diesem Dokument.
