Was macht Production-Readiness-Checkliste?
Jeder Eintrag gibt an, was zu prüfen ist. Wende an, was zum Projektstand passt, unter Verwendung der Phasen-Stufen in CLAUDE.md; falls keine definiert sind, leite die Phase (Prototyp, MVP, Produktion oder Skalierung) ab und gib sie an. Markiere in Reviews Einträge, die nicht zur Phase passen, als „noch nicht zutreffend“ und nenne den Auslöser, der sie relevant machen würde.
1. Sicherheit und Zugriffskontrolle
- Autorisierung: Überprüfe Berechtigungen serverseitig für jeden Endpunkt und jedes aufgerufene Objekt, nicht nur beim Login (verhindert IDOR und BOLA). Bei Supabase, Firebase oder ähnlichen Backends müssen zeilenbasierte Sicherheitsregeln oder Sicherheitsregeln aktiviert und getestet sein.
- Eingabevalidierung: Validiere Typ, Länge, Format und Bereich an jeder Vertrauensgrenze mit einer Schema-Bibliothek (Zod, Pydantic oder Äquivalent). Client-seitige Validierung dient der UX, niemals der Sicherheit.
- SQL-Injection: Verwende nur parametrisierte Abfragen oder ORM-Bindungen. Erlaube dynamische Bezeichner wie Sortierspalten per Whitelist.
- XSS: Verlasse dich auf Framework-Escaping. Vermeide
innerHTML,dangerouslySetInnerHTMLundv-htmlmit nicht vertrauenswürdigen Daten oder bereinige mit einer geprüften Bibliothek wie DOMPurify. Füge eine Content Security Policy hinzu. - CSRF: Verwende für cookie-basierte Sitzungen SameSite-Cookies plus CSRF-Tokens oder Origin-Prüfungen bei zustandsändernden Anfragen. Ändere niemals den Zustand per GET.
- CORS: Erlaube exakte Ursprünge per Whitelist. Spiegele niemals beliebige Ursprünge wider oder erlaube einen Wildcard mit Anmeldeinformationen. CORS ist keine Zugriffskontrolle.
- SSRF: Wenn der Server benutzergelieferte URLs abruft, erlaube Ziele per Whitelist, blockiere private, Loopback- und Link-Local-Adressen für IPv4 und IPv6 (einschließlich Cloud-Metadaten unter
169.254.169.254) und überprüfe nach Weiterleitungen und DNS-Auflösung erneut. - Geheimnisverwaltung: Lade Geheimnisse aus Umgebungsvariablen oder einem Secrets Manager. Sie erscheinen niemals im Code, in Logs, Container-Images oder im Git-Verlauf, und alles, was durchgesickert ist, wird rotiert.
- IAM: Wende das Prinzip der geringsten Privilegien auf jede Person, jeden Dienst und jedes Token an. Verwende separate Anmeldeinformationen pro Umgebung und pro Dienst und verwende niemals Root- oder Admin-Schlüssel in Anwendungen.
- OAuth: Verwende einen bewährten Anbieter oder eine Bibliothek anstelle einer benutzerdefinierten Authentifizierung. Verwende Authorization Code mit PKCE für Browser- und Mobile-Clients, exakten Redirect-URI-Abgleich, State-Validierung und minimale Bereiche.
- JWT-Rotation: Verwende kurzlebige Access-Tokens, rotierende Refresh-Tokens mit Wiederverwendungserkennung und Signaturschlüssel, die über Schlüssel-IDs (
kid) und JWKS rotiert werden. Überprüfe immer Signatur, Algorithmus, Aussteller, Zielgruppe und Ablauf. - Passwort- und Sitzungssicherheit: Hashe Passwörter mit Argon2id oder bcrypt. Setze Sitzungscookies als HttpOnly, Secure und SameSite. Biete MFA an, wenn Konten einen Wert darstellen.
- TLS: Serviere HTTPS überall mit automatischer Zertifikatserneuerung, TLS 1.2 minimum (bevorzuge 1.3) und HSTS. Deaktiviere niemals die Zertifikatsprüfung.
- Verschlüsselung während der Übertragung: Verschlüssele den internen Datenverkehr ebenso wie den öffentlichen Datenverkehr, einschließlich Dienst-, Datenbank-, Cache- und Warteschlangenverbindungen.
- Verschlüsselung im Ruhezustand: Verschlüssele Datenbanken, Festplatten, Backups und Objektspeicher mit Schlüsseln in einem KMS. Ziehe für hochsensible Daten eine Verschlüsselung auf Feldebene in Betracht.
- Sicherheits-Header: Setze Content-Security-Policy (einschließlich frame-ancestors gegen Clickjacking), Strict-Transport-Security,
X-Content-Type-Options: nosniffund Referrer-Policy. - WAF: Platziere eine Web Application Firewall mit verwalteten Regelsätzen vor öffentlichen Produktions-Apps.
- DDoS-Schutz: Verlasse dich auf den Schutz des Anbieters (Cloudflare, AWS Shield oder Plattform-Standardeinstellungen) sowie auf Ratenbegrenzungen und Autoscaling-Obergrenzen, damit ein Angriff nicht zu einer unbegrenzten Rechnung führen kann.
- Lieferkettensicherheit: Führe Abhängigkeits-Schwachstellenscans (npm audit, pip-audit, Dependabot oder ähnlich) in CI durch. Überprüfe jedes neue Paket, ob es echt, korrekt benannt und gewartet ist.
- Datei-Uploads: Überprüfe den Typ anhand des Inhalts und nicht der Erweiterung, begrenze die Größe, speichere im Objektspeicher unter zufälligen Namen und serviere private Dateien über kurzlebige signierte URLs.
- Prüfprotokolle: Zeichne auf, wer was und wann bei sensiblen Aktionen (Auth-Ereignisse, Berechtigungsänderungen, Datenexporte, Geldbewegungen) getan hat, in einem Append-Only-Speicher.
- Datenschutz und personenbezogene Daten (PII): Erhebe das Minimum, wisse, wo personenbezogene Daten leben, halte sie aus Logs heraus, definiere Aufbewahrungsfristen und unterstütze Löschung und Export, wo Gesetze wie DSGVO oder CCPA gelten.
2. Daten und Datenbanken
- Datenbank-Indizierung: Indiziere Spalten, die in Filtern, Joins und Sortierungen in Tabellen verwendet werden, die wachsen werden, einschließlich Fremdschlüssel. Vermeide redundante Indizes, die Schreibvorgänge verlangsamen.
- Abfrageoptimierung: Überprüfe Pläne mit
EXPLAINfür langsame oder häufige Abfragen. Wähle nur benötigte Spalten aus und vermeide es, indizierte Spalten in Funktionen innerhalb von WHERE-Klauseln zu verpacken. - N+1-Abfragen: Finde Schleifen, die einmal pro Element abfragen. Ersetze sie durch Joins, Eager Loading oder Batching.
- Connection-Pooling: Passe die Pool-Größe an die Datenbankgrenzen an. Verwende in serverlosen Umgebungen einen Pooler (PgBouncer, RDS Proxy oder den Pooler des Anbieters), da jede Instanz ihre eigenen Verbindungen öffnet.
- Transaktionen: Verpacke mehrschrittige Schreibvorgänge, die zusammen erfolgreich sein oder fehlschlagen müssen, in eine einzige Transaktion und wähle die Isolationsstufe bewusst.
- Constraints: Erzwinge die Integrität in der Datenbank mit NOT NULL, UNIQUE, Fremdschlüsseln und CHECK-Constraints. Anwendungsprüfungen allein unterliegen Race Conditions.
- Paginierung: Paginiere jeden Listen-Endpunkt und jede Abfrage mit einer begrenzten Seitengröße. Bevorzuge Cursor-Paginierung (Keyset) für große oder sich ändernde Daten.
- Geld und Zeit: Speichere Geld als ganzzahlige Nebeneinheiten oder einen decimal-Typ. Speichere Zeitstempel in UTC und konvertiere nur für die Anzeige.
- Read Replicas: Füge sie nur hinzu, wenn Lesevorgänge die Primärdatenbank überlasten, und behandle Replikationsverzögerungen, insbesondere wenn Benutzer ihre eigenen Schreibvorgänge lesen.
- Replikation: Wisse, ob sie synchron oder asynchron ist und wie viele Daten ein Failover verlieren kann.
- Partitionierung: Partitioniere sehr große Tabellen (oft nach Zeit), um Indizes und Wartung handhabbar zu halten, und laufe alte Daten durch Löschen von Partitionen ab.
- Sharding: Behandle es als letztes Mittel nach Indizierung, Caching, Replikaten und vertikaler Skalierung. Wähle einen Shard-Key, der Hot Spots und abteilungsübergreifende Abfragen vermeidet.
- Datenbank-Migrationen: Halte Migrationen versioniert, überprüft, in Bereitstellungen automatisiert und nach Möglichkeit umkehrbar. Verwende für Null-Ausfallzeiten Expand and Contract: Hinzufügen, Backfill, Wechseln, dann in einer späteren Version entfernen. Erstelle Backups vor destruktiven Änderungen.
- Schema-Versionierung: Versioniere Datenverträge (Datenbankschemata, Ereignis-Payloads, API-Schemata), damit alter und neuer Code während Bereitstellungen nebeneinander laufen können.
3. Nebenläufigkeit und verteilte Systeme
- Race Conditions: Suche nach Prüfe-dann-handle-Code (Kontostände, Inventar, eindeutige Benutzernamen, Coupon-Einlösung). Behebe es mit atomaren Aktualisierungen, Constraints, Transaktionen oder Sperren.
- Thread-Sicherheit: Synchronisiere oder eliminiere gemeinsam genutzte veränderliche Zustände über Threads, Worker und asynchrone Tasks hinweg. Modulebene-Globals werden oft über Anfragen hinweg gemeinsam genutzt.
- Optimistisches Sperren: Überprüfe eine Versionsspalte oder einen ETag beim Aktualisieren für Datensätze mit geringer Konkurrenz und gib bei Konflikten 409 oder 412 zurück.
- Pessimistisches Sperren: Verwende
SELECT ... FOR UPDATEfür kritische Abschnitte mit hoher Konkurrenz und halte Sperren kurz. - Deadlocks: Erwerbe Sperren in einer konsistenten Reihenfolge, halte Transaktionen kurz und wiederhole bei Deadlock-Fehlern.
- Verteilte Sperren: Verwende sie nur zur Koordinierung über Prozesse hinweg, mit Leases, die ablaufen, und Fencing-Tokens. Bevorzuge Datenbank-Constraints oder Warteschlangen, wenn diese ausreichen.
- Verteilte Transaktionen: Vermeide Two-Phase-Commit über Dienste hinweg. Halte die Transaktionsgrenzen nach Möglichkeit innerhalb einer Datenbank.
- Saga-Muster: Verkette für Workflows, die sich über Dienste erstrecken, lokale Transaktionen mit Kompensationsaktionen und mache jeden Schritt idempotent.
- CAP-Theorem: Während einer Netzwerkpartition muss ein System entweder Konsistenz oder Verfügbarkeit wählen. Entscheide pro Funktion: Kontostände und Inventar benötigen Konsistenz, während Feeds und Zähler Veraltung tolerieren können.
- Eventuelle Konsistenz: Wo sie akzeptiert wird, gestalte UI und Logik für veraltete Lesevorgänge und lasse Aktualisierungen konvergieren.
- Leader-Wahl: Wenn genau eine Instanz handeln muss (Scheduler, Singleton-Worker), verwende einen Lease oder ein Plattform-Primitiv, niemals eine hartcodierte Instanz.
- Netzwerkpartitionen: Gehe davon aus, dass jeder Aufruf auf halbem Weg fehlschlagen oder ohne Antwort erfolgreich sein kann. Entwerfe mit Timeouts, Idempotenz und Abgleich.
- Taktversatz: Verlasse dich niemals auf Uhren über Maschinen hinweg für die Reihenfolge oder Korrektheit. Verwende Datenbank-Zeitstempel, Sequenznummern oder logische Uhren und erlaube kleine Toleranzen bei Token-Ablaufprüfungen.
- Service Discovery: Löse Dienste über DNS, die Plattform oder ein Registry auf, niemals hartcodierte IPs.
4. Resilienz und Fehlertoleranz
- Timeouts: Gib jedem ausgehenden Aufruf (HTTP, Datenbank, Cache, Warteschlange, LLM-API) Verbindungs- und Anfrage-Timeouts, die in die eigene Frist des Aufrufers passen.
- Wiederholungen: Wiederhole nur vorübergehende Fehler (Timeouts, Verbindungsfehler, 429, 502, 503, 504) bei idempotenten Operationen mit begrenzten Versuchen. Vermeide es, auf jeder Ebene gleichzeitig zu wiederholen, was die Last vervielfacht.
- Exponentielles Backoff: Führe Backoff exponentiell mit Jitter durch und beachte
Retry-After-Header. - Circuit Breaker: Stoppe den Aufruf einer ausfallenden Abhängigkeit nach wiederholten Fehlern, schlage schnell mit einem Fallback fehl und sondiere die Wiederherstellung.
- Idempotenz: Gib Operationen, die möglicherweise wiederholt werden (Zahlungen, Bestellungen, Webhook-Handler, Jobs), einen Idempotenz-Schlüssel oder natürlichen Schlüssel, damit Duplikate keine zusätzliche Wirkung haben.
- Backpressure: Beschränke Warteschlangen, Puffer und Nebenläufigkeit. Wenn überlastet, wirf Last ab oder gib 429 oder 503 zurück, anstatt unbegrenzte Arbeit anzunehmen.
- Bulkheads: Isoliere Ressourcen (getrennte Pools oder Worker), damit eine langsame Abhängigkeit nicht alles erschöpfen kann.
- Graceful Degradation: Entscheide, was noch funktioniert, wenn eine Abhängigkeit ausfällt, wie zwischengespeicherte Daten, ein Nur-Lesen-Modus oder das vorübergehende Ausblenden einer Funktion.
- Graceful Shutdown: Höre bei
SIGTERMauf, neue Arbeit anzunehmen, beende laufende Anfragen und Jobs und schließe dann Verbindungen. - Health Checks: Stelle einen kostengünstigen Health-Endpunkt für den Load Balancer oder die Plattform bereit.
- Liveness- & Readiness-Probes: Liveness erkennt nur einen hängenden Prozess und darf nicht von externen Diensten abhängen, sonst startet ein Datenbank-Ausrutscher alles neu. Readiness entscheidet, ob eine Instanz Datenverkehr empfangen soll, und kann Abhängigkeiten überprüfen.
- Failover: Wisse, was passiert, wenn die primäre Datenbank, Zone oder der primäre Anbieter ausfällt. Automatisiere es, wo Betriebszeit wichtig ist, und teste es.
5. Messaging, Hintergrundarbeit und Echtzeit
- Nachrichtenwarteschlangen: Verschiebe langsame, wiederholbare oder bursty Arbeit (E-Mails, Medienverarbeitung, Drittanbieteraufrufe) aus dem Anforderungspfad in eine Warteschlange mit Workern.
- Liefergarantien: Gehe von Mindestens-Einmal-Zustellung aus, daher müssen Verbraucher idempotent sein. Gehe nicht von einer Bestellung aus, es sei denn, das System garantiert sie pro Schlüssel.
- Dead Letter Queues: Leite Nachrichten, die Wiederholungen erschöpft haben, an eine DLQ mit einem Alarm und einem Wiedergabepfad weiter. Verwerfe sie niemals stillschweigend oder wiederhole sie auf unbestimmte Zeit.
- Pub/Sub: Verwende es für Fan-Out an mehrere unabhängige Verbraucher mit definierten Ereignisschemata und Eigentumsverhältnissen.
- Ereignisgesteuerte Architektur: Führe sie ein, wenn die Entkopplung die Debugging-Kosten wert ist. Behandle Ereignisse als versionierte Verträge und halte Anfragen über sie hinweg nachvollziehbar.
- Transaktionaler Outbox: Wenn ein Datenbank-Schreibvorgang auch ein Ereignis veröffentlichen muss, schreibe beide in einer Transaktion (eine Outbox-Tabelle) und leite asynchron weiter, was das Dual-Write-Problem vermeidet.
- Cron-Jobs: Mache geplante Jobs idempotent, sicher für zweimalige Ausführung oder Überlappung, auf jeweils eine Instanz beschränkt und auf verpasste oder fehlgeschlagene Läufe überwacht.
- WebSockets: Authentifiziere beim Verbinden, sende Heartbeats, verbinde mit Backoff erneut und plane für mehrere Instanzen (gemeinsames Pub/Sub oder Sticky Sessions).
- Server-Sent Events: Bevorzuge sie gegenüber WebSockets für unidirektionale Server-zu-Client-Streams wie Benachrichtigungen, Fortschritt und LLM-Token-Streaming.
- Long Polling: Verwende es als Fallback, wenn WebSockets und SSE nicht verfügbar sind, mit Timeouts und einer Begrenzung der gehaltenen Verbindungen.
- Webhooks: Überprüfe für eingehende Webhooks Signaturen (HMAC), lehne veraltete Zeitstempel ab, um Wiederholungen zu stoppen, bestätige schnell und verarbeite asynchron, und dedupliziere nach Ereignis-ID. Signiere für ausgehende Webhooks Payloads, wiederhole mit Backoff und versioniere Ereignisformate.
6. Traffic, Edge und Netzwerk
- Ratenbegrenzung: Begrenze pro Benutzer, API-Schlüssel und IP auf öffentlichen, authentifizierten und teuren Endpunkten (Login, Registrierung, Passwort-Reset, OTP, LLM-Aufrufe). Gib 429 mit
Retry-Afterzurück. - Lastverteilung: Verteile Traffic über auf Gesundheit geprüfte Instanzen. Halte App-Server zustandslos, damit jede Instanz jede Anfrage bedienen kann.
- Reverse Proxys: Beende TLS, komprimiere und erzwinge Körpergröße- und Timeout-Grenzen am Proxy. Vertraue
X-Forwarded-Fornur von bekannten Proxys, damit Client-IPs nicht gefälscht werden können. - API-Gateways: Zentralisiere Auth, Ratenbegrenzung, Routing und Validierung, wenn es mehrere Dienste oder eine öffentliche API gibt. Eine einzelne App benötigt selten eines.
- CDN: Serviere statische Assets und Medien über ein CDN mit langen Cache-Lebensdauern und inhaltsgehashten Dateinamen.
- DNS: Senke TTLs vor Migrationen, verwalte Einträge nach Möglichkeit als Code und erwarte Ausbreitungsverzögerungen.
- TCP vs UDP: Standardmäßig TCP-basierte Protokolle. Verwende UDP nur für latenzempfindlichen Traffic, der Verlust toleriert (Echtzeit-Medien, Spiele), mit anwendungsspezifischer Handhabung.
- HTTP/2 & HTTP/3: Aktiviere sie am Edge oder CDN für Multiplexing und schnellere Verbindungen. Dies ist normalerweise Konfiguration, kein Anwendungscode.
- gRPC: Verwende es für interne Dienstaufrufe, die strenge Verträge oder Streaming benötigen, mit einer Frist für jeden Aufruf. Browser benötigen gRPC-Web oder ein Gateway.
7. Caching
- Caching: Cache nur, nachdem ein Bedarf gemessen wurde, und definiere den Schlüssel, die TTL und die Zielgruppe jedes Caches. Speichere niemals benutzerspezifische oder berechtigungsabhängige Daten in einem gemeinsam genutzten Cache unter einem generischen Schlüssel.
- Edge-Caching: Setze
Cache-Controlexplizit, markiere personalisierte Antworten als private oder no-store und verwende stale-while-revalidate, wo Frische nicht kritisch ist. - CDN-Caching: Lege für CDNs
Cache-ControlundSurrogate-Controlmit TTLs fest, die zu deinen Ressourcen und Aktualisierungsmustern passen. - HTTP-Caching: Verwende ETags oder Last-Modified für bedingte Anfragen, um Bandbreite zu sparen. Setze
Cache-Control: no-cachefür dynamische Daten, die nicht veralten dürfen, aber von der Validierung profitieren. - Anwendungs-Caching: Verwende einen speicherinternen Cache (Redis, Memcached) oder einen In-Process-Cache. Sei dir der Cache-Invalidierung, Serialisierung und Speichergrenzen bewusst.
- Cache-Invalidierung: Der schwierigste Teil. Lösche, aktualisiere oder entwerten (durch Ändern von Schlüsseln) beim Schreiben, nicht beim Lesen. Für Inhalts-Caches können Webhooks oder eine Fetch-API Aktualisierungen auslösen.
- Write-Through & Write-Behind: Leite Schreibvorgänge durch den Cache, um ihn automatisch zu füllen. Nimm bei Write-Behind ein gewisses Datenverlustrisiko in Kauf, da Schreibvorgänge im Cache bestätigt und später in die Datenbank geschrieben werden.
- Read-Through & Cache-Aside: Lade Daten beim Fehlschlag des Caches (Read-Through) oder in der Anwendung (Cache-Aside) nach. Achte auf den Thundering-Herd, bei dem mehrere Anforderungen gleichzeitig denselben Cache-Fehlschlag erleiden.
- Verteilte Caching-Muster: Erwäge für große Systeme die globale Cache-Invalidierung über Pub/Sub, konsistentes Hashing für die Cache-Aufteilung und lokale Caches zur Latenzreduzierung.
- CDN-Zwischenspeicherung: Wenn du ein CDN für dynamische APIs verwendest, setze einen kurzen TTL (z. B. 60 s) für öffentliche Endpunkte wie Produktlisten oder Blog-Artikel. Verwende benutzerspezifische Cookiewerte für personalised Antworten.
8. Performance
- Latenz: Misse die 95. und 99. Perzentil-Latenz, nicht nur den Durchschnitt. Ein hoher Durchschnitt mit niedrigem Perzentil ist in Ordnung; hohe Perzentile deuten auf Ausreißer oder Tail-Latenz hin.
- Durchsatz: Kenne die maximale Anfragenrate und die Datenmenge, die dein System verarbeiten kann, bevor die Latenz einbricht, die Fehlerquote steigt oder die Kosten explodieren.
- Startup-Zeit: Optimiere die Kaltstartzeit in serverlosen Umgebungen (keine unnötigen Abhängigkeiten, schnellere Laufzeiten). Für Container sorge dafür, dass Images klein sind und das Gesundheits-Check schnell bestanden wird.
- CPU-Grenzen: Setze CPU-Grenzen für Container oder serverlose Funktionen. Ohne Grenzen konkurrieren Instanzen um CPU-Zeit auf dem Host.
- Speichergrenzen: Setze Speichergrenzen und überwache die Nutzung. Speicherlecks führen zu OOM-Abstürzen, nicht zu allmählicher Verlangsamung.
- Speicherkontingente: Für Instanzen, die temporäre Dateien oder Caches schreiben, setze Speicherkontingente, damit eine Instanz nicht den Festplattenplatz aller anderen verbraucht.
- Asynchrone Verarbeitung: Verschiebe langsame Arbeit in eine Warteschlange, damit Anforderungen schnell zurückkehren. Der LLM-Token-Streaming ist eine Ausnahme: streame, blockiere nicht.
- Parallelität: Verarbeite unabhängige Aufgaben parallel (Goroutinen, Futures, Promise.all), aber begrenze die Parallelität auf einen angemessenen Wert unter Berücksichtigung von Ressourcen und Abhängigkeiten.
- Batch-Verarbeitung: Fasse kleine Vorgänge in Batches zusammen (z. B. Redis-Pipeline mehrerer Befehle, eine einzige Datenbankabfrage für 20 Zeilen anstelle von 20 Abfragen).
- Profiling: Vor der Optimierung, profiliere und identifiziere Engpässe. Optimiere nicht blind, was schnell genug ist. Verwende APM-Tools oder Flamegraphs, um Lecks und Hot Spots zu finden.
- Lasttests: Führe Lasttests mit realistischen Verkehrsmustern durch, einschließlich Spitzenzeiten. Miss das Verhalten unter Last, nicht nur den Leerlauf.
- Reservekapazität: Plane Überkapazität für Verkehrsspitzen und Failover. In Cloud-Umgebungen bedeutet dies Autoscaling-Margen und ausreichende Reserven in den am stärksten ausgelasteten Diensten.
- Performance-Regressionen: Überwache die Leistung im Laufe der Zeit und benachrichtige über Verschlechterungen. Führe Performance-Tests in CI als Smoke-Tests durch und flagge Ausreißer.
9. APIs
- API-Versionierung: Beginne mit Header-Pfad-Versionierung (
/v1/). Verwende für interne APIs Semver und veröffentliche Versionsänderungen. Gib veraltete Versionen mit ausreichender Vorankündigung auf. - API-Design (REST): Verwende konsistente Benennung (Substantive im Plural, hierarchisch), HTTP-Methoden (GET lesen, POST erstellen, PUT ersetzen, PATCH aktualisieren, DELETE löschen) und richtige Statuscodes. Halte Antworten unter einer Grenze (z. B. 1 MB).
- API-Design (GraphQL): Definiere Datenquoten oder Komplexitätsgrenzen pro Abfrage, deaktiviere Introspection in der Produktion und verwende Persisted Queries. Vermeide tief verschachtelte Abfragen ohne Begrenzung.
- API-Design (gRPC/ Protobuf): Definiere Verträge in
.proto, versioniere sie, verwende Unary für Anfrage/Antwort und Streaming für große Datensätze oder Echtzeit. Füge jeder RPC eine Frist hinzu. - API-Dokumentation: Halte die Dokumentation automatisch generiert und aktuell (OpenAPI für REST, Proto für gRPC). Stelle ein Playground oder eine Referenz bereit.
- API-Fehlerbehandlung: Gib konsistente Fehlerstrukturen zurück, die einen Code, eine Nachricht und eine Spur enthalten. Vermeide es, Server-Interna oder Stack-Traces nach außen zu geben.
- API-Ratenbegrenzung: Wie bereits erwähnt, begrenze die Rate auf API-Ebene zusätzlich zur anwendungsspezifischen Begrenzung.
- API-Authentifizierung & -Autorisierung: Verwende API-Schlüssel oder OAuth2 für den öffentlichen Zugriff. Überprüfe Berechtigungen in jedem Endpunkt, nicht nur einmalig.
- API-Zustandsverwaltung: Halte APIs zustandslos, es sei denn, ein bestimmter Grund erfordert Sitzungen (nicht RESTful, aber in der Praxis manchmal notwendig).
- API-Pagination & -Filterung: Paginiere nach Cursor für sich ändernde Datensätze, filtere nach Parametern, sortiere nach wählbaren Feldern und begrenze die Seitengröße.
- API-Antwort-Caching: Setze
Cache-ControlundETagfür GET-Anfragen, die zwischengespeichert werden können. VerwendeVary, um nach Kopfzeilen zu unterscheiden. - API-CORS: Wie bereits erwähnt, erlaube nur vertrauenswürdige Ursprünge und verwende keine Wildcards mit Anmeldeinformationen.
- API-WebSockets & Streaming: Dokumentiere Ereignistypen und erwartete Daten. Verwende Subprotokolle zur Trennung.
- API-Versionierungsstrategie: Gib veraltete Felder oder Endpunkte mit einem Sunset-Header auf. Kommuniziere Änderungen über Änderungsprotokolle oder Mailinglisten.
10. Observability
- Protokollierung: Strukturierte Protokolle im JSON-Format an stdout mit einem kontextuellen Korrelations-ID pro Anfrage. Gib ausreichende Details, aber kein PII. Verwende Log-Levels (debug, info, warn, error) angemessen.
- Metriken: Definiere und sammle Metriken der roten Signale: Latenz (p50, p95, p99), Fehlerrate, Durchsatz (Anfragen/Sekunde, Jobs/Sekunde, Ereignisse/Sekunde), Auslastung (CPU, Speicher, Festplatte, Netzwerk).
- Verteilte Ablaufverfolgung (Distributed Tracing): Verwende eine eindeutige Ablaufverfolgungs-ID, die über Dienste, Warteschlangen und Hintergrundjobs hinweg propagiert wird. Sende Ablaufverfolgungen an ein Backend (Jaeger, Tempo, X-Ray).
- Überwachung & Alarmierung: Alarmiere über Symptome (hohe Latenz, viele Fehler, geringer Durchsatz), nicht nur über Ursachen (hohe CPU). Verwende Schwellenwerte und Anomalieerkennung. Definiere Mitigations-SOPs in Playbooks.
- Dashboards: Erstelle Dashboards für verschiedene Zielgruppen: Entwicklung (Fehlerraten, Durchsatz), Betrieb (Infrastruktur), Management (SLIs/SLOs, Kosten).
- Kostenüberwachung: Verfolge die Kosten für Cloud-Dienste, APIs von Drittanbietern (insbesondere LLM-APIs), Datenübertragung und Lagerung. Setze Budgetgrenzen und alarmiere bei Überschreitung.
- Log-Analyse: Verwende ein Log-Management-Tool (ELK, Splunk, Grafana Loki) zur Suche, Filterung und Korrelation von Logs. Richte Muster für bekannte Probleme ein.
- Zentralisiertes Logging: Sammle Logs von allen Diensten und Instanzen an einem zentralen Ort. Verwende einen Log-Agenten, der Logs an ein zentrales Backend streamt.
- APM (Application Performance Monitoring): Verwende ein APM-Tool, um Anwendungsleistung, Transaktionen, Fehler und Abhängigkeiten in Echtzeit zu überwachen.
- SLIs, SLOs & SLAs: Definiere Service Level Indicators (Latenz, Fehlerquote, Verfügbarkeit), Service Level Objectives (die Ziele, z. B. 99,9 % Verfügbarkeit) und Service Level Agreements (die vertraglichen Verpflichtungen).
11. Tests
- Unit-Tests: Teste einzelne Funktionen oder Methoden isoliert. Verwende Mocks oder Stubs für externe Abhängigkeiten. Optimiere auf Reproduzierbarkeit und Geschwindigkeit.
- Integrationstests: Teste die Interaktion zwischen Komponenten, einschließlich Datenbanken, externen APIs und Diensten. Verwende Testcontainer oder Docker für Abhängigkeiten.
- E2E-Tests: Teste kritische Benutzerabläufe von Anfang bis Ende über die tatsächliche UI oder API. Optimiere auf Genauigkeit, nicht auf Geschwindigkeit.
- API-Tests: Teste API-Endpunkte auf korrekte Antworten, Statuscodes, Fehlerbehandlung und Ratenbegrenzung.
- Vertragstests (Contract Tests): Verifiziere, dass APIs oder Nachrichten mit der erwarteten Schnittstelle übereinstimmen (Consumer-Driven Contracts wie bei Pact).
- Smoke-Tests: Führe nach der Bereitstellung eine schnellreichende Reihe grundlegender Prüfungen durch, um sicherzustellen, dass das System gestartet ist und funktioniert.
- Regressionstests: Optimiere auf das Erkennen von Regressionen, nicht auf vollständige Abdeckung. Führe sie bei jedem Build oder vor der Bereitstellung aus.
- Load-Tests / Performance-Tests: Miss die Systemleistung unter erwarteter und übermäßiger Last, um Engpässe zu identifizieren. Optimiere auf konsistentes Verhalten.
- Chaos-Engineering: Füge kontrollierte Störungen (Ausfälle von Diensten, Netzwerklatenz) ein, um die Fehlertoleranz zu validieren. Optimiere auf Wiederherstellbarkeit.
- Testdatenmanagement: Verwende vorhersehbare, konsistente und isolierte Daten. Optimiere die Bereinigung und Wiederherstellung des Ausgangszustands zwischen Läufen.
- Flaky-Tests-Erkennung: Optimiere auf deterministische Tests. Verwende Test-Retrials mit niedriger Priorität, aber priorisiere die Ursachenbehebung.
- Testabdeckung: Optimiere auf bedeutungsvolle Abdeckung kritischer Pfade und Randfälle, nicht auf bloße Metrik. Überwache die Abdeckungstrends, nicht die absolute Zahl.
12. Auslieferung, CI/CD und Bereitstellung
- CI-Pipeline: Führe Tests, Linting und Sicherheitsscans bei jedem Commit oder Pull Request aus. Optimiere auf Geschwindigkeit und Feedback, nicht auf Perfektion.
- CD-Pipeline: Optimiere für vollautomatische Bereitstellungen in Produktion nach bestandenen Tests. Optimiere für Geschwindigkeit und Wiederholbarkeit, nicht für manuelle Überprüfung.
- Bereitstellungsstrategie: Optimiere auf Null-Ausfallzeiten und Rollback-Fähigkeit. Verwende Rolling, Blue/Green, Canary oder Feature-Flags. Optimiere auf Reduzierung des Bereitstellungsrisikos.
- Feature-Flags: Optimiere auf schrittweise Einführung von Funktionen, A/B-Tests und Kanarienvogel-Releases. Verwende einen Feature-Flag-Dienst und nicht Umgebungsvariablen für dynamische Funktionen.
- Infrastructure as Code (IaC): Optimiere auf versionierte, überprüfbare und automatisierte Bereitstellung. Verwende Terraform, Pulumi, CloudFormation oder CDK.
- Konfigurationsmanagement (nicht IaC): Optimiere auf Umgebungsvariablen oder Konfigurationsserver, nicht auf hartcodierte Werte. Verwende Geheimnisse aus Secrets Manager.
- Containerisierung: Optimiere auf kleine, sichere und reproduzierbare Container. Verwende Multi-Stage-Builds, nicht root, keine unnötigen Pakete.
- Orchestrierung: Optimiere auf Kubernetes, Nomad oder Swarm für die Planung und Verwaltung mehrerer Container. Optimiere auf Deklaration, nicht auf Skripte.
- Serverlos: Optimiere auf kurze, zustandslose Funktionen mit schnellem Start. Optimiere auf ereignisgesteuerte, nicht auf zeitgesteuerte Skalierung.
- Backup & Wiederherstellung: Optimiere auf automatische, getestete Backups mit definierten RPO und RTO. Optimiere auf die Fähigkeit zur Point-in-Time-Wiederherstellung.
- Bereitstellungsbenachrichtigungen: Optimiere auf Benachrichtigungen über Bereitstellungen in Kommunikationskanäle (Slack, Teams, E-Mail). Optimiere auf Transparenz, nicht auf Lärm.
13. Disaster Recovery
- RPO & RTO: Definiere die akzeptablen Datenverlust- und Ausfallzeiten pro System. Optimiere auf Erfüllung der Vorgaben, nicht auf Perfektion.
- Backup-Strategie: Optimiere auf die definierten RPOs/RTOs. Optimiere auf automatisierte, verschlüsselte Backups mit regelmäßigen Tests der Wiederherstellung.
- Failover-Plan: Optimiere auf dokumentierte, automatisierte Failover-Schritte für Datenbanken, Dienste und Zonen. Optimiere auf Praxis, nicht auf Theorie.
- Desaster-Recovery-Tests: Optimiere auf regelmäßige, automatisierte Tests von Failover- und Wiederherstellungsprozessen. Optimiere auf Lernen, nicht auf Bestätigung.
- Multi-Region-Bereitstellung: Optimiere auf geografische Redundanz für geschäftskritische Systeme. Optimiere auf Standby, nicht auf Read-Replica für Failover.
- Datenwiederherstellungsplan: Optimiere auf die Fähigkeit, Daten aus Backups, Replikaten oder Archiven wiederherzustellen. Optimiere auf Tests, nicht auf Hoffnung.
- Incident-Response-Plan: Optimiere auf dokumentierte, getestete Prozesse für die Reaktion auf Vorfälle, Benachrichtigungen und Eskalation. Optimiere auf Playbooks, nicht auf Ad-hoc-Aktionen.
14. Client-seitig
- Client-seitige Sicherheit: Optimiere auf sichere Speicherung von Tokens (kein localStorage für sensible Tokens), Eingabevalidierung (Server ist die letzte Verteidigungslinie) und Schutz vor XSS (wie zuvor).
- Client-seitige Leistung: Optimiere auf schnelle Ladezeiten (First Contentful Paint, Largest Contentful Paint, First Input Delay). Optimiere auf Code-Splitting, Lazy Loading und minimierte Bundles.
- Client-seitige Zuverlässigkeit: Optimiere auf Offline-Unterstützung, Netzwerkfehlerbehandlung und Anzeige von Cachedaten, wenn das Backend nicht verfügbar ist. Optimiere auf Fehlertoleranz, nicht nur auf UX.
- Client-seitige Observability: Optimiere auf clientseitige Fehlerprotokollierung, Performance-Monitoring und Benutzeraktionen (Analytics). Optimiere auf Erkenntnisse, nicht auf Rohdaten.
- Zugänglichkeit (A11y): Optimiere auf WCAG-Compliance, semantisches HTML, Tastaturnavigation und Screenreader-Unterstützung.
- Internationalisierung (i18n): Optimiere auf übersetzte Zeichenketten, Datums-/Währungsformatierung und bidirektionalen Text, wo zutreffend.
- Datenvisualisierung: Optimiere auf effektive und genaue Darstellung von Daten. Optimiere auf Klarheit, nicht auf visuelle Komplexität.
- Forms & Eingabe: Optimiere auf feldweise Validierung, Fehlermeldungen und Barrierefreiheit (z. B. Aria-Attribute).
15. LLM-Funktionen
- Prompt-Injection-Schutz: Optimiere auf Trennung von Anweisungen und Daten, Eingabebereinigung und Ausgabeprüfung, um Prompt-Injection zu verhindern. Verwende eine robustere System-Prompt-Struktur.
- Ausgabevalidierung: Optimiere auf Überprüfung der LLM-Ausgabe auf Format, Schema und Inhaltsfilterung (z. B. keine sensiblen Daten oder SQL-Injection in generierten Abfragen).
- Kostenkontrolle: Optimiere auf Token-Budget, Ratenbegrenzung und Modellauswahl, um Kosten zu kontrollieren. Verwende Caching für wiederkehrende Abfragen und Prompt-Komprimierung.
- Ratenbegrenzung & Quoten: Optimiere auf Begrenzung von LLM-Aufrufen pro Benutzer, API-Schlüssel und Zeitintervall, um Kosten und Missbrauch zu kontrollieren.
- Modell-Rollout & -Versionierung: Optimiere auf Testen neuer Modelle gegen deine Anwendungsfälle. Verwende Staging-Tests und allmähliches Rollout, um Regressionen zu erkennen.
- Sicherheit & Datenschutz: Optimiere auf Vermeidung des Sendens sensibler Daten an LLM-Anbieter. Verwende lokale oder private Modelle für sensible Workloads.
- Fehlerbehandlung & Fallbacks: Optimiere auf LLM-bezogene Fehler (Ratenbegrenzung, Modellfehler, Timeouts). Optimiere auf Fallback-Pläne (z. B. einfachere Modelle oder zwischengespeicherte Antworten).
- Überwachung & Metriken: Optimiere auf Metriken zu LLM-Aufrufen: Latenz, Token, Kosten, Fehlerrate, Antwortqualität (z. B. menschliches Feedback). Optimiere auf Nachvollziehbarkeit, nicht auf Rohzahlen.
- Ausgabeformatierung: Optimiere auf strukturierte Ausgaben (JSON, Markdown) für die programmatische Handhabung. Optimiere auf Konsistenz, nicht auf Kreativität.
- Daten, die für LLM-Abfragen verwendet werden: Optimiere auf In-Kontext-Lernen (Beispiele in Prompts) oder Feinabstimmung mit domänenspezifischen Daten. Optimiere auf Relevanz, nicht auf Vollständigkeit.
16. Kostenoptimierung
- Ressourcennutzung: Optimiere auf die richtige Dimensionierung von Instanzen, Containern und Datenbanken. Optimiere auf Auslastung, nicht auf Überbereitstellung.
- Speicherkosten: Optimiere auf Speicherverwaltung: Tiered Storage, Archivierung ungenutzter Daten, Löschen veralteter Backups.
- Netzwerkkosten: Optimiere auf Datenübertragungskosten zwischen Regionen, Diensten und zum Internet. Optimiere auf Datenlokalität, nicht auf Zentralisierung.
- Dienstkosten: Optimiere auf die Kosten von Drittanbieter-APIs, verwalteten Diensten und Lizenzgebühren. Optimiere auf Kostenbewusstsein, nicht auf Billigkeit.
- Lebenszyklus-Management: Optimiere auf das Ablaufen / Entfernen von Ressourcen, die nicht mehr benötigt werden (UAT-Umgebungen, alte Container-Images, nicht referenzierte Datenspeicher).
- Serverlose Kosten: Optimiere auf Kaltstartvermeidung durch Provisioned Concurrency (wenn die Kosten es wert sind) und Vermeidung langer Funktionsausführungen, die die Abrechnungsgrenzen erhöhen.
- CDN-Kosten: Optimiere auf CDN-Cache-Trefferquoten und Datenübertragungskosten. Optimiere effiziente Cache-Strategien für eine hohe Trefferquote.
- Datenbankkosten: Optimiere auf Datenbankinstanzgröße, Speicherbereitstellung und IOPS. Optimiere auf Serverless- oder Autoscaling-Datenbanken für variable Workloads.
- Kostenbudgets & -warnungen: Optimiere auf definierte Budgetschwellen und automatische Warnungen bei Überschreitung. Optimiere auf Kostenkontrolle, nicht auf Kostenvermeidung.
- Reservierte Instanzen & Sparpläne: Optimiere auf Verpflichtungen zu langfristigen Rabatten für stabile Workloads. Optimiere auf Vorhersagbarkeit, nicht auf Flexibilität.
17. Externe Integrationen
- Abhängigkeitsmanagement: Optimiere auf die Anzahl der Drittanbieter-APIs, Datenquellen und Dienste, von denen du abhängig bist. Optimiere auf Begrenzung, nicht auf Vollständigkeit.
- API-Keys & -Tokens: Optimiere auf geheime und rotierende API-Keys und -Tokens, die für jede Integration spezifisch sind. Speichere sie in einem Secrets Manager.
- Service Level Agreements (SLAs): Optimiere auf die SLAs von Drittanbietern und ob sie deinen Anforderungen entsprechen. Optimiere auf Ausfallsicherheit, nicht auf blindes Vertrauen.
- Fehlerbehandlung & Fallbacks: Optimiere auf die spezifischen Fehlerbedingungen jedes Anbieters (Rate Limits, Timeouts, Serverfehler). Optimiere auf Fallback-Pläne (Cachedaten, alternative Dienste, manuelle Bearbeitung).
- Datenschutz & Compliance: Optimiere auf Datenverarbeitungsvereinbarungen (Data Processing Agreements, DPAs) und die Einhaltung von Vorschriften durch Drittanbieter (z. B. DSGVO, SOC 2, PCI).
- Auswirkungen von Drittanbieter-Ausfällen: Optimiere auf die Auswirkungen eines Ausfalls des Drittanbieters auf dein System. Optimiere auf Notfallpläne, nicht auf Hoffnung.
- Retry-Strategien: Optimiere auf die Retry-Strategien, die von APIs von Drittanbietern erwartet werden (z. B.
Retry-After-Header, exponentielle Backoffs). Optimiere auf Respekt, nicht auf Missbrauch. - Monitoring von Drittanbietern: Optimiere auf die Überwachung der Verfügbarkeit, Latenz und Fehlerquoten von Drittanbieter-Diensten. Optimiere auf Erkennung, nicht auf Reaktion.
- Verträge & Lizenzen: Optimiere auf das Verständnis der Nutzungsbedingungen, Preisgestaltung und Datenverarbeitungsbedingungen von Drittanbietern. Optimiere auf Lesen, nicht auf Klicken.
- Exit-Strategie: Optimiere auf das Verständnis der Kosten und des Aufwands für den Wechsel des Drittanbieters. Optimiere auf Portabilität, nicht auf Vendor Lock-in.