Codierungskonventionen für Next.js-Web-Apps
Wenden Sie diese Konventionen auf die angeforderte Arbeit an. Explizite Benutzeranweisungen überschreiben jede Regel oder Vorgabe in dieser Skill. Bewahren Sie bestehende Produktanforderungen und Integrationen; die Anwendung dieser Skill autorisiert keine nicht damit zusammenhängende Migration oder die Installation jeder optionalen Abhängigkeit.
Überprüfen Sie vor der Implementierung Projektanweisungen, installierte Versionen und bestehende Konventionen. Lesen Sie die relevante installierte Next.js-Dokumentation, sofern verfügbar, insbesondere node_modules/next/dist/docs/; andernfalls konsultieren Sie die versionsgerechte offizielle Dokumentation. Gehen Sie nicht von Framework-APIs einer anderen Version aus.
Standardeinstellungen und bedingte Funktionen
| Bereich | Standard | Überschreibung oder Aktivierungsregel |
|---|---|---|
| Framework | Next.js App Router und strenges TypeScript | Berücksichtigen Sie die gewählten Versionen des Projekts und explizite Benutzerentscheidungen. |
| Komponenten | Base UI mit Tailwind CSS, gekapselt in lokale Komponenten | Unterstützen Sie Radix, shadcn/ui oder eine andere angeforderte Bibliothek. Behalten Sie die gleiche Komponentenorganisation bei. |
| Varianten | class-variance-authority und ein Tailwind-bewusster Klassenkombinierungs-Helfer | Verwenden Sie ein etabliertes Äquivalent wieder. |
| API-Transport | Axios hinter benutzerdefinierten APIClient und ServerAPIClient Abstraktionen | Ein bestehender benutzerdefinierter Client, fetch oder ein anderer angeforderter Transport ist gültig. Halten Sie Verträge transportunabhängig. |
| Validierung | Zod-Schemas mit abgeleiteten TypeScript-Typen | Standardmäßig an externen Datengrenzen erforderlich; nur auf explizite Benutzeranweisung ändern. |
| Remote-Client-Daten | TanStack Query mit einem gemeinsamen Query-Wrapper | Verwenden Sie ein angefordertes Äquivalent wieder. |
| Gemeinsamer interaktiver Zustand | Zustand | Verwenden Sie den lokalen React-Status für den Zustand, der einer Komponente gehört. Beachten Sie explizite Alternativen. |
| Authentifizierung | Anbieterneutraler E-Mail-OTP-Ablauf, wenn Authentifizierung angefordert wird | Folgen Sie dem ausgewählten Anbieter und den angeforderten Anmeldemethoden; wählen oder stellen Sie keinen Anbieter implizit bereit. |
| Cross-Tab-Synchronisation | Aktiviert für relevante gemeinsame Mutationsereignisse | Optional und auf Anfrage entfernbar. Fügen Sie Ereignisse nur dort hinzu, wo Cross-Tab-Konsistenz nützlich ist. |
| Protokollierung und Tracing | Folgen Sie einem vorhandenen Protokollierungssystem | Wenn keines vorhanden ist, führen Sie keine Protokollierungs-/Trace-Infrastruktur ein, schlagen Sie keine vor und erwähnen Sie sie nicht, es sei denn, dies wird angefordert. |
| Mock-Daten und Simulation | Aus | Nur hinzufügen, wenn der Benutzer Mock-Daten oder Entwicklungs-/Testsimulation anfordert. |
| Entwicklungs-Tooling | Separate Entwicklungsmodule | Fügen Sie Tools nur hinzu, wenn sie relevant oder angefordert sind; kein vorgeschriebenes Tool oder Overlay. |
Wählen Sie Standardeinstellungen, wenn eine Entscheidung getroffen werden muss; fragen Sie nicht nach jeder Standardeinstellung. Führen Sie Authentifizierung, Zustandspeicher, Synchronisation oder Infrastruktur nicht in Funktionen ein, die diese nicht benötigen.
Erforderliche Ordnerstruktur
Verwenden Sie diese Organisation für neuen Code. Erstellen Sie Verzeichnisse, wenn ihre Aufgaben notwendig werden, anstatt das Projekt mit leeren Platzhaltern zu füllen. Verschieben Sie in einem bestehenden Projekt ohne Migrationsanforderung keine nicht zusammenhängenden Dateien.
src/
├── app/ Routen, Layouts, API-Endpunkte
├── components/
│ ├── ui/ Gemeinsame UI-Primitive
│ ├── standalone/ Wiederverwendbare Domain-Komponenten
│ ├── pages/<page>/ Seiten-spezifische Komponenten
│ └── <feature>/ Funktions-Subsysteme
├── controllers/
│ ├── client/<domain>/ Browser-API-Aufrufe
│ └── server/<domain>/ Server-seitige API-Aufrufe
├── providers/ React-Context-Anbieter
├── stores/ Zustand-Stores
├── hooks/ Gemeinsame React-Hooks
├── helpers/ Authentifizierung/Zugriff und andere Workflows
├── lib/ API-Clients, Cache, Protokollierung, Synchronisation
├── db/ Datenbank/Redis-Clients
├── utils/ Kleine Hilfsfunktionen und Konstanten
└── assets/icons/ Quell-SVGs
Ordnernamen für Infrastruktur beschreiben die Platzierung, nicht erforderliche Dienste. Keine Datenbank, Redis, Cache oder Protokollierungsstack wird durch diese Struktur impliziert.
- Organisieren Sie Domain-Code unter diesen Verantwortungsordnern; vermeiden Sie es, sie durch eine andere Top-Level-Architektur zu ersetzen.
- Verwenden Sie PascalCase für Komponentendateien,
useSomething.tsfür Hooks (.tsxnur wenn JSX vorhanden ist) und camelCase für Operationsdateien wieupdateName.ts. - Verwenden Sie beschreibende Domain- und Funktionsverzeichnisse. Behalten Sie Framework-Dateinamen wie
page.tsx,layout.tsxundroute.tsunverändert bei. - Verwenden Sie
index.ts, um Controller-Namespaces zu assemblieren, undindex.tsxals Einstiegspunkt einer mehrteiligen Komponente. - Verwenden Sie
@/für Importe, die insrcverwurzelt sind; verwenden Sie relative Importe für nahe interne Geschwister. Verwenden Sieimport typefür reine Typ-Abhängigkeiten. - Vermeiden Sie temporäre Kopien, Backup-Ordner, doppelte Implementierungen und Auffangdateien mit unklaren Verantwortlichkeiten.
Routen und Komponentenzusammensetzung
Halten Sie app/ fokussiert auf Routing, Layout-Zusammensetzung, Request-Handling und anfängliches Datenladen. Verwenden Sie Routengruppen wie (auth), (no-auth) und (settings), wenn ihre Layout-Grenzen nützlich sind. Ein Routengruppenname allein bietet keinen Zugriffsschutz.
Halten Sie Seiten dünn: Laden Sie initiale Daten, treffen Sie Seitenebenen-Entscheidungen und rendern Sie Komponenten aus components/pages/<page>/ oder dem relevanten Funktionsverzeichnis. Server-Komponenten sind die Standardeinstellung; führen Sie Client-Grenzen für Browser-Status, Ereignisse und APIs ein.
Komponentenplatzierung:
components/ui/: domainunabhängige Primitive und Wrapper um die gewählte UI-Bibliothek.components/standalone/: wiederverwendbare Domain-Steuerelemente, die seiten- oder funktionsübergreifend verwendet werden.components/pages/<page>/: Komponenten, die für eine Seite spezifisch sind.components/<feature>/: größere Subsysteme, die routenübergreifend gemeinsam genutzt werden, wie Navigation oder eine Befehlsschnittstelle.
Teilen Sie komplexe Komponenten in fokussierte Dateien auf. Dies ist eine Kernkonvention. Eine substanzielle Komponente sollte ein Verzeichnis mit einem index.tsx-Einstiegspunkt für die Zusammensetzung und benannten unterstützenden Komponenten, Tabs, Zeilen, Hooks und Typen nach Bedarf haben. Akkumulieren Sie nicht mehrere substanzielle Subkomponenten und nicht zusammenhängende Effekte in einer Datei. Teilen Sie nach Verantwortlichkeit auf, nicht nach einer willkürlichen Zeilengrenze; vermeiden Sie die Fragmentierung von trivialem Markup.
Halten Sie Interaktionsmechaniken in funktionslokalen Hooks oder fokussierten Handler-Komponenten: Tastaturnavigation, Auswahl, Ereignisabonnements, Drag-Verhalten und Ansichtskoordination. Verschieben Sie einen Hook nach src/hooks/, wenn er gemeinsam genutzt wird. Halten Sie Eingabe-Shortcuts so begrenzt, dass sie nicht mit editierbaren Steuerelementen interferieren; bereinigen Sie Listener beim Unmount.
Kapseln Sie die primitive Bibliothek lokal und exponieren Sie zusammensetzbare Teile wie Dialog, DialogTrigger, DialogContent und DialogTitle. Bewahren Sie zugängliche Semantik, Fokus-Verhalten und die tatsächliche Zusammensetzungs-API der Bibliothek. Kopieren Sie keine Radix-spezifischen Props in Base-UI-Wrapper, ohne die Kompatibilität zu überprüfen.
Typisieren Sie Wrapper-Props vom zugrunde liegenden Primitiv oder nativen Element und fügen Sie nur benötigte benutzerdefinierte Props hinzu. Verwenden Sie typisierte Varianten für Größe, Betonung und Zustand. Führen Sie Consumer-Klassen vorhersagbar zusammen und bewahren Sie die Ref-Unterstützung gemäß den installierten React/Bibliotheks-APIs.
Verwenden Sie semantische CSS-Variablen, die mit Tailwind-Utilities verbunden sind. Halten Sie Themenwerte zentralisiert und Komponentenvarianten lokal. Diese Skill schreibt die Styling-Organisation vor, kein visuelles Thema, Abstandsskala oder Produktdesign.
Setzen Sie relevante Kontextanbieter in app/providers.tsx zusammen; halten Sie ihre Implementierungen in providers/. Halten Sie Browser-spezifische Anbieter hinter einer expliziten Client-Grenze und vermeiden Sie es, die Initialisierung von Entwicklungs-Tools mit normalen Anbieterverantwortlichkeiten zu vermischen.
Controller und HTTP-Clients
Verwenden Sie eine Operation pro Datei unter controllers/client/<domain>/ oder controllers/server/<domain>/. Bauen Sie verschachtelte Namespace-Objekte durch index.ts-Dateien zusammen, zum Beispiel:
ClientController.org.members.list()
ClientController.profile.updateName(input)
ServerController.org.info()
Controller stellen typisierte Operationen und Endpunktkonstruktion bereit. Komponenten sollten Controller aufrufen, anstatt URLs oder Transportkonfigurationen zusammenzubauen. Controller bleiben dünn; legen Sie wiederverwendbare Workflow-Logik in helpers/ und Infrastruktur in lib/ ab.
Halten Sie Browser- und Server-HTTP-Clients getrennt:
lib/APIClient.ts: browsersicherer Transport, Query/Body-Serialisierung, Antwortverarbeitung und Unterstützung für Abbrüche.lib/ServerAPIClient.ts: serverseitiger Transport, vertrauenswürdige Basis-URL und anforderungsspezifische Anmeldeinformationen/Sitzungskontext.- Halten Sie Server-Geheimnisse und Server-spezifische Abhängigkeiten aus Browser-Importen heraus. Bewahren Sie niemals benutzerspezifische Anmeldeinformationen in einem gemeinsam genutzten, veränderbaren Singleton.
- Wenn Server-Controller Anwendungsendpunkte aufrufen, leiten Sie nur die erforderlichen Anmeldeinformationen an vertrauenswürdige Ziele weiter. Vertrauen Sie einem vom Aufrufer bereitgestellten Identitätsheader nicht als Authentifizierung.
- Normalisieren Sie Transportfehler, Nicht-2xx-Antworten und Anwendungsfehler konsistent. Bewahren Sie aussagekräftige Status/Code-Informationen. Verwandeln Sie fehlgeschlagene Anfragen nicht in erfolgreiche leere Daten.
- Unterstützen Sie
AbortSignaldurch Controller- und Transportebenen. Ein Abbruch sollte keine Fehlerbenachrichtigungen oder Wiederholungen auslösen.
API-Schemas, Verträge und Handler
Zod-Schemas sind die Standardquelle der Wahrheit für Eingaben. Definieren Sie spezifische Schemas für Body-, Query- und Pfadparameter, einschließlich Formate, zulässige Werte, Längen-/Bereichsgrenzen, Optionalität und bewusste Koerzion. Validieren Sie vor der Verwendung externer Werte. Vermeiden Sie z.any(), breite Records, Casts und Nicht-Null-Assertionen als Ersatz für Verträge. Behandeln Sie unbekannte Schlüssel für jede Grenze bewusst.
Kollokieren Sie methodenspezifische Schemas und exportierte Request/Query/Response-Typen standardmäßig mit der Route. Leiten Sie Request-Typen mit z.infer ab; definieren Sie explizite Response-Verträge und verwenden Sie Response-Schemas, wo Laufzeitvalidierung erforderlich ist. Verwenden Sie diese Typen in Controllern und Komponenten wieder, anstatt sie neu zu deklarieren. Wenn Laufzeitverträge mit Browser-Code geteilt werden müssen oder Routenmodul-Exporteinschränkungen dies erfordern, verwenden Sie ein benachbartes schema.ts oder types.ts und reine Typ-Importe, sodass die Server-Implementierung niemals in das Client-Bundle gezogen wird.
Verwenden Sie einen konsistenten, diskriminierten Antwortumschlag:
type APIResponse<T> =
| { success: true; data: T; error: null }
| {
success: false;
data: null;
error: { code: string; message: string; details?: unknown };
};
Schränken Sie details auf explizite, sichere Validierungs-/Fehlerdetailtypen ein, wo sie verwendet werden. Halten Sie Fehler und HTTP-Status konsistent über alle Zweige hinweg. Legen Sie keine internen Ausnahmen oder Stacktraces in Produktionsantworten offen.
Organisieren Sie Multi-Methoden-Routen in methodenspezifische Schema-/Typen-Abschnitte und Funktionen wie get_request und post_request. Exportieren Sie Handler durch withAPIRequestHandler() in lib/api/APIRequestHandler.ts.
Pflegen Sie lib/api/error/ mit einer APIError-Klasse und einem domainorganisierten, typisierten Katalog von Fehlercodes, Nachrichten und Status. Der gemeinsame Handler bildet Validierungsfehler, Domain-Fehler und unerwartete Fehler auf denselben Antwortvertrag ab. Integrieren Sie die Protokollierung nur unter der oben genannten Protokollierungsbedingung.
Extrahieren Sie wiederholte Organisationssuche, Identitätsauflösung, Query-Parsing und Zugriffs-Workflows in helpers/. Halten Sie kleine reine Transformationen und Konstanten in utils/. Teilen Sie größere Integrationen in fokussierte Workflow-Dateien auf; die Route sollte diese Schritte orchestrieren, anstatt die gesamte Integration zu enthalten.
Datenabruf und Zustand
Laden Sie anfängliche Seitendaten durch Server-Controller, wenn angemessen, und übergeben Sie typisierte, serialisierbare Props an interaktive Komponenten. Verwenden Sie Promise.all für unabhängige Anfragen; bewahren Sie die Reihenfolge für abhängige Operationen.
Verwenden Sie TanStack Query für Remote-Client-Daten. Stellen Sie gemeinsame Standardeinstellungen und einen useApiQuery-Wrapper bereit, der den API-Umschlag entpackt, Fehler propagiert und das Query-Abbruchsignal weiterleitet. Query-Schlüssel müssen relevante Identitäts-/Ressourcen-/Filtereingaben enthalten. Begrenzen Sie serverseitige Query-Clients pro Anfrage; invalidieren oder aktualisieren Sie betroffene Query-Einträge nach Mutationen.
Verwenden Sie funktionsspezifische Zustand-Stores für gemeinsamen interaktiven Zustand wie Auswahl, Filter, Panels und Befehlszustand. Abonnieren Sie einzelne Slice oder verwenden Sie flache Auswahl für gruppierte Werte. Halten Sie Setter/Aktionen explizit und setzen Sie den Zustand zurück, wenn sich die zugehörige Ressource ändert. Vermeiden Sie es, eine zweite unabhängige Kopie von Remote-Daten in Zustand zu führen, wenn Query sie bereits besitzt.
Verwenden Sie lokalen Zustand für komponenteneigene Eingaben, Dirty-Status, Validierungsmeldungen und Speicherzustand. Verhindern Sie doppelte Übermittlungen und bewahren Sie Benutzereingaben bei Fehlern. Es gibt keine erforderliche Formularbibliothek.
Brechen Sie überholte Such-/Filteranfragen ab und brechen Sie bei der Bereinigung ab. Schützen Sie sich davor, dass abgeschlossene Vorgänge eine neue Ressource aktualisieren. Klassifizieren Sie nur tatsächliche Abbrüche als solche; verschlucken Sie Netzwerkfehler nicht stillschweigend.
Für große Listen wenden Sie Virtualisierung und Paginierung an, wenn nützlich, mit Lade-, Leer-, Fehler-, Wiederholungs- und End-of-List-Zuständen. Setzen Sie Paginierung und Auswahl entsprechend zurück, wenn sich die Ressource/Filter ändert. Halten Sie die Tastaturnavigation konsistent mit virtualisierten Zeilen.
Optionale Cross-Tab-Synchronisation
Aktivieren Sie die Synchronisation für relevante gemeinsame Mutationen standardmäßig, es sei denn, der Benutzer deaktiviert sie. Fügen Sie sie nicht zu isoliertem Zustand ohne Synchronisationsbedarf hinzu.
Verwenden Sie ein typisiertes Ereignisregister in lib/local-sync/, Domain-Ereignisschemas unter events/ und einen gemeinsamen hooks/useLocalSync.ts-Hook. Leiten Sie Payload-Typen von Zod ab und validieren Sie sowohl ausgehende als auch eingehende Nachrichten.
Eine Storage-Ereignis-Implementierung sollte andere Tabs und Same-Tab-Listener benachrichtigen, transiente Ereignis-Payloads anstelle von persistentem Anwendungszustand verwenden und Listener bereinigen. Ein vorhandener äquivalenter Transport ist akzeptabel. Verhindern Sie Echo-Schleifen und doppelte Verarbeitung; synchronisieren Sie keine Geheimnisse. Ereignisse sollten den kanonischen Zustandsbesitzer aktualisieren oder invalidieren. Cross-Tab-Ereignisse sind UI-Koordination, keine Autorisierung oder garantierte Zustellung.
Authentifizierung und Autorisierung
Wenden Sie diesen Abschnitt an, wenn Authentifizierung im Umfang enthalten ist. Halten Sie die Implementierung anbieterneutral und passen Sie sie an den ausgewählten Dienst oder das benutzerdefinierte Backend an.
- Für die E-Mail-OTP-Authentifizierung trennen Sie Senden-Code, Verifizieren-Code und Abmelden in separate Vorgänge. Validieren Sie die E-Mail-Adresse und OTP-Eingaben mit Zod. Verwenden Sie Sitzungs-Tokens mit angemessener Gültigkeitsdauer; halten Sie das Token nicht im lokalen Speicher des Browsers fest. Aktualisieren Sie Tokens über einen geeigneten Mechanismus.
- Verwenden Sie Middleware, um geschützte Routen zu sichern, Benutzer zu nicht authentifizierten Bereichen umzuleiten und Token-Prüfungen vor dem Rendern von Seiten durchzuführen. Halten Sie Middleware-Leistungskritisch und vermeiden Sie darin teure Datenbankabfragen.
- Stellen Sie den aktuellen Benutzer und seine Sitzung über einen React-Kontext bereit. Verwenden Sie einen zentralen Authentifizierungs-Workflow in
helpers/. - Erzwingen Sie die Autorisierung auf API-Ebene; vertrauen Sie nicht nur auf das Ausblenden von UI-Elementen.
Tipps zur Code-Qualität und -Struktur
- Integrieren Sie Linting und Formatierung über ESLint und Prettier mit den empfohlenen Konfigurationen für Next.js und TypeScript.
- Ein Tool zur Verwaltung konsistenter Import-Reihenfolge ist nützlich (durch
eslint-plugin-import) - Vermeiden Sie zirkuläre Importe durch klare Hierarchien:
components→hooks,utils→controllers→lib. - Behandeln Sie Fehler auf der nächsthöheren geeigneten Ebene; fangen Sie Fehler nicht ab, ohne sie zu protokollieren oder dem Benutzer zu melden.
- Verwenden Sie konsistente asynchrone Muster. Bevorzugen Sie
async/awaitgegenüber expliziten Promise-Ketten. Behandeln Sie Fehler mit try/catch auf einer sinnvollen Granularitätsebene. - Dokumentieren Sie komplexe Logik, unerwartete Verhaltensweisen und öffentliche APIs mit JSDoc-Kommentaren. Aktualisieren Sie die Dokumentation mit Code-Änderungen.
- Führen Sie automatisierte Tests für kritische Pfade durch: Komponenten-Rendering, API-Integration und Workflow-Fehlerfälle.
Migration oder Übernahme dieser Konventionen
Wenn Sie diese Skill auf ein bestehendes Projekt anwenden:
- Bewerten Sie die bestehende Projektstruktur und -konfiguration, bevor Sie Änderungen vorschlagen
- Schlagen Sie eine Migration nur vor, wenn der Benutzer dies ausdrücklich wünscht oder die aktuellen Konventionen nicht funktionieren
- Führen Sie die Migration schrittweise durch und halten Sie das Projekt während des gesamten Prozesses funktionsfähig
- Bewahren Sie die bestehenden Produktanforderungen, Integrationen und Dienste
- Dokumentieren Sie alle Abweichungen von den Konventionen, die aus der Migration resultieren