Communitygithub.com

Flutter/Dart Code Review Best Practices

Bibliotheksunabhängige Checkliste für Flutter/Dart Code Reviews, die Widget-Best Practices, State-Management-Muster (BLoC, Riverpod, Provider, GetX, MobX, Signals), Dart-Idiome, Performance, Barrierefreiheit, Sicherheit und saubere Architektur abdeckt.

Was ist Dart Code Review Best Practices?

Diese Fähigkeit bietet eine umfassende, bibliotheksunabhängige Checkliste für Code Reviews von Flutter/Dart-Anwendungen. Sie ist für alle State-Management-Lösungen (BLoC, Riverpod, Provider, GetX, MobX, Signals, ValueNotifier etc.) geeignet. Die Checkliste deckt Bereiche wie allgemeine Projekthygiene, Dart-Sprachfallen, Widget-Best Practices, State-Management-Architektur, Performance-Optimierung, Testing, Barrierefreiheit, plattformspezifische Belange und Sicherheit ab. Sie unterstützt Entwickler und KI-Agenten (wie Claude Code, Cursor, Codex) dabei, konsistente und qualitativ hochwertige Code Reviews durchzuführen, indem sie spezifische Prüfpunkte und Anti-Patterns beschreibt. Die Fähigkeit ist besonders nützlich, um die Einhaltung von Best Practices sicherzustellen und häufige Fehler in Flutter/Dart-Codebasen zu identifizieren.

Funktioniert mit~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/flutter-dart-code-review

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Flutter/Dart Code-Review Best Practices

Umfassende, bibliotheksunabhängige Checkliste für die Überprüfung von Flutter/Dart-Anwendungen. Diese Prinzipien gelten unabhängig davon, welche State-Management-Lösung, Routing-Bibliothek oder DI-Framework verwendet wird.


1. Allgemeine Projekthygiene

  • Das Projekt folgt einer konsistenten Ordnerstruktur (Feature-first oder Layer-first)
  • Korrekte Trennung der Belange: UI, Geschäftslogik, Datenebenen
  • Keine Geschäftslogik in Widgets; Widgets sind rein präsentativ
  • pubspec.yaml ist sauber – keine ungenutzten Abhängigkeiten, Versionen sind angemessen fixiert
  • analysis_options.yaml enthält ein strenges Lint-Set mit aktivierten strengen Analyzer-Einstellungen
  • Keine print()-Anweisungen im Produktionscode – verwenden Sie dart:developer log() oder ein Logging-Paket
  • Generierte Dateien (.g.dart, .freezed.dart, .gr.dart) sind aktuell oder in .gitignore
  • Plattformspezifischer Code ist hinter Abstraktionen isoliert

2. Dart-Sprachfallen

  • Implizites dynamic: Fehlende Typannotationen, die zu dynamic führen – aktivieren Sie strict-casts, strict-inference, strict-raw-types
  • Nullsicherheitsmissbrauch: Übermäßiger ! (Bang-Operator) anstelle von korrekten Null-Prüfungen oder Dart 3 Pattern Matching (if (value case var v?))
  • Typ-Promotion-Fehler: Verwendung von this.field, wo die lokale Variablen-Promotion funktionieren würde
  • Zu breites Fangen: catch (e) ohne on-Klausel; geben Sie immer Ausnahmetypen an
  • Fangen von Error: Error-Subtypen weisen auf Fehler hin und sollten nicht gefangen werden
  • Unbenutztes async: Funktionen, die mit async markiert sind, aber nie await verwenden – unnötiger Overhead
  • late-Übernutzung: late wird verwendet, wo nullable oder Konstruktor-Initialisierung sicherer wäre; verzögert Fehler zur Laufzeit
  • String-Konkatenation in Schleifen: Verwenden Sie StringBuffer anstelle von + für iterative String-Erstellung
  • Veränderlicher Zustand in const-Kontexten: Felder in Klassen mit const-Konstruktor sollten nicht veränderlich sein
  • Ignorieren von Future-Rückgabewerten: Verwenden Sie await oder rufen Sie explizit unawaited() auf, um die Absicht zu signalisieren
  • var wo final funktioniert: Bevorzugen Sie final für lokale Variablen und const für Compile-Zeit-Konstanten
  • Relative Imports: Verwenden Sie package:-Imports für Konsistenz
  • Offengelegte veränderliche Sammlungen: Öffentliche APIs sollten unveränderliche Ansichten zurückgeben, nicht rohe List/Map
  • Fehlendes Dart 3 Pattern Matching: Bevorzugen Sie switch-Ausdrücke und if-case gegenüber ausführlichen is-Prüfungen und manuellem Casting
  • Wegwerf-Klassen für mehrere Rückgabewerte: Verwenden Sie Dart 3 Records (String, int) anstelle von einmaligen DTOs
  • print() im Produktionscode: Verwenden Sie dart:developer log() oder das Logging-Paket des Projekts; print() hat keine Log-Level und kann nicht gefiltert werden

3. Widget-Best Practices

Widget-Zerlegung:

  • Kein einzelnes Widget mit einer build()-Methode, die ~80-100 Zeilen überschreitet
  • Widgets werden sowohl nach Kapselung als auch nach Änderungsverhalten (Rebuild-Grenzen) aufgeteilt
  • Private _build*()-Hilfsmethoden, die Widgets zurückgeben, werden in separate Widget-Klassen extrahiert (ermöglicht Element-Wiederverwendung, const-Weitergabe und Framework-Optimierungen)
  • Stateless Widgets werden gegenüber Stateful bevorzugt, wenn kein veränderlicher lokaler Zustand benötigt wird
  • Extrahierte Widgets befinden sich in separaten Dateien, wenn sie wiederverwendbar sind

Const-Verwendung:

  • const-Konstruktoren werden wo immer möglich verwendet – verhindert unnötige Rebuilds
  • const-Literale für Sammlungen, die sich nicht ändern (const [], const {})
  • Der Konstruktor wird als const deklariert, wenn alle Felder final sind

Key-Verwendung:

  • ValueKey wird in Listen/Grids verwendet, um den Zustand bei Neuanordnungen zu erhalten
  • GlobalKey wird sparsam verwendet – nur wenn der Zugriff auf den Zustand über den gesamten Baum wirklich notwendig ist
  • UniqueKey wird in build() vermieden – es erzwingt einen Rebuild bei jedem Frame
  • ObjectKey wird verwendet, wenn die Identität auf einem Datenobjekt basiert und nicht auf einem einzelnen Wert

Theming und Designsystem:

  • Farben stammen aus Theme.of(context).colorScheme – keine hartcodierten Colors.red oder Hex-Werte
  • Textstile stammen aus Theme.of(context).textTheme – kein Inline-TextStyle mit rohen Schriftgrößen
  • Dark-Mode-Kompatibilität wurde überprüft – keine Annahmen über hellen Hintergrund
  • Abstände und Größen verwenden konsistente Design-Tokens oder Konstanten, keine magischen Zahlen

Build-Methoden-Komplexität:

  • Keine Netzwerkaufrufe, Datei-I/O oder schwere Berechnungen in build()
  • Kein Future.then() oder async-Arbeit in build()
  • Keine Erstellung von Abonnements (.listen()) in build()
  • setState() auf den kleinstmöglichen Teilbaum beschränkt

4. State-Management (Bibliotheksunabhängig)

Diese Prinzipien gelten für alle Flutter-State-Management-Lösungen (BLoC, Riverpod, Provider, GetX, MobX, Signals, ValueNotifier usw.).

Architektur:

  • Geschäftslogik lebt außerhalb der Widget-Ebene – in einer State-Management-Komponente (BLoC, Notifier, Controller, Store, ViewModel usw.)
  • State-Manager erhalten Abhängigkeiten per Injektion, nicht durch interne Konstruktion
  • Eine Dienst- oder Repository-Ebene abstrahiert Datenquellen – Widgets und State-Manager sollten keine APIs oder Datenbanken direkt aufrufen
  • State-Manager haben eine einzige Verantwortung – keine „Gott“-Manager, die nicht zusammenhängende Belange behandeln
  • komponentenübergreifende Abhängigkeiten folgen den Konventionen der Lösung:
    • Bei Riverpod: Anbieter, die von anderen Anbietern über ref.watch abhängen, sind erwartet – kennzeichnen Sie nur zirkuläre oder übermäßig verworrene Ketten
    • Bei BLoC: Blöcke sollten nicht direkt von anderen Blöcken abhängen – bevorzugen Sie gemeinsam genutzte Repositories oder Koordination auf Präsentationsebene
    • Bei anderen Lösungen: Befolgen Sie die dokumentierten Konventionen für die Kommunikation zwischen Komponenten

Unveränderlichkeit und Wertegleichheit (für Lösungen mit unveränderlichem Zustand: BLoC, Riverpod, Redux):

  • Zustandsobjekte sind unveränderlich – neue Instanzen werden über copyWith() oder Konstruktoren erstellt, nie direkt mutiert
  • Zustandsklassen implementieren == und hashCode korrekt (alle Felder in den Vergleich einbezogen)
  • Der Mechanismus ist im gesamten Projekt konsistent – manuelle Überschreibung, Equatable, freezed, Dart Records oder andere
  • Sammlungen innerhalb von Zustandsobjekten werden nicht als rohe veränderliche List/Map offengelegt

Reaktivitätsdisziplin (für reaktive Mutationslösungen: MobX, GetX, Signals):

  • Zustand wird nur über die reaktive API der Lösung mutiert (@action in MobX, .value bei Signalen, .obs in GetX) – direkte Feldmutation umgeht die Änderungsverfolgung
  • Abgeleitete Werte verwenden den berechneten Mechanismus der Lösung, anstatt redundant gespeichert zu werden
  • Reaktionen und Entsorger werden ordnungsgemäß bereinigt (ReactionDisposer in MobX, Effektbereinigung in Signals)

Zustandsform-Design:

  • Sich gegenseitig ausschließende Zustände verwenden versiegelte Typen, Union-Varianten oder den integrierten asynchronen Zustandstyp der Lösung (z. B. Riverpods AsyncValue) – keine booleschen Flags (isLoading, isError, hasData)
  • Jeder asynchrone Vorgang modelliert Laden, Erfolg und Fehler als unterschiedliche Zustände
  • Alle Zustandsvarianten werden in der UI erschöpfend behandelt – keine stillschweigend ignorierten Fälle
  • Fehlerzustände tragen Fehlerinformationen zur Anzeige; Ladezustände enthalten keine veralteten Daten
  • Nullable-Daten werden nicht als Ladeindikator verwendet – Zustände sind explizit
// SCHLECHT – boolesche Flag-Suppe ermöglicht unmögliche Zustände
class UserState {
  bool isLoading = false;
  bool hasError = false; // isLoading && hasError ist darstellbar!
  User? user;
}

// GUT (unveränderlicher Ansatz) – versiegelte Typen machen unmögliche Zustände undarstellbar
sealed class UserState {}
class UserInitial extends UserState {}
class UserLoading extends UserState {}
class UserLoaded extends UserState {
  final User user;
  const UserLoaded(this.user);
}
class UserError extends UserState {
  final String message;
  const UserError(this.message);
}

// GUT (reaktiver Ansatz) – beobachtbares Enum + Daten, Mutationen über die Reaktivitäts-API
// enum UserStatus { initial, loading, loaded, error }
// Verwenden Sie die Observable/Signal Ihrer Lösung, um Status und Daten getrennt zu umschließen

Rebuild-Optimierung:

  • Zustandskonsumenten-Widgets (Builder, Consumer, Observer, Obx, Watch usw.) sind so eng wie möglich eingegrenzt
  • Selektoren werden verwendet, um nur dann neu zu bauen, wenn sich bestimmte Felder ändern – nicht bei jeder Zustandsemission
  • const-Widgets werden verwendet, um die Rebuild-Ausbreitung durch den Baum zu stoppen
  • Berechneter/abgeleiteter Zustand wird reaktiv berechnet, nicht redundant gespeichert

Abonnements und Entsorgung:

  • Alle manuellen Abonnements (.listen()) werden in dispose() / close() gekündigt
  • Stream-Controller werden geschlossen, wenn sie nicht mehr benötigt werden
  • Timer werden im Entsorgungslebenszyklus abgebrochen
  • Der vom Framework verwaltete Lebenszyklus wird gegenüber manuellem Abonnement bevorzugt (deklarative Builder gegenüber .listen())
  • mounted-Prüfung vor setState in asynchronen Callbacks
  • BuildContext wird nach await nicht ohne Prüfung von context.mounted verwendet (Flutter 3.7+) – veralteter Kontext führt zu Abstürzen
  • Keine Navigation, Dialoge oder Scaffold-Nachrichten nach asynchronen Lücken ohne Überprüfung, ob das Widget noch gemountet ist
  • BuildContext wird niemals in Singletons, State-Managern oder statischen Feldern gespeichert

Lokaler vs. globaler Zustand:

  • Flüchtiger UI-Zustand (Checkbox, Slider, Animation) verwendet lokalen Zustand (setState, ValueNotifier)
  • Gemeinsam genutzter Zustand wird nur so hoch wie nötig gehoben – nicht übermäßig globalisiert
  • Funktionsbereichsbezogener Zustand wird ordnungsgemäß entsorgt, wenn die Funktion nicht mehr aktiv ist

5. Performance

Unnötige Rebuilds:

  • setState() wird nicht auf der Root-Widget-Ebene aufgerufen – lokalisieren Sie Zustandsänderungen
  • const-Widgets werden verwendet, um die Rebuild-Ausbreitung zu stoppen
  • RepaintBoundary wird um komplexe Teilbäume verwendet, die unabhängig neu zeichnen
  • Der child-Parameter von AnimatedBuilder wird für Teilbäume verwendet, die unabhängig von der Animation sind

Teure Operationen in build():

  • Kein Sortieren, Filtern oder Abbilden großer Sammlungen in build() – in der State-Management-Ebene berechnen
  • Keine Regex-Kompilierung in build()
  • Die Verwendung von MediaQuery.of(context) ist spezifisch (z. B. MediaQuery.sizeOf(context))

Bildoptimierung:

  • Netzwerkbilder verwenden Caching (jede für das Projekt geeignete Caching-Lösung)
  • Angemessene Bildauflösung für das Zielgerät (kein Laden von 4K-Bildern für Thumbnails)
  • Image.asset mit cacheWidth/cacheHeight, um in der Anzeigegröße zu dekodieren
  • Platzhalter- und Fehler-Widgets werden für Netzwerkbilder bereitgestellt

Lazy Loading:

  • ListView.builder / GridView.builder wird anstelle von ListView(children: [...]) für große oder dynamische Listen verwendet (konkrete Konstruktoren sind für kleine, statische Listen in Ordnung)
  • Paginierung wird für große Datenmengen implementiert
  • Verzögertes Laden (deferred as) wird für schwere Bibliotheken in Web-Builds verwendet

Sonstiges:

  • Das Opacity-Widget wird bei Animationen vermieden – verwenden Sie AnimatedOpacity oder FadeTransition
  • Clipping wird bei Animationen vermieden – Bilder vorab zuschneiden
  • operator == wird nicht auf Widgets überschrieben – verwenden Sie stattdessen const-Konstruktoren
  • Intrinsische Dimensionierungs-Widgets (IntrinsicHeight, IntrinsicWidth) werden sparsam verwendet (zusätzlicher Layout-Durchlauf)

6. Testen

Testtypen und Erwartungen:

  • Unit-Tests: Decken die gesamte Geschäftslogik ab (State-Manager, Repositories, Hilfsfunktionen)
  • Widget-Tests: Decken einzelnes Widget-Verhalten, Interaktionen und visuelle Ausgabe ab
  • Integrationstests: Decken kritische Benutzerabläufe von Anfang bis Ende ab
  • Golden-Tests: Pixelgenaue Vergleiche für designkritische UI-Komponenten

Abdeckungsziele:

  • Ziel: 80 %+ Zeilenabdeckung bei der Geschäftslogik
  • Alle Zustandsübergänge haben entsprechende Tests (Laden → Erfolg, Laden → Fehler, Wiederholung usw.)
  • Randfälle getestet: leere Zustände, Fehlerzustände, Ladezustände, Grenzwerte

Testisolierung:

  • Externe Abhängigkeiten (API-Clients, Datenbanken, Dienste) werden gemockt oder gefälscht
  • Jede Testdatei testet genau eine Klasse/Einheit
  • Tests überprüfen das Verhalten, nicht die Implementierungsdetails
  • Stubs definieren nur das Verhalten, das für jeden Test benötigt wird (minimales Stubbing)
  • Kein gemeinsam genutzter veränderlicher Zustand zwischen Testfällen

Widget-Testqualität:

  • pumpWidget und pump werden korrekt für asynchrone Operationen verwendet
  • find.byType, find.text, find.byKey werden angemessen verwendet
  • Keine flaky Tests, die von Timing abhängen – verwenden Sie pumpAndSettle oder explizites pump(Duration)
  • Tests laufen in CI und Fehler blockieren Merges

7. Barrierefreiheit

Semantische Widgets:

  • Das Semantics-Widget wird verwendet, um Screenreader-Beschriftungen bereitzustellen, wo automatische Beschriftungen unzureichend sind
  • ExcludeSemantics wird für rein dekorative Elemente verwendet
  • MergeSemantics wird verwendet, um verwandte Widgets zu einem einzigen zugänglichen Element zu kombinieren
  • Bilder haben die Eigenschaft semanticLabel gesetzt

Screenreader-Unterstützung:

  • Alle interaktiven Elemente sind fokussierbar und haben sinnvolle Beschreibungen
  • Die Fokusreihenfolge ist logisch (folgt der visuellen Lesereihenfolge)

Visuelle Barrierefreiheit:

  • Kontrastverhältnis >= 4,5:1 für Text gegenüber Hintergrund
  • Antippbare Ziele sind mindestens 48x48 Pixel groß
  • Farbe ist nicht der einzige Indikator für den Zustand (Symbole/Text daneben verwenden)
  • Text skaliert mit den Systemschriftgrößeneinstellungen

Interaktionsbarrierefreiheit:

  • Keine No-Op-onPressed-Callbacks – jeder Button tut etwas oder ist deaktiviert
  • Fehlerfelder schlagen Korrekturen vor
  • Der Kontext ändert sich nicht unerwartet, während der Benutzer Daten eingibt

8. Plattformspezifische Belange

iOS/Android-Unterschiede:

  • Plaatformadaptive Widgets werden verwendet, wo angemessen
  • Die Rücknavigation wird korrekt behandelt (Android-Zurück-Button, iOS-Wisch-zum-Zurückgehen)
  • Statusleiste und Safe Area werden über das SafeArea-Widget behandelt
  • Plattformspezifische Berechtigungen werden in AndroidManifest.xml und Info.plist deklariert

Responsive Design:

  • LayoutBuilder oder MediaQuery werden für responsive Layouts verwendet
  • Breakpoints werden konsistent definiert (Telefon, Tablet, Desktop)
  • Text läuft auf kleinen Bildschirmen nicht über – verwenden Sie Flexible, Expanded, FittedBox
  • Landscape-Orientierung wurde getestet oder explizit gesperrt
  • Webspezifisch: Maus-/Tastaturinteraktionen werden unterstützt, Hover-Zustände sind vorhanden

9. Sicherheit

Sichere Speicherung:

  • Sensitive Daten werden nicht in Klartext in SharedPreferences, Datenbanken oder als Dateien gespeichert
  • Token und Geheimnisse werden mit flutter_secure_storage oder der Schlüsselbund-/Kettenspeicher-API der Plattform gespeichert
  • Im App-Speicher zwischengespeicherte Daten werden bei der Abmeldung oder Sitzungszeitüberschreitung gelöscht

Netzwerksicherheit:

  • Alle API-Anfragen verwenden HTTPS – keine HTTP-Anfragen in der Produktion
  • SSL/TLS-Pinning wird implementiert, wo hohe Sicherheitsanforderungen bestehen
  • API-Schlüssel sind nicht im Quellcode fest codiert – werden aus Umgebungsvariablen oder sicheren Konfigurationsdiensten gelesen
  • Anfragen validieren Eingaben auf der Clientseite – vertrauen Sie niemals ausschließlich der serverseitigen Validierung

Eingabevalidierung:

  • Alle Benutzereingaben werden validiert und bereinigt (Formularfelder, Deep Links, WebView-Eingaben)
  • Keine direkte Ausgabe von unsicheren Benutzereingaben – HTML-Escape oder Markdown-Sanitisierung verwenden
  • Deep Links werden gegen eine definierte Liste erwarteter Routen validiert

Autorisierung und Authentifizierung:

  • Authentifizierungstoken werden sicher gespeichert und bei Zugriffsverweigerung gelöscht
  • Die Sitzungsverwaltung hat angemessene Ablauf- und Erneuerungsmechanismen
  • Der Zugriff auf bestimmte Bildschirme oder Funktionen wird in einer zentralen Auth-Schicht überprüft
  • Daten aus APIs, die nicht autorisierte Inhalte enthalten, werden filtriert

10. Abhängigkeitsinjektion

DI-Konfiguration:

  • Abhängigkeiten werden über einen zentralen DI-Container bereitgestellt (get_it, provider, riverpod, injectable usw.)
  • DI-Einrichtung ist aspektorientiert – keine manuelle Konstruktorverdrahtung, die über die gesamte Codebasis verstreut ist
  • Keine „Service-Locator“-Antimuster – registrierte Typen werden konstruiert, wo sie benötigt werden
  • Singleton-Registrierungen werden nur für zustandslose Dienste oder gemeinsam genutzte Ressourcen verwendet
  • Faktorien werden für vorübergehende Abhängigkeiten verwendet, die jedes Mal neu erstellt werden müssen
  • Der DI-Container wird in Tests einfach durch Mocks ersetzt

Testbarkeit:

  • Anbieter/Registrierungen können in Tests überschrieben werden
  • Keine versteckten Abhängigkeiten – alle Abhängigkeiten werden über den DI-Container oder den Konstruktor weitergegeben
  • Abhängigkeiten sind im Produktions- und Test-Code einheitlich

11. Fehlerbehandlung und Logging

Fehlerbehandlung:

  • Alle try-catch-Blöcke behandeln spezifische Ausnahmetypen – kein breites catch (Exception e) ohne Unterscheidung
  • Die Fehlerbehandlung erfolgt auf der geeigneten Abstraktionsebene – UI fängt Ausnahmen von Repositorys/Diensten
  • Fehler im Zusammenhang mit der Geschäftslogik werden den Benutzern über Snackbars, Dialoge oder Inline-Fehlermeldungen angezeigt
  • Ausnahmen werden nicht stillschweigend geschluckt – selbst ein Wiederholungsmechanismus protokolliert die ursprünglichen Fehler
  • Kritische Fehler lösen einen Absturz aus oder zeigen eine Fehlerbildschirm-Widget an (Erase to gray / ErrorWidget)

Logging:

  • Das Logging verwendet ein strukturiertes Logging-Framework (z. B. logging, talker, loggy, benutzerdefinierte Logger)
  • Logs haben angemessene Ebenen (debug, info, warning, error)
  • Keine sensiblen Daten in Logs (Passwörter, Token, persönliche Daten)
  • Fehlerlogs enthalten aussagekräftige Fehlermeldungen und Stack-Traces
  • Logs sind in Produktions-Builds nicht zugänglich (kompiliert oder anderweitig entfernt)

12. Internationalisierung und Lokalisierung (i18n/l10n)

Lokalisierungseinrichtung:

  • Strings sind nicht hartcodiert – alle Textinhalte werden über die i18n-Lösung des Projekts referenziert (ARB-Dateien, .i18n.yaml, l10n.yaml)
  • Anwendung unterstützt mindestens eine Sprache (normalerweise die Standardsprache) + Fallback
  • RTL-Unterstützung wird getestet, wenn Arabisch, Hebräisch oder andere RTL-Sprachen in der Zielgruppe sind
  • Textlayout wird mit RTL getestet (End-to-End-Ausrichtung, nicht nur einzelne Zeichen)

Übersetzungsqualität:

  • Alle UI-Strings haben Übersetzungen – keine fehlenden Schlüssel in lokalen Builds
  • Platzhalter in übersetzten Strings sind korrekt – keine fehlenden oder falsch platzierten Parameter
  • Lokalisierte Strings berücksichtigen den Kontext (formell vs. informell, Pluralformen)

13. Routinge und Navigation

Routing-Architektur:

  • Routing verwendet eine deklarative API (Navigator 2.0, go_router, auto_route, beamer) – keine versteckten Navigator.push-Aufrufe, die tief in Widgets vergraben sind
  • Routen sind als benannte oder typisierte Routen definiert – keine rohen Zeichenfolgen, die Zielpfade darstellen, es sei denn, die Architektur des Projekts erfordert dies
  • Tiefenverknüpfung wird unterstützt (wenn die App über eine externe URL geöffnet wird, navigiert sie zur richtigen Route)
  • Die Navigation ist zustandsbehaftet – zurückgeschobene Seiten bewahren ihren Scroll-Zustand, es sei denn, sie werden explizit gelöscht

Navigationsmuster:

  • Auth-Flow-Aufrufe sind in einer Auth-Route oder einem Auth-Guard zentralisiert – Navigation wird nicht über mehrere Widgets verteilt
  • Modale Präsentation wird konsistent verwendet (BottomSheet, Dialog, Vollbild-Modal)
  • Routenparameter werden über die Routing-Lösung übergeben – nicht über Navigator.push mit benutzerdefinierten Argumenten
  • Fehlerbehandlung wird für fehlgeschlagene Navigationen hinzugefügt (404-Seite, Fallback-Route)

14. Build-Konfiguration

Build-Varianten:

  • Unterschiedliche Build-Varianten werden definiert (debug, profile, release) mit unterschiedlichen Konfigurationen für main.dart, GoogleService-Info.plist, AndroidManifest.xml
  • Umgebungs-Enums oder -Konstanten werden verwendet, um die Konfiguration zu abstrahieren – keine magischen Strings für API-URLs oder Funktionen
  • Die Konfiguration wird nach Umgebung getrennt (dev, staging, production)

Flutter-spezifische Build-Konfiguration:

  • Splash-Screen wird für alle Plattformen konfiguriert – flutter_native_splash oder benutzerdefinierte native Splash-Screens
  • App-Icon-Sets sind für alle erforderlichen Auflösungen vorhanden – flutter_launcher_icons oder benutzerdefinierte native Konfiguration
  • Der Build-Kanal ist korrekt eingerichtet – das Freigeben von Builds an den App Store und Play Store wird über CI/CD gesteuert

Checklisten-Nutzungshinweise

  1. Richtlinien, keine Regeln – verstehen Sie den Kontext, bevor Sie einen Punkt als Fehler markieren
  2. Fokus auf „Ob“ und „Warum“, nicht auf „Wie“ – die Checkliste ist implementierungsneutral
  3. Behandeln Sie Zustandsverwaltung als Prinzip, nicht als Produkt – die aufgeführten Prinzipien gelten für alle Lösungen
  4. Review in Schichten – analysieren Sie zuerst die Gesamtarchitektur, dann tiefer in die Implementierung
  5. Überspringen Sie Rubriken, die für den aktuellen Review nicht relevant sind – verwenden Sie das, was für Ihre Codebasis relevant ist

Bibliotheksspezifische Hinweise

Riverpod

  • Verwenden Sie ref.watch für automatische Neuerstellung, ref.listen für Nebenwirkungen
  • AsyncValue mit .when() für erschöpfende Zustandsbehandlung
  • Anbieter sollten andere Anbieter niemals direkt verändern – respektieren Sie die unidirektionale Datenfluss
  • Provider.family wird für parametrisierte Abfragen verwendet

BLoC

  • Verwenden Sie BlocProvider für die Bereitstellung und BlocBuilder/BlocSelector für den Konsum
  • Die add-Methode ist der einzige Weg, um Ereignisse zu senden – emit sollte nur innerhalb von mapEventToState aufgerufen werden
  • Blöcke sollten keine anderen Blöcke direkt abhängig machen – verwenden Sie gemeinsam genutzte Repositories
  • Verwenden Sie BlocObserver für das applikationsweite Debugging und Logging

Provider

  • Verwenden Sie ChangeNotifierProvider für veränderlichen Zustand und Provider für unveränderliche Werte
  • Consumer und Selector für granulare Rebuild-Steuerung
  • ProxyProvider ist der Mechanismus für Provider, die von anderen abhängen – direkte Provider.of-Aufrufe zwischen ihnen vermeiden

GetX

  • Verwenden Sie GetX/Obx für granulare Rebuilds – vermeiden Sie GetBuilder, es sei denn, Sie benötigen die manuelle Steuerung
  • Controller sollten keine Widgets direkt verändern – Rückgabewerte von Methoden ändern die Ansicht über Observablen
  • Get.lazyPut wird für Controller mit verzögerter Initialisierung verwendet

MobX

  • Verwenden Sie @observable für reaktive Felder und @action für Mutationen
  • Observer-Widgets sollten eng um das spezifische Observable herum angeordnet sein, das sie lesen
  • @computed wird für abgeleitete Werte verwendet – speichern Sie sie nicht manuell

Signals (z. B. signals, solidart)

  • Verwenden Sie Signal für veränderliche Zustandsbehälter und Computed für abgeleitete Werte
  • effect() für Nebenwirkungen, die automatisch aufgeräumt werden
  • Signale in Widgets: watch (ähnlich wie Consumer) für granulare Rebuilds
  • Vermeiden Sie die direkte Mutation von Signal-Wrapper-Objekten – aktualisieren Sie .value

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

Verwandte Skills