Aller au contenu

PD-172 — Rate limiting distribué Redis multi-dimensions (contractuel V2)

1. Objectif

La User Story PD-172 définit un contrat de limitation de débit distribué, cohérent multi-instances, pour protéger les endpoints critiques du backend ProbatioVault contre les abus automatisés, tout en préservant la disponibilité globale.

Objectifs contractuels :

  • protéger l’authentification contre le bruteforce ;
  • plafonner les endpoints coûteux ;
  • garantir l’équité entre tenants ;
  • rendre chaque blocage observable côté exploitation ;
  • fournir des signaux client standard (X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After) ;
  • appliquer une stratégie Redis-down différenciée par famille de routes, avec code HTTP normatif ;
  • rester conforme RGPD (minimisation des données dans Redis, diagnostic opérationnel conservé en logs).

2. Périmètre / Hors périmètre

Inclus

  • Évaluation rate-limit avant exécution logique métier.
  • Dimensions V1 obligatoires : ip, user_id, tenant, route.
  • Politique multi-fenêtres V1 : burst + sustained.
  • Garde-fou global tenant : 500 req/min (sustained).
  • Réponse 429 en cas de dépassement quota.
  • Stratégie Redis indisponible :
  • auth : fail-closed 503 + Retry-After
  • read : fail-open contrôlé
  • costly (upload/export/proof) : fail-closed 503 + Retry-After
  • Routes santé /health/* et /ready/* : profil dédié très élevé (pas de whitelist).
  • Évaluation atomique multi-dimensions/multi-fenêtres en une seule commande Redis Lua.
  • Observabilité : logs structurés + métriques exploitables.
  • Configuration statique au boot (V1).

Exclu

  • Anti-DDoS réseau/CDN/WAF.
  • CAPTCHA.
  • Device fingerprinting.
  • Quotas billing/pricing.
  • Limitation BullMQ/jobs.
  • Whitelist/bypass ops V1.
  • API key en dimension V1 (prévu V2).
  • Reload dynamique de configuration sans redéploiement (V2).

3. Définitions

Terme Définition
Rate-limit check Décision d’autorisation/refus avant métier.
burst Fenêtre courte anti-rafale.
sustained Fenêtre longue anti-abus continu.
fail-open Requête autorisée si backend de quota indisponible.
fail-closed Requête refusée si backend de quota indisponible.
Redis indisponible Vrai si au moins une condition est vraie : timeout > 50 ms sur check quota, ou connection refused/reset, ou circuit-breaker local en état OPEN.
identifier_raw Identifiant canonique avant pseudonymisation (utilisé en mémoire applicative et en logs sécurité).
identifier_hmac hex(lower(HMAC-SHA256(secret, identifier_raw))), utilisé dans les clés Redis.
route_key base64url(route normalisée, sans padding) pour composition de clé Redis sûre.
Machine d’état requête État de décision pour une requête unique (RECEIVED -> terminal).
Machine d’état système État du sous-système rate-limit inter-requêtes (HEALTHY/DEGRADED/RECOVERING).
Endpoint sensible Endpoint avec protection plus restrictive que le profil générique.
Endpoint coûteux Endpoint à coût CPU/IO élevé (ex: upload/export/proof).

4. Invariants (non négociables)

ID Règle Justification
INV-172-01 Pour une même entrée normalisée (route, dimension, identifier, fenêtres actives), la décision rate-limit DOIT être identique quelle que soit l’instance backend. Cohérence inter-instance.
INV-172-02 Si la décision est refus, la logique métier cible NE DOIT PAS s’exécuter. Atomicité quota-métier.
INV-172-03 Tout refus (429 ou 503 fail-closed) DOIT produire un événement observable (log structuré + métrique). Exploitabilité opérationnelle.
INV-172-04 Les endpoints sensibles DOIVENT avoir un profil plus restrictif que le profil générique sur au moins une fenêtre ou une dimension. Hiérarchie de protection.
INV-172-05 La stratégie Redis-down DOIT respecter : auth=fail-closed, read=fail-open contrôlé, costly=fail-closed. Arbitrage sécurité/disponibilité.
INV-172-06 Le modèle d’états requête (§5.4) est normatif ; toute transition non listée est interdite. Évite ambiguïté de comportement.
INV-172-07 Aucun mécanisme de whitelist/bypass n’est autorisé en V1. Réduction du risque d’exemption abusive.
INV-172-08 La configuration des seuils est figée au boot en V1. Stabilité opérationnelle et reproductibilité.
INV-172-09 Les formats de données sont définis une seule fois en §5.1 ; toute autre section y fait référence. Source de vérité unique.
INV-172-10 L’évaluation multi-dimensions/multi-fenêtres DOIT être faite en une commande Redis Lua atomique. Évite divergences et races multi-clés.
INV-172-11 Redis NE DOIT PAS contenir d’IP brute ni d’identifiants bruts ; uniquement identifier_hmac. Minimisation RGPD.
INV-172-12 Les logs sécurité PEUVENT contenir client_ip_raw pour diagnostic, avec rétention maximale 7 jours. Besoin de diagnostic + proportionnalité RGPD.
INV-172-13 /health/* et /ready/* DOIVENT utiliser un profil dédié haut (10000 req/min) et NE SONT PAS une whitelist. Disponibilité monitoring sans bypass.
INV-172-14 Les clés rate-limit ont un TTL plafonné et un budget mémoire dédié (256 MB sur db=2). Maîtrise du risque DoS par cardinalité.

5. Flux nominaux

5.1 Modèle de données contractuel (source de vérité unique)

Donnée Format / encodage Taille / longueur Jeu de caractères Casse Validation Comportement si invalide
route chemin HTTP absolu normalisé (template route) 1..256 chars ASCII URL path case-sensitive ^/[A-Za-z0-9._~!$&'()*+,;=:@%/-]{1,255}$ rejet 400 ERR-172-03
route_key base64url(route UTF-8, sans '=') 1..344 chars [A-Za-z0-9_-] case-sensitive ^[A-Za-z0-9_-]{1,344}$ rejet 500 ERR-172-04
dimension enum 1 valeur ip\|user_id\|tenant\|route lowercase ^(ip|user_id|tenant|route)$ rejet 400 ERR-172-03
identifier_raw valeur canonique pré-hash 1..256 chars selon dimension case-sensitive ip: IPv4/IPv6 canonique ; user_id/tenant/route: ^[A-Za-z0-9._:@/-]{1,256}$ rejet 400 ERR-172-03
identifier_hmac hex(lower(HMAC-SHA256(secret, identifier_raw))) 64 chars [a-f0-9] lowercase ^[a-f0-9]{64}$ rejet 500 ERR-172-04
redis_key rate_limit:v1:{route_key}:{dimension}:{identifier_hmac}:{window_kind} 32..512 chars [A-Za-z0-9:_-] case-sensitive ^rate_limit:v1:[A-Za-z0-9_-]{1,344}:(ip|user_id|tenant|route):[a-f0-9]{64}:(burst|sustained)$ rejet 500 ERR-172-04
window_kind enum 1 valeur burst\|sustained lowercase ^(burst|sustained)$ rejet 500 ERR-172-05
route_family enum 1 valeur auth\|read\|costly lowercase ^(auth|read|costly)$ rejet 500 ERR-172-05
route_profile enum 1 valeur auth\|read_standard\|costly\|health_monitoring lowercase regex enum stricte rejet 500 ERR-172-05
decision_state enum 1 valeur ALLOWED\|THROTTLED\|BYPASS_DEGRADED\|DENIED_DEGRADED\|REJECTED_INVALID_CONTEXT UPPERCASE regex enum stricte rejet 500 ERR-172-05
system_state enum 1 valeur HEALTHY\|DEGRADED\|RECOVERING UPPERCASE regex enum stricte rejet 500 ERR-172-05
X-RateLimit-Limit entier décimal 1..10 chars [0-9] n/a ^[0-9]{1,10}$ réponse non conforme
X-RateLimit-Remaining entier décimal 1..10 chars [0-9] n/a ^[0-9]{1,10}$ réponse non conforme
Retry-After entier décimal (secondes) 1..6 chars [0-9] n/a ^[0-9]{1,6}$ réponse non conforme

Règles de normalisation complémentaires :

  • Si user_id est absent : valeur canonique anonymous.
  • Si tenant est absent : valeur canonique public.
  • Si ip ou route est absent/non fiable : ERR-172-03.

Note C-01 (résolue) :

  • Exemple route valide : /api/v1/:id.
  • Exemple route_key correspondant : L2FwaS92MS86aWQ.
  • La clé Redis reste valide car route n’est jamais injectée brute dans un segment séparé par :.

Note RGPD C-03 (tranchée) :

  • Clé Redis : uniquement identifier_hmac.
  • Logs sécurité : client_ip_raw autorisé pour diagnostic anti-abus.
  • Rétention client_ip_raw : 7 jours max, accès restreint SOC/SRE.
  • Base légale : intérêt légitime sécurité (RGPD art. 6(1)(f)), minimisation appliquée.

5.2 Bornes numériques obligatoires

Paramètre Défaut Min Max Unité Contexte Comportement hors bornes
redis_db_index 2 0 15 index DB runtime rejet configuration au boot
redis_timeout_unavailable_ms 50 10 200 ms définition Redis indisponible rejet configuration au boot
latency_rate_limit_check_p99 5 0 5 ms backend API P99 non-conformité perf + alerte
redis_rtt_per_check_max 1 1 1 RTT décision unitaire non-conformité perf
dimensions_count_v1 4 4 4 dimensions V1 rejet config si différent
windows_per_route_v1 2 2 2 fenêtres burst+sustained rejet config si différent
retry_after_fail_closed_seconds 1 1 60 s réponses 503 fail-closed rejet config si hors bornes
key_ttl_max_seconds 3600 60 3600 s garde-fou anti-cardinalité rejet config si hors bornes
redis_memory_budget_mb_db2 256 64 512 MB budget logique rate-limit ouverture circuit-breaker + alerte
raw_ip_log_retention_days 7 1 30 jours conformité RGPD non-conformité sécurité/compliance
degraded_clearing_cycles 3 1 10 cycles retour HEALTHY rejet config si hors bornes

Profils contractuels par défaut :

Profil Routes cibles Burst Sustained Dimensions évaluées
auth /auth/login, /auth/otp, /auth/refresh 5 req / 10s 20 req / 60s ip,user_id,tenant,route
costly /documents/upload, /exports, /proof/generate 3 req / 10s 10 req / 60s ip,user_id,tenant,route
read_standard routes lecture métier 30 req / 10s 120 req / 60s ip,user_id,tenant,route
health_monitoring /health/*, /ready/* 2000 req / 10s 10000 req / 60s ip,user_id,tenant,route

Garde-fou global tenant (contractuel) :

Paramètre Valeur
tenant_global_sustained.max_requests 500
tenant_global_sustained.window_seconds 60
Scope dimension tenant, clé route_key="__global__", fenêtre sustained

5.3 SLA temporels (fenêtres et expiration)

Paramètre SLA Défaut Min Max Configurabilité Comportement à expiration
ttl_padding_seconds 5 1 30 statique au boot (V1) TTL effectif recalculé à chaque incrément
burst_window_ttl 15 11 3600 dérivé (10 + padding) compteur burst expiré puis recréé au prochain hit
sustained_window_ttl 65 61 3600 dérivé (60 + padding) compteur sustained expiré puis recréé
tenant_global_ttl 65 61 3600 dérivé guardrail tenant réévalué au prochain hit
degraded_probe_interval_seconds 10 1 60 statique au boot sonde de sortie de mode dégradé
degraded_clearing_cycles 3 1 10 statique au boot retour HEALTHY après N sondes successives

Règle absolue : aucune clé rate_limit:v1:* ne doit survivre au-delà de key_ttl_max_seconds=3600.

5.4 Machine d’états contractuelle (requête)

États :

  • RECEIVED
  • ALLOWED (terminal)
  • THROTTLED (terminal)
  • BYPASS_DEGRADED (terminal)
  • DENIED_DEGRADED (terminal)
  • REJECTED_INVALID_CONTEXT (terminal)

Transitions autorisées :

État source État cible Statut Condition HTTP
RECEIVED ALLOWED AUTORISÉE quotas respectés réponse métier
RECEIVED THROTTLED AUTORISÉE quota dépassé 429 + headers RL
RECEIVED BYPASS_DEGRADED AUTORISÉE Redis indisponible + route_family=read réponse métier
RECEIVED DENIED_DEGRADED AUTORISÉE Redis indisponible + route_family=auth|costly 503 + Retry-After
RECEIVED REJECTED_INVALID_CONTEXT AUTORISÉE contexte invalide (ip/route invalides) 400

Transitions interdites :

État source Transition sortante Statut Justification
ALLOWED -> * INTERDITE terminal
THROTTLED -> * INTERDITE terminal
BYPASS_DEGRADED -> * INTERDITE terminal
DENIED_DEGRADED -> * INTERDITE terminal
REJECTED_INVALID_CONTEXT -> * INTERDITE terminal

5.4 bis Machine d’états système (inter-requêtes)

États :

  • HEALTHY
  • DEGRADED
  • RECOVERING

Transitions autorisées :

État source État cible Condition
HEALTHY DEGRADED détection Redis indisponible
DEGRADED RECOVERING première sonde Redis réussie
RECOVERING HEALTHY degraded_clearing_cycles sondes successives réussies
RECOVERING DEGRADED échec sonde

Clarification C-02 :

  • La machine requête décide la réponse HTTP d’une requête.
  • La machine système décrit la santé du sous-système quota entre requêtes.
  • Elles sont distinctes et non substituables.

5.5 Atomicité multi-composant

Scope Synchrone/Async Garantie
Évaluation quotas (4 dimensions x 2 fenêtres + guardrail tenant) Synchrone Une seule commande Redis EVALSHA atomique
Émission log structuré Async immédiat Traçabilité refus exigée (INV-172-03)
Émission métrique Async immédiat Observabilité SRE
Crash pré-décision n/a aucune exécution métier
Crash post-décision / pré-observabilité n/a incident d’exploitation (non-conformité INV-172-03)

Contrat Lua normatif :

  1. L’API calcule toutes les clés Redis nécessaires.
  2. L’API appelle EVALSHA rate_limit_v1.lua une seule fois.
  3. Le script lit toutes les fenêtres/dimensions, détecte tout dépassement, calcule retry_after.
  4. Si dépassement : retour THROTTLED, aucune décision partielle multi-clé.
  5. Sinon : incrément + TTL de toutes les clés concernées dans la même exécution atomique.

5.6 Stratégie de migration DDL

Aucune modification de schéma SQL requise pour PD-172.
Aucune migration DDL applicable.

5.7 Mécanismes de protection distribuée

Mécanisme Applicabilité Contrat
Lock distribué Non applicable L’atomicité Redis Lua couvre la section critique quota.
Idempotence Non applicable (requête API) Chaque requête compte comme tentative distincte.
Réconciliation Applicable Sonde toutes les 10s; sortie de dégradé après 3 succès consécutifs.
Rate-limiting Applicable Granularité V1 obligatoire : ip + user_id + tenant + route; dépassement => 429.
Clearing conditionnel Applicable Circuit-breaker OPEN si indisponibilité répétée ou budget mémoire dépassé; fermeture selon cycles conformes.

Checklist protection distribuée :

  • Lock : raison de non-applicabilité documentée.
  • Idempotence : raison de non-applicabilité documentée.
  • Réconciliation : intervalle et règles définis.
  • Rate-limit : granularité + dépassement définis.
  • Clearing : cycles et comportement définis.

5.8 Contraintes inter-modules

Élément Contrat PD-172
Routes à protéger /auth/login, /auth/otp, /auth/refresh, /documents/upload, /exports, /proof/generate, routes lecture, /health/*, /ready/*
Mécanisme de protection Contrôle rate-limit en pré-traitement route
Données cross-module nécessaires request.path, request.ip, request.user.sub, request.user.tenant
Résolution FK cross-module Non applicable
Scope d’enregistrement Ciblé par profils de routes
Exceptions d’accès Aucune exception whitelist/bypass en V1

5bis. Diagrammes (si applicable)

Diagramme d’état requête (stateDiagram-v2)

stateDiagram-v2
    [*] --> RECEIVED
    RECEIVED --> ALLOWED : quotas OK
    RECEIVED --> THROTTLED : quota depasse
    RECEIVED --> BYPASS_DEGRADED : redis down + route_family=read
    RECEIVED --> DENIED_DEGRADED : redis down + route_family=auth|costly
    RECEIVED --> REJECTED_INVALID_CONTEXT : contexte invalide
    ALLOWED --> [*]
    THROTTLED --> [*]
    BYPASS_DEGRADED --> [*]
    DENIED_DEGRADED --> [*]
    REJECTED_INVALID_CONTEXT --> [*]

Diagramme d’état système (stateDiagram-v2)

stateDiagram-v2
    [*] --> HEALTHY
    HEALTHY --> DEGRADED : redis indisponible
    DEGRADED --> RECOVERING : sonde succes
    RECOVERING --> HEALTHY : N succes consecutifs
    RECOVERING --> DEGRADED : sonde echec

Diagramme de séquence (sequenceDiagram)

sequenceDiagram
    participant C as Client
    participant API as Backend API (NestJS)
    participant RL as Redis RateLimit (db=2)
    participant OBS as Logs/Metrics

    C->>API: HTTP request(route, ip, auth context)
    API->>API: normalize route + identifier_raw
    API->>API: route_key=base64url(route)
    API->>API: identifier_hmac=HMAC-SHA256(secret, identifier_raw)
    API->>API: compose all redis keys
    API->>RL: EVALSHA rate_limit_v1.lua (single atomic command)
    RL-->>API: {decision, remaining, retry_after, system_state}

    alt decision=ALLOWED
        API->>OBS: metric decision=ALLOWED
        API-->>C: response metier + X-RateLimit-Limit + X-RateLimit-Remaining
    else decision=THROTTLED
        API->>OBS: log+metric decision=THROTTLED
        API-->>C: 429 + X-RateLimit-* + Retry-After
    else decision=BYPASS_DEGRADED
        API->>OBS: log+metric decision=BYPASS_DEGRADED
        API-->>C: response metier (fail-open controle)
    else decision=DENIED_DEGRADED
        API->>OBS: log+metric decision=DENIED_DEGRADED
        API-->>C: 503 + Retry-After
    end

6. Cas d’erreur

Code Cas Réponse contractuelle
ERR-172-01 Quota dépassé (burst ou sustained) 429 + X-RateLimit-Limit + X-RateLimit-Remaining + Retry-After
ERR-172-02 Redis indisponible sur route fail-closed (auth|costly) 503 Service Unavailable + Retry-After
ERR-172-03 Contexte invalide (ip/route absents ou invalides) 400
ERR-172-04 Clé Redis construite hors format contractuel 500
ERR-172-05 Profil de limite manquant/invalide au boot démarrage refusé
ERR-172-06 Timeout check quota (>50ms) traité comme Redis indisponible (ERR-172-02 ou fail-open read)
ERR-172-07 IP client non résolue de manière fiable via chaîne proxy 400
ERR-172-08 Saturation cardinalité/mémoire (>256MB sur budget RL) ouverture circuit-breaker + alerte + matrice fail-open/fail-closed

7. Critères d’acceptation (testables)

ID Critère Observable
CA-172-01 Le quota est partagé globalement entre instances backend. Même client atteint la limite indépendamment de l’instance.
CA-172-02 Tout dépassement renvoie 429 avec headers standard. X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After présents.
CA-172-03 Les profils auth/costly/read appliquent les seuils contractuels chiffrés. Seuils mesurés = 5/10s & 20/60s, 3/10s & 10/60s, 30/10s & 120/60s.
CA-172-04 Les dimensions V1 ip,user_id,tenant,route sont exploitées. Variation d’une dimension change la clé et la décision.
CA-172-05 Deux fenêtres sont actives par route (burst + sustained). Dépassement d’une fenêtre suffit à refuser.
CA-172-06 Tout refus est observable en logs/métriques. Événement structuré + métrique par refus.
CA-172-07 Redis down applique la matrice fail-open/fail-closed. read bypass, auth|costly en 503 + Retry-After.
CA-172-08 Le check rate-limit respecte P99 <= 5 ms. Mesure perf instrumentée.
CA-172-09 L’évaluation multi-dimensions est atomique en une commande Redis. Un seul EVALSHA par requête, pas de divergence multi-clé.
CA-172-10 route avec : produit une clé Redis valide. Ex. /api/v1/:id accepté et clé conforme regex.
CA-172-11 Redis ne stocke que des identifiants pseudonymisés HMAC. Aucune IP brute / user_id brut dans rate_limit:v1:*.
CA-172-12 Les logs sécurité conservent IP brute avec rétention limitée. client_ip_raw présent, purge <= 7 jours.
CA-172-13 /health/* et /ready/* ont un profil dédié haut sans whitelist. 10000 req/min effectif, aucun bypass dédié.
CA-172-14 Budget cardinalité mémoire et TTL max sont respectés. TTL <= 3600s, budget logique <=256MB, alerte sinon.
CA-172-15 Garde-fou global tenant 500 req/min actif. Dépassement tenant global bloque même si route individuelle sous seuil.

8. Scénarios de test (Given / When / Then)

ID Given When Then
ST-172-01 2 instances backend actives un même client dépasse un quota partagé refus cohérent sur les 2 instances
ST-172-02 profil route défini et quota atteint requête supplémentaire même fenêtre 429 + headers contractuels
ST-172-03 route sensible + route générique campagnes identiques seuil sensible atteint plus tôt
ST-172-04 dimensions V1 renseignées variation d’une seule dimension décision recalculée selon nouvelle clé
ST-172-05 fenêtres burst et sustained actives dépassement de burst uniquement refus immédiat
ST-172-06 refus de quota généré consultation logs/métriques trace exploitable présente
ST-172-07 Redis indisponible + /auth/login appel route 503 + Retry-After
ST-172-08 Redis indisponible + route lecture appel route réponse métier (fail-open contrôlé)
ST-172-09 charge représentative mesure latence check P99 <= 5 ms
ST-172-10 redémarrage sans changement config trafic identique comportement stable
ST-172-11 route /api/v1/:id génération de clé Redis clé conforme regex redis_key
ST-172-12 trafic normal inspection clés Redis identifiants uniquement en HMAC
ST-172-13 trafic monitoring élevé /health/live 9000 req/min pas de throttling avant seuil contractuel
ST-172-14 tenant en trafic multi-routes total > 500 req/min throttling tenant global
ST-172-15 budget mémoire RL > 256MB nouvelle vague de requêtes circuit-breaker OPEN + alerte + matrice dégradée
ST-172-16 état système DEGRADED 3 sondes consécutives réussies transition RECOVERING -> HEALTHY

9. Hypothèses explicites

ID Hypothèse Impact si faux
H-172-01 La normalisation des templates de route NestJS est déterministe. Risque de clés divergentes entre instances.
H-172-02 La chaîne proxy de confiance est correctement configurée. Risque d’erreurs IP (ERR-172-07).
H-172-03 L’infrastructure permet la purge stricte des logs IP bruts à 7 jours. Risque de non-conformité RGPD.
H-172-04 Le budget mémoire rate-limit est monitorable sur le périmètre dédié. Détection tardive de saturation cardinalité.

10. Points clarifiés

10.1 Contraintes techniques (stack réelle)

Élément Valeur contractuelle
Projet cible ProbatioVault-backend
Langage principal TypeScript
Framework backend NestJS
ORM TypeORM
Base de données métier PostgreSQL
Backend rate limiting distribué Redis
Files/jobs (hors périmètre PD-172) BullMQ

10.2 Décisions tranchées dans cette version

ID historique Décision normative V2
Q-172-01 / Q-172-02 Seuils burst/sustained fournis par profil (auth, costly, read, health)
Q-172-03 Fail-closed fixé à 503 Service Unavailable + Retry-After
Q-172-05 identifier_hmac en Redis, IP brute uniquement en logs sécurité (7 jours max)
Q-172-06 /health/* et /ready/* : profil dédié 10000 req/min, pas de whitelist
C-05 / H-04 Atomicité multi-clé contractualisée via script Lua unique
A-01 Redis indisponible défini formellement (timeout>50ms ou connection refused/reset ou breaker OPEN)
R-02 TTL max des clés + budget mémoire 256MB sur db=2 contractualisés
DIV-01 Référentiel Epic harmonisé vers PD-186

10.3 Questions résiduelles (non bloquantes)

ID Point résiduel Impact
Q-172-04 Liste exhaustive des routes read métier couverture fonctionnelle à finaliser côté PO
Q-172-09 Cardinalité maximale des labels métriques tuning observabilité / coût
Q-172-11 Détail fin de stratégie proxy trust multi-environnements robustesse IP canonique

10.4 Learnings contextuels intégrés

Source Learning intégré Effet contractuel
PD-180 Le rate-limit ne doit pas perdre d’événements en charge ; observabilité obligatoire. INV-172-03 + CA-172-06/07 renforcés.
PD-81 Toute logique temporelle doit formaliser SLA min/max/default. §5.3 entièrement borné (plus de NON FOURNI).

Références

  • Epic : PD-186 — Backend Core sécurisé et modulaire
  • JIRA : PD-172
  • Repos concernés : ProbatioVault-backend
  • Documents associés :
  • docs/epics/backend-core/PD-172-rate-limiting-redis/PD-172-besoin.md
  • docs/epics/backend-core/PD-172-rate-limiting-redis/PD-172-clarifications.md
  • src/config/rate-limit.config.ts
  • src/config/config.schema.ts
  • src/common/middleware/global-rate-limit.middleware.ts