Aller au contenu

PD-285 — Plan d'implémentation

1. Découpage en composants

# Composant Responsabilité Fichier(s) Impact
C1 Migration SQL UPDATE max_size_bytes de 104857600 à 524288000 pour DEFAULT et B2C_EVIDENCE_MINOR src/database/migrations/<timestamp>-RaiseMaxSize500MB.ts Données DB
C2 Tests unitaires config Mettre à jour les valeurs de mock et assertions de 104857600 à 524288000 test/unit/**/category-config.service.spec.ts, test/unit/**/deposit.controller.spec.ts Tests
C3 Amendement PD-252 Modifier PD-252-besoin.md et PD-252-specification.md : 100 MB500 MB ProbatioVault-doc/docs/epics/legal-compliance/PD-252-*/PD-252-besoin.md, PD-252-specification.md Documentation
C4 Cohérence inter-EB Vérifier que la pipeline coherence-report.py ne signale plus l'écart PD-101 vs backend Script existant scripts/coherence/coherence-report.py Validation

Pas de composant logiciel modifié : Le middleware (category-size.middleware.ts) et le service (category-config.service.ts) lisent maxSizeBytes depuis la DB. Il n'y a aucune constante hardcodée dans le code applicatif — seule la migration seed contient 104857600. Le relèvement se fait par migration SQL uniquement.

2. Flux techniques

Flux F1 — Migration DB (C1)

1. TypeORM exécute la migration
2. UPDATE vault_secure.document_category_configs
   SET max_size_bytes = 524288000, updated_at = NOW()
   WHERE category IN ('DEFAULT', 'B2C_EVIDENCE_MINOR')
3. Le cache CategoryConfigService expire après 60s (INV-T5-03)
4. Les requêtes suivantes utilisent la nouvelle limite

Flux F2 — Validation upload (existant, inchangé)

1. Requête upload → CategorySizeMiddleware
2. Middleware lit Content-Length, compare à resolve(null).maxSizeBytes (désormais 524288000)
3. Si > 524288000 → PayloadTooLargeException ERR-79-004
4. Sinon → DepositController → CategoryConfigService.assertSizeAllowed()
5. Si taille réelle > 524288000 → PayloadTooLargeException ERR-79-004
6. Sinon → flux nominal (dépôt, hash, stockage)

Flux F3 — Amendement documentaire (C3)

1. Modifier PD-252-besoin.md : remplacer "max 100 MB" par "max 500 MB" pour les 2 catégories
2. Modifier PD-252-specification.md : remplacer la valeur 100 par 500 dans le tableau des seuils
3. Vérifier cohérence textuelle entre les deux documents

2bis. Diagrammes Mermaid

Graphe de dépendances entre composants

graph TD
    C1["C1 — Migration SQL<br/><code>RaiseMaxSize500MB.ts</code>"]
    C2["C2 — Tests unitaires config<br/><code>category-config.service.spec.ts</code><br/><code>deposit.controller.spec.ts</code>"]
    C3["C3 — Amendement PD-252<br/><code>PD-252-besoin.md</code><br/><code>PD-252-specification.md</code>"]
    C4["C4 — Cohérence inter-EB<br/><code>coherence-report.py</code>"]

    DB[("vault_secure.<br/>document_category_configs")]
    MW["CategorySizeMiddleware<br/>(existant, inchangé)"]
    SVC["CategoryConfigService<br/>(existant, inchangé)"]
    CACHE["Cache TTL 60s<br/>(INV-T5-03)"]

    C1 -->|UPDATE max_size_bytes| DB
    DB -->|lecture| CACHE
    CACHE -->|resolve()| SVC
    SVC -->|maxSizeBytes| MW
    C2 -->|mock maxSizeBytes = 524288000| SVC
    C2 -->|mock maxSizeBytes = 524288000| MW
    C3 -.->|aligne doc 100→500 MB| C4
    C1 -.->|valide cohérence post-migration| C4

    style C1 fill:#4CAF50,color:#fff
    style C2 fill:#2196F3,color:#fff
    style C3 fill:#FF9800,color:#fff
    style C4 fill:#9C27B0,color:#fff
    style DB fill:#607D8B,color:#fff
    style MW fill:#78909C,color:#fff
    style SVC fill:#78909C,color:#fff
    style CACHE fill:#78909C,color:#fff

Séquence — Flux F1 : Migration DB + invalidation cache

sequenceDiagram
    participant TOM as TypeORM Runner
    participant DB as PostgreSQL<br/>(vault_secure)
    participant SVC as CategoryConfigService
    participant CACHE as Cache (TTL 60s)
    participant MW as CategorySizeMiddleware
    participant CLIENT as Client (upload)

    Note over TOM,DB: Déploiement — Migration C1
    TOM->>DB: UPDATE document_category_configs<br/>SET max_size_bytes = 524288000<br/>WHERE category IN ('DEFAULT','B2C_EVIDENCE_MINOR')
    DB-->>TOM: 2 rows updated

    Note over CACHE: Cache expire après ≤ 60s (INV-T5-03)
    CLIENT->>MW: POST /deposit (Content-Length: 450000000)
    MW->>SVC: resolve(category)
    SVC->>CACHE: get(category)
    CACHE-->>SVC: miss (expiré)
    SVC->>DB: SELECT max_size_bytes WHERE category = 'DEFAULT'
    DB-->>SVC: 524288000
    SVC->>CACHE: set(category, config, TTL=60s)
    SVC-->>MW: maxSizeBytes = 524288000
    MW->>MW: 450000000 ≤ 524288000 → OK
    MW-->>CLIENT: next() → flux nominal

    Note over CLIENT,MW: Cas rejet (Content-Length > 524288000)
    CLIENT->>MW: POST /deposit (Content-Length: 524288001)
    MW->>SVC: resolve(category)
    SVC-->>MW: maxSizeBytes = 524288000
    MW->>MW: 524288001 > 524288000 → REJET
    MW-->>CLIENT: 413 PayloadTooLargeException (ERR-79-004)

3. Mapping invariants → mécanismes

Invariant ID Exigence Mécanisme Composant Observable Risque
INV-285-01-coherence Borne backend = 524288000 bytes Migration UPDATE SQL C1 SELECT max_size_bytes FROM vault_secure.document_category_configs WHERE category = 'DEFAULT' retourne 524288000 Faible — UPDATE simple
INV-285-02-categories-cible Seules DEFAULT et B2C_EVIDENCE_MINOR relevées Clause WHERE restrictive dans la migration C1 Query count des catégories à 524288000 = exactement 2 Faible
INV-285-03-rejet-hors-borne Taille > 524288000 rejetée Middleware declaredSize > maxSizeBytes + Service sizeBytes > config.maxSizeBytes Existant (non modifié) ERR-79-004 sur requête 524288001 ; acceptation sur 524288000 Nul — logique inchangée
INV-285-04-unite-et-bornes Paramètre en bytes, bornes [1, 524288000] Colonne BIGINT DB + parseInt service Existant Valeur numérique lue = 524288000 Nul
INV-285-05-erreur-metier Code ERR-79-004 pour dépassement PayloadTooLargeException hardcodé Existant (non modifié) Response body contient code: 'ERR-79-004' Nul
INV-285-06-non-regression Fichiers 1..104857600 acceptés Borne relevée (524288000 > 104857600) Aucun (garanti mathématiquement) Tests existants passent sans modification Nul
INV-285-07-doc-sync PD-252 contient storage.category_max_bytes: 500 MB Édition manuelle des 2 artefacts C3 Grep textuel dans les 2 fichiers Faible
INV-285-08-checklist-temporelle Aucune transition temporelle Non applicable Revue de code Nul
INV-285-09-etats-retour Aucune transition retour Non applicable (stateless) Revue de code Nul
INV-285-10-protection-distribuee Aucun mécanisme distribué Non applicable Revue de code Nul
INV-285-11-atomicite-ddl Aucune migration DDL Non applicable (UPDATE data, pas DDL) Migration ne contient pas de CREATE/ALTER TABLE Nul
INV-285-12-intermodule Aucune contrainte inter-module Non applicable Diff ne touche aucun import/guard/middleware Nul

4. Mapping critères d'acceptation → mécanismes

Critère ID Mécanisme(s) Composant Observable Risque
CA-01 Migration UPDATE DEFAULT.max_size_bytes = 524288000 C1 TC-NOM-01 : lecture config retourne 524288000 Faible
CA-02 Migration UPDATE B2C_EVIDENCE_MINOR.max_size_bytes = 524288000 C1 TC-NOM-02 : lecture config retourne 524288000 Faible
CA-03 Middleware existant compare Content-Length à maxSizeBytes (désormais 524288000) Existant TC-NOM-03 : 524288001 rejeté ; TC-NOM-04 : 524288000 accepté Nul
CA-04 Service existant assertSizeAllowed() rejette avec ERR-79-004 Existant TC-NOM-05 : ERR-79-004 sur 524288001 Nul
CA-05 Mise à jour des mocks dans les tests unitaires C2 TC-NOM-09 : suite passante Faible
CA-06 Édition PD-252 besoin + specification C3 TC-NOM-07 : grep storage.category_max_bytes: 500 MB Faible
CA-07 Exécution pipeline inter-EB post-migration C4 TC-NOM-08 : rapport sans écart PD-101/backend Faible

5. Mapping tests (TC-*) → mécanismes + observables

Test ID Référence spec Mécanisme(s) Point(s) d'observation Niveau de test visé
TC-NOM-01 INV-285-01, CA-01 Migration UPDATE + CategoryConfigService.resolve() config.maxSizeBytes === 524288000 Unit
TC-NOM-02 INV-285-01, CA-02 Migration UPDATE + CategoryConfigService.resolve() config.maxSizeBytes === 524288000 pour B2C_EVIDENCE_MINOR Unit
TC-NOM-03 INV-285-03, CA-03 CategorySizeMiddleware declaredSize > maxSizeBytes PayloadTooLargeException levée Unit
TC-NOM-04 INV-285-03, CA-03 CategorySizeMiddleware declaredSize <= maxSizeBytes next() appelé Unit
TC-NOM-05 INV-285-03, INV-285-05, CA-04 CategoryConfigService.assertSizeAllowed() code === 'ERR-79-004' dans exception Unit
TC-NOM-06 INV-285-03 CategoryConfigService.assertSizeAllowed() Pas d'exception levée Unit
TC-NOM-07 INV-285-07, CA-06 Diff textuel PD-252 Chaîne storage.category_max_bytes: 500 MB présente dans les 2 fichiers Documentation (revue manuelle)
TC-NOM-08 INV-285-01, CA-07 Pipeline coherence-report.py Rapport sans écart PD-101/backend Integration (script)
TC-NOM-09 CA-05 Suite tests unitaires complète Tous tests passants Unit
TC-ERR-01 E-01, CA-03 Middleware Content-Length > 524288000 Rejet immédiat Unit
TC-ERR-02 E-02, CA-04 Service taille > 524288000 ERR-79-004 Unit
TC-ERR-03 E-03 CategoryConfigService.resolve() avec catégorie inconnue ERR-79-001 Unit (existant)
TC-ERR-04 E-04 Middleware parseInt NaN check next() passthrough Unit (existant)
TC-ERR-05 E-05, CA-06 Revue documentaire Grep 2 fichiers Documentation
TC-ERR-06 E-06, CA-07 Pipeline inter-EB Rapport de cohérence Integration
TC-NR-01 INV-285-06 Borne 524288000 > 104857600 Tests existants plage 1..104857600 passent Unit
TC-NR-02 INV-285-06 assertSizeAllowed(config, 104857600) Pas d'exception Unit
TC-NEG-01 INV-285-02 Query DB exhaustive Seules 2 catégories à 524288000 Unit
TC-NEG-02 INV-285-04 assertSizeAllowed avec valeurs limites Rejet 524288001, 0, -1 Unit
TC-INV-08..12 INV-285-08..12 Revue de code (preuve d'absence) Diff ne contient aucun mécanisme temporel/distribué/DDL/intermodule Documentation

6. Gestion des erreurs

Erreur Code Composant Traitement Observable
Upload > 524288000 (Content-Length) ERR-79-004 CategorySizeMiddleware PayloadTooLargeException, requête coupée avant Multer HTTP 413 + code: 'ERR-79-004'
Upload > 524288000 (taille réelle) ERR-79-004 CategoryConfigService PayloadTooLargeException après réception fichier HTTP 413 + code: 'ERR-79-004'
Catégorie inconnue ERR-79-001 CategoryConfigService BadRequestException HTTP 400 (inchangé)
Config DB absente/inactive ERR-79-002 CategoryConfigService UnprocessableEntityException HTTP 422 (inchangé)

Aucun nouveau code d'erreur introduit. Tous les traitements d'erreur sont existants et inchangés.

7. Impacts sécurité

Risque Mitigation Statut
Augmentation surface d'abus (fichiers plus gros) Quotas utilisateur (cumul, concurrence, journalier) inchangés — hors périmètre PD-285 Couvert par mécanismes existants
DoS par upload volumineux Middleware Content-Length pré-coupe le flux + rate limiting existant Inchangé
Incohérence client/serveur PD-101 (client) déjà à 500 MB — cette story aligne le backend Résolu par PD-285

Aucune nouvelle surface d'attaque. La limite passe de 100 à 500 MB mais les garde-fous existants (quotas, rate-limit, middleware) restent actifs.

8. Hypothèses techniques

ID Hypothèse Impact si faux
HT-01 La migration peut UPDATE les lignes existantes sans conflit (pas de lock concurrent sur la table document_category_configs) Migration échoue — relancer après vérification
HT-02 Le cache CategoryConfigService (TTL 60s) expirera naturellement après migration — pas besoin de restart Valeur stale pendant max 60s après déploiement. Acceptable car la migration s'exécute avant le trafic en déploiement blue-green
HT-03 maxSizeBytes est stocké en BIGINT — 524288000 est dans la plage BIGINT Toujours vrai (BIGINT max = 9.2×10¹⁸)
HT-04 Les tests existants de middleware et service utilisent des mocks pour maxSizeBytes — la valeur du mock doit être mise à jour Si des tests utilisent la vraie DB, ils prendront la nouvelle valeur automatiquement
HT-05 PD-252 besoin et specification sont dans ProbatioVault-doc/docs/epics/legal-compliance/PD-252-politique-formats-preservation/ Si chemin différent, localiser par find
HT-06 Content-Length absent → middleware laisse passer (comportement existant ligne 25-28 de category-size.middleware.ts) — inchangé par PD-285 Spec mentionne ce cas comme point à clarifier (Q-03), mais le comportement existant est safe : la validation métier ultérieure est l'autorité finale

9. Points de vigilance (risques, dette, pièges)

  1. Cache TTL 60s : Après migration, les instances en cours peuvent servir l'ancienne valeur pendant 60s max. En déploiement blue-green, les nouvelles instances démarrent avec cache vide → pas de risque.

  2. Migration data vs DDL : Cette migration est un UPDATE de données, pas un changement de schéma. Pas de risque ALTER TYPE ADD VALUE (cf. learning PD-282/PD-279). Pas besoin de commitTransaction() intermédiaire.

  3. Pas de rollback automatique : Conformément au pattern existant (down() vide pour production safety), le rollback nécessiterait une migration inverse manuelle. Risque faible car le changement est réversible par un simple UPDATE.

  4. Multipart 5 TB inchangé : NORMATIVE_DEFAULTS.MAX_FILE_SIZE dans upload-config.service.ts n'est PAS modifié. Attention à ne pas confondre les deux limites (catégorie vs multipart).

  5. Cohérence inter-EB : Le pipeline coherence-report.py doit être exécuté après la migration ET après l'amendement PD-252 pour valider CA-07. Ordre important.

10. Hors périmètre

  • Changement de NORMATIVE_DEFAULTS.MAX_FILE_SIZE (multipart, 5 TB)
  • Changement des quotas utilisateur (cumul, concurrence, journalier)
  • Changement client mobile PD-101
  • Changement d'infrastructure S3/OVH
  • Changement des politiques MIME / audit mineurs hors taille
  • Ajout de nouvelles catégories documentaires
  • Modification du middleware ou du service (logique inchangée, seule la donnée DB change)

11. Périmètre de test

Niveau de test In scope Hors scope (justification)
Unitaire Tous les composants : migration (valeurs), mocks config service, assertions middleware et service sur borne 524288000
Intégration Pipeline coherence-report.py (CA-07), exécution migration sur base de test
E2E Hors périmètre : aucun nouveau flux applicatif, seule une valeur de configuration DB change. Les tests E2E existants couvrent déjà le flux upload et restent valides Pas de nouveau endpoint/flux à tester E2E

Tous les niveaux de test pertinents sont couverts. Les tests E2E existants sur le flux upload restent valides sans modification (ils utilisent des fichiers < 500 MB). Aucune exclusion non justifiée.

12. Mécanismes cross-module

Aucune modification d'autres modules. Le changement est limité à : - Une migration SQL (données, pas de schéma) - Des tests unitaires (mocks) - De la documentation externe (PD-252)

Aucun guard, middleware ou intercepteur n'est ajouté sur des routes d'autres modules.