Code-Standards und Konventionen
Codierungsstandards, Arbeitsbereichsgrenzen und Konventionen für die Mitarbeit an LibreChat.
Arbeitsbereich-Grenzen
LibreChat ist ein Monorepo. Jeder neue Code sollte auf den korrekten Workspace ausgerichtet sein:
| Arbeitsbereich | Sprache | Seite | Zweck |
|---|---|---|---|
/api | JS (Legacy) | Backend | Express-Server — Änderungen hier minimieren |
/packages/api | TypeScript | Backend | Neuer Backend-Code befindet sich hier (nur TS, wird von /api konsumiert) |
/packages/data-schemas | TypeScript | Backend | Datenbankmodelle/-schemas und datenbankspezifische geteilte Logik |
/packages/data-provider | TypeScript | Geteilt | API-Typen, Endpoints, Data-Service — wird von Frontend und Backend verwendet |
/client | TypeScript/React | Frontend | Frontend SPA |
/packages/client | TypeScript | Frontend | Geteilte Frontend-Dienstprogramme |
- All new backend code must be TypeScript in
/packages/api. - Halten Sie Änderungen an
/apiauf ein absolutes Minimum (schlanke JS-Wrapper, die/packages/apiaufrufen). - Datenbankspezifische gemeinsame Logik gehört in
/packages/data-schemas. - Frontend/Backend-geteilte API-Logik (endpoints, types, data-service) befindet sich in
/packages/data-provider. - Erstellen Sie den gesamten kompilierten Code vom Projektstammverzeichnis aus:
npm run build. - Erstellen Sie den gemeinsam genutzten data-provider-Code nach API-/Typänderungen neu:
npm run build:data-provider.
Allgemeine Richtlinien
- Verwenden Sie „Clean Code“-Prinzipien: Halten Sie Funktionen und Module klein, befolgen Sie das Single-Responsibility-Prinzip und schreiben Sie ausdrucksstarken sowie lesbaren Code.
- Verwenden Sie aussagekräftige und beschreibende Variablen- und Funktionsnamen.
- Priorisieren Sie die Lesbarkeit und Wartbarkeit von Code gegenüber Kürze.
- Verwenden Sie die bereitgestellten
.eslintrc- und.prettierrc-Dateien für eine konsistente Code-Formatierung. - Beheben Sie alle Formatierungs-Lint-Fehler mithilfe der Auto-Fix-Funktion, sofern verfügbar. Alle TypeScript/ESLint-Warnungen und -Fehler müssen behoben werden.
Benennung und Dateiorganisation
- Verwenden Sie nach Möglichkeit Dateinamen, die aus einem einzigen Wort bestehen, wie
permissions.ts,capabilities.tsoderservice.ts. - Wenn mehrere Wörter benötigt werden, bevorzugen Sie ein einzelnes Verzeichnis, das den Kontext der Datei angibt, wie zum Beispiel
admin/capabilities.tsanstelle vonadminCapabilities.ts. - Lassen Sie das Verzeichnis den Kontext liefern. Bevorzugen Sie
app/service.tsgegenüberapp/appConfigService.ts.
Code-Struktur
- Never-nesting: Verwenden Sie Early Returns, flachen Code und minimale Einrückungen. Unterteilen Sie komplexe Operationen in gut benannte Hilfsfunktionen.
- Funktional zuerst: reine Funktionen, unveränderliche Daten,
map/filter/reduceanstelle von imperativen Schleifen. Greifen Sie nur dann auf OOP zurück, wenn es die Domänenmodellierung oder die Kapselung von Zuständen eindeutig verbessert. - Keine dynamischen Importe, es sei denn, dies ist unbedingt erforderlich.
- Extrahiere wiederkehrende Logik in dedizierte Hilfsfunktionen (DRY). Bevorzuge parametrisierte Helfer, Konstanten, gemeinsame Validatoren, zentralisierte Fehlerbehandlung und gemeinsame Typen gegenüber nahezu identischen Implementierungen.
Iteration und Performance
- Schleifen minimieren — insbesondere bei gemeinsam genutzten Datenstrukturen wie Nachrichten-Arrays, die häufig durchlaufen werden. Jeder zusätzliche Durchlauf summiert sich bei zunehmender Skalierung.
- Fassen Sie aufeinanderfolgende O(n)-Operationen wann immer möglich in einem einzigen Durchlauf zusammen; iterieren Sie niemals zweimal über dieselbe Sammlung, wenn die Arbeit kombiniert werden kann.
- Wählen Sie Datenstrukturen, die die Notwendigkeit von Iterationen reduzieren (z. B.
Map/Setfür Suchvorgänge anstelle vonArray.find/Array.includes). - Vermeiden Sie unnötige Objekterstellung; berücksichtigen Sie Zeit-Raum-Abwägungen.
- Speicherlecks verhindern: Gehen Sie vorsichtig mit Closures um, geben Sie Ressourcen/Event-Listener frei und vermeiden Sie zirkuläre Referenzen.
Typsicherheit
- Verwenden Sie niemals
any. Explizite Typen für alle Parameter, Rückgabewerte und Variablen. unknowneinschränken — vermeiden Sieunknown,Record<string, unknown>undas unknown as T-Assertionen. EinRecord<string, unknown>deutet fast immer auf eine fehlende explizite Typdefinition hin.- Typen nicht duplizieren — prüfen Sie, ob ein Typ bereits im Projekt existiert (insbesondere in
packages/data-provider), bevor Sie einen neuen definieren. Verwenden Sie vorhandene Typen wieder und erweitern Sie diese. - Verwenden Sie Union-Types, Generics und Interfaces auf angemessene Weise.
Kommentare und Dokumentation
- Schreiben Sie selbstdokumentierenden Code; keine Inline-Kommentare, die beschreiben, was der Code tut.
- JSDoc nur für komplexe/nicht offensichtliche Logik oder Intellisense bei öffentlichen APIs.
- Einzeiliges JSDoc für kurze Dokumentationen, mehrzeiliges für komplexe Fälle.
- Vermeiden Sie eigenständige
//Kommentare, sofern dies nicht unbedingt erforderlich ist.
Import-Reihenfolge
Importe sind in drei Abschnitte unterteilt (in dieser Reihenfolge):
- Paketimporte — sortiert nach Zeilenlänge von kurz nach lang (
reactist immer der erste Import). import typeimports — sortiert von der längsten zur kürzesten (zuerst Paket-Typen, dann lokale Typen; die Längensortierung wird zwischen den Untergruppen zurückgesetzt).- Lokale/Projekt-Importe — sortiert von der längsten zur kürzesten.
- Fassen Sie Wertimporte aus demselben Modul so weit wie möglich zusammen.
- Verwenden Sie immer eigenständige
import type { ... }für Typ-Importe; verwenden Sie niemals das Inline-Schlüsselworttypeinnerhalb von Wert-Importen (z. B. istimport { Foo, type Bar }falsch).
Loop-Einstellungen
- Begrenzen Sie Schleifen so weit wie möglich. Bevorzugen Sie Transformationen in einem einzigen Durchlauf und vermeiden Sie es, dieselben Daten mehrfach zu durchlaufen.
for (let i = 0; ...)für leistungsrelevante oder indexabhängige Operationen.for...offür einfache Array-Iteration.for...innur für die Aufzählung von Objekteigenschaften.
Node.js API-Server
API-Design
- Befolgen Sie RESTful-Prinzipien beim Entwurf von APIs.
- Verwenden Sie aussagekräftige und beschreibende Namen für Routen, Controller, Services und Modelle.
- Verwenden Sie für jede Route die entsprechenden HTTP-Methoden (GET, POST, PUT, DELETE).
- Verwenden Sie korrekte Statuscodes und Antwortstrukturen für konsistente API-Antworten (2xx für Erfolg, 4xx für fehlerhafte Anfragen des Clients, 5xx für Serverfehler).
- Verwenden Sie try-catch-Blöcke, um Exceptions abzufangen und ordnungsgemäß zu behandeln.
- Implementieren Sie eine ordnungsgemäße Fehlerbehandlung und geben Sie konsistent geeignete Fehlerantworten zurück.
- Verwenden Sie das im
utils-Verzeichnis enthaltene Protokollierungssystem, um wichtige Ereignisse und Fehler zu protokollieren. - Führen Sie eine JWT-basierte, zustandslose Authentifizierung unter Verwendung der
requireJWTAuth-Middleware durch.
Dateistruktur
Neuer Backend-Code kommt als TypeScript in /packages/api. Das Legacy-Verzeichnis /api folgt dieser Struktur:
Routen
Gibt jede HTTP-Anfragemethode, die zu verwendende Middleware sowie die für jede Route aufzurufende Controller-Funktion an.
- Definieren Sie Routen mithilfe des Express Routers in separaten Dateien für jede Ressource oder logische Gruppierung.
- Verwenden Sie beschreibende Routennamen und halten Sie sich an RESTful-Konventionen.
- Halte Routen prägnant und auf eine einzige Verantwortung fokussiert.
- Stellen Sie allen Routen den
/apiNamespace voran.
Controller
Enthält die Logik für jede Route, einschließlich des Aufrufs der entsprechenden Service-Funktionen und der Rückgabe des passenden Antwort-Statuscodes sowie des JSON-Bodys.
- Erstellen Sie für jede Route eine separate Controller-Datei, um die Request/Response-Logik zu verarbeiten.
- Benennen Sie Controller-Dateien nach der PascalCase-Konvention und hängen Sie „Controller“ an den Dateinamen an (z. B.
UserController.js). - Halten Sie Controller schlank, indem Sie komplexe Vorgänge an Service- oder Model-Dateien delegieren.
Dienste
Enthält komplexe Geschäftslogik oder Vorgänge, die von mehreren Controllern gemeinsam genutzt werden.
- Benennen Sie Service-Dateien nach der PascalCase-Konvention und hängen Sie „Service“ an den Dateinamen an (z. B.
AuthService.js). - Vermeiden Sie eine enge Kopplung von Diensten an bestimmte Modelle oder Datenbanken, um die Wiederverwendbarkeit zu verbessern.
- Behalten Sie das Prinzip der einzigen Verantwortlichkeit (Single Responsibility Principle) innerhalb jedes Dienstes bei.
Modelle
Definiert Mongoose-Modelle zur Darstellung von Datenentitäten und deren Beziehungen.
- Verwenden Sie für Modelldateien und die zugehörigen Collections Namen im Singular und in PascalCase (z. B.
User.jsundusers-Collection). - Fügen Sie nur die notwendigen Felder, Indizes und Validierungen in die Modelle ein.
- Halten Sie Modelle unabhängig von der API-Schicht, indem Sie direkte Referenzen auf request/response-Objekte vermeiden.
Datenbankzugriff (MongoDB und Mongoose)
- Verwenden Sie Mongoose (https://mongoosejs.com) als MongoDB ODM.
- Erstellen Sie separate Model-Dateien für jede Entität und stellen Sie eine klare Trennung der Zuständigkeiten sicher.
- Verwenden Sie die Mongoose-Schema-Validierung, um die Datenintegrität durchzusetzen.
- Gehen Sie effizient mit Datenbankverbindungen um und vermeiden Sie Verbindungslecks.
- Verwenden Sie Mongoose Query Builder, um prägnante und lesbare Datenbankabfragen zu erstellen.
React Client
Allgemeine Best Practices für TypeScript und React
- Nutzen Sie TypeScript best practices, um von statischer Typisierung und verbesserten Werkzeugen zu profitieren.
- Gruppieren Sie zusammengehörige Dateien innerhalb von Feature-Verzeichnissen (z. B.
SidePanel/Memories/). - Benennen Sie Komponenten unter Verwendung der PascalCase-Konvention.
- Verwenden Sie prägnante und beschreibende Namen, die den Zweck der Komponente genau widerspiegeln.
- Teilen Sie komplexe Komponenten bei Bedarf in kleinere, wiederverwendbare Komponenten auf.
- Halte die Rendering-Logik innerhalb von Komponenten minimal.
- Extrahiere wiederverwendbare Teile in separate Funktionen oder Hooks.
- Wenden Sie Prop-Typ-Definitionen mithilfe von TypeScript-Typen oder -Interfaces an.
- Verwenden Sie bei Bedarf eine Formularvalidierung (wir verwenden React Hook Form für die Formularvalidierung und -übermittlung).
Lokalisierung
- Alle für den Client sichtbaren Texte müssen mithilfe des
useLocalize()-Hooks lokalisiert werden. - Aktualisiere nur die englischen Schlüssel in
client/src/locales/en/translation.json(andere Sprachen werden extern automatisiert). - Verwenden Sie semantische Lokalisierungsschlüssel-Präfixe:
com_ui_,com_assistants_usw. - Stellen Sie immer aussagekräftigen Fallback-Text für neue Lokalisierungsschlüssel bereit.
Datendienste
- Erstellen Sie Data-Provider-Hooks in
client/src/data-provider/[Feature]/queries.ts. - Exportieren Sie alle Hooks aus
client/src/data-provider/[Feature]/index.ts. - Füge Feature-Exporte zur Hauptdatei
client/src/data-provider/index.tshinzu. - Verwenden Sie React Query (
@tanstack/react-query) für alle API-Interaktionen. - Implementieren Sie eine ordnungsgemäße Abfragevalidierung (Query Invalidation) bei Mutationen.
- Füge QueryKeys und MutationKeys zu
packages/data-provider/src/keys.tshinzu.
Beim Hinzufügen einer gemeinsamen API-Integration aktualisieren Sie:
packages/data-provider/src/api-endpoints.ts(endpoints)packages/data-provider/src/data-service.ts(Data-Service-Funktionen)packages/data-provider/src/types/queries.ts(TypeScript-Typen)
Leistung
- Priorisieren Sie Speichereffizienz und Geschwindigkeit bei Skalierung.
- Implementieren Sie eine ordnungsgemäße Cursor-Paginierung für große Datensätze.
- Vermeiden Sie unnötige Re-Renders durch korrekte Dependency-Arrays.
- Nutzen Sie die Caching- und Hintergrund-Refetching-Funktionen von React Query.
Testen und Dokumentation
- Schreiben Sie Unit-Tests für alle kritischen und komplexen Funktionalitäten mit Jest.
- Schreibe Integrationstests für alle API-endpoints unter Verwendung von Supertest.
- Schreiben Sie End-to-End-Tests für alle clientseitigen Funktionen mit Playwright.
- Verwenden Sie beschreibende Testfall- und Funktionsnamen, um den Zweck des Tests klar auszudrücken.
- Führen Sie Tests aus ihrem Arbeitsverzeichnis aus:
cd api && npx jest <pattern>,cd packages/api && npx jest <pattern>usw. - Decken Sie Lade-, Erfolgs- und Fehlerzustände für UI-/Datenflüsse ab.
- Verwenden Sie
test/layout-test-utilsfür das Rendern von Komponenten in Frontend-Tests. - Bevorzugen Sie echte Logik gegenüber Mocks. Mocken Sie nur das, was nicht lokal kontrolliert werden kann, wie externe HTTP-APIs, ratenbegrenzte Dienste und nicht-deterministische Systemaufrufe.
- Verwenden Sie Spies, wenn Sie Aufrufe überprüfen müssen, ohne die zugrunde liegende Implementierung zu ersetzen.
- Verwenden Sie
mongodb-memory-serverfür MongoDB-basierte Tests, damit Abfragen und Schema-Validierungen das tatsächliche Datenbankverhalten ausführen.
Wie finden Sie diese Anleitung?