Aller au contenu

PD-250 — Décomposition en tâches agents — Job destruction définitive et bordereau

1. Matrice des dépendances

ID Agent Description Produit Consomme Dépend de Niveau
T1 agent-developer Configuration Joi (13 params + 3 SLA + preNoticeJobInterval) config/destruction.config.ts, constantes queues [] 0
T8 agent-developer Machine à états documents (5 transitions interdites) services/document-state-machine.service.ts [] 0
T13 agent-developer Migrations DDL (enum, had_legal_lock, tables, séquence) Tables DB, enum étendu, audit_destruction_seq [] 0
T2 agent-developer Service d'éligibilité (triple condition WORM) services/eligibility.service.ts Entities DB (T13), DocumentSecure [T13] 1
T6 agent-developer Service d'audit transactionnel (audit_destruction_seq) services/destruction-audit.service.ts Séquence audit_destruction_seq (T13) [T13] 1
T9 agent-developer Service de zeroization document (flux legal_lock) services/document-zeroization.service.ts Colonne had_legal_lock (T13) [T13] 1
T7 agent-developer Service d'alertes et métriques batch services/destruction-alert.service.ts, events/destruction.events.ts [T6] 2
T3 agent-developer Service de génération du bordereau (PDF/A + sig + TSA) services/bordereau.service.ts, entities/destruction-bordereau.entity.ts EligibilityService (T2) [T2, T13] 2
T4 agent-developer Service d'exécution de destruction séquentielle services/destruction-execution.service.ts Eligibility (T2), Audit (T6), Zeroization (T9), Bordereau (T3), Alert (T7), StateMachine (T8) [T2, T3, T6, T7, T8, T9] 3
T5 agent-developer Service de réconciliation post-crash services/reconciliation.service.ts Audit (T6), Alert (T7), StateMachine (T8) [T6, T7, T8] 3
T10 agent-developer Contrôleur admin bordereaux (GET /admin/bordereaux) controllers/bordereau.controller.ts, DTOs Bordereau entity (T3), Audit (T6) [T3, T6] 3
T11 agent-developer Processor préavis BullMQ (quotidien) processors/pre-notice.processor.ts, events/pre-notice.events.ts Eligibility (T2), Config (T1) [T1, T2] 2
T12 agent-developer Processor principal destruction BullMQ processors/destruction.processor.ts Execution (T4), Bordereau (T3), Alert (T7), Config (T1), Reconciliation (T5) [T1, T3, T4, T5, T7] 4
T15 agent-developer Module NestJS principal (wiring) destruction.module.ts, enums/*.ts Tous les services et processors [T1..T12] 5
T14 agent-qa-unit-integration Tests contractuels transversaux __tests__/contractual/*.spec.ts Tous les fichiers produits [T1..T13, T15] 6
T16 agent-adversarial Review sécurité (fail-closed, PII, timing) Rapport de vulnérabilités Tous les fichiers produits [T15] 6

2. Bloc de parallélisation

parallelization:
  strategy: by_level
  levels:
    - level: 0
      tasks: [1, 8, 13]
      agents: [agent-developer, agent-developer, agent-developer]
      branches: ["feature/PD-250-l0-config", "feature/PD-250-l0-state-machine", "feature/PD-250-l0-migrations"]
      estimated_time: "2h"
    - level: 1
      tasks: [2, 6, 9]
      agents: [agent-developer, agent-developer, agent-developer]
      branches: ["feature/PD-250-l1-eligibility", "feature/PD-250-l1-audit", "feature/PD-250-l1-zeroization"]
      estimated_time: "2.5h"
    - level: 2
      tasks: [3, 7, 11]
      agents: [agent-developer, agent-developer, agent-developer]
      branches: ["feature/PD-250-l2-bordereau", "feature/PD-250-l2-alerts", "feature/PD-250-l2-prenotice"]
      estimated_time: "3h"
    - level: 3
      tasks: [4, 5, 10]
      agents: [agent-developer, agent-developer, agent-developer]
      branches: ["feature/PD-250-l3-execution", "feature/PD-250-l3-reconciliation", "feature/PD-250-l3-admin-api"]
      estimated_time: "3h"
    - level: 4
      tasks: [12]
      agents: [agent-developer]
      branches: ["feature/PD-250-l4-processor"]
      estimated_time: "2.5h"
    - level: 5
      tasks: [15]
      agents: [agent-developer]
      branches: ["feature/PD-250-l5-module-wiring"]
      estimated_time: "1h"
    - level: 6
      tasks: [14, 16]
      agents: [agent-qa-unit-integration, agent-adversarial]
      branches: ["feature/PD-250-l6-contractual-tests", "feature/PD-250-l6-security-review"]
      estimated_time: "2h"
  total_sequential_time: "22h"
  total_parallel_time: "16h"
  speedup_factor: 1.37
  git_strategy: branch_per_level

Note : Le speedup est modéré (1.37x) car le DAG a une profondeur de 7 niveaux avec peu de largeur au-delà du niveau 3. La stratégie branch_per_level est pertinente pour limiter la complexité de merge (6 merges vs 16 merges avec branch_per_task).

3. Détail de chaque tâche


Tâche 1 — Configuration et validation Joi

  • Agent : agent-developer
  • Niveau : 0
  • Dépend de : []
  • Contract : destruction-config
  • Fichiers :
  • src/modules/destruction/config/destruction.config.ts
  • src/modules/destruction/__tests__/destruction.config.spec.ts
  • Description : Implémenter la validation Joi stricte pour les 14 paramètres numériques (13 originaux + preNoticeJobInterval ajouté pour MAJ-02) et les 3 SLA temporels. Utiliser le pattern registerAs() existant (cf. legal-pre.config.ts). Définir les constantes de noms de queue (pv-jobs-destruction, pv-jobs-prenotice) sans caractère :. Options Joi : abortEarly: false, allowUnknown: false, stripUnknown: false. Rejet strict (pas de clamp).
  • Réserve Gate 5 intégrée :
  • MAJ-02 : Ajouter preNoticeJobInterval (défaut 24h, min 1h, max 168h) comme variable dédiée distincte de destructionJobInterval. Variable env : DESTRUCTION_PRE_NOTICE_JOB_INTERVAL.
  • Tests : TC-250-18 (queue names), TC-250-23 (config hors bornes, échantillonnage MIN-15 : 3 params × bornes min+max)
  • Décision architecturale :
  • Choix : registerAs() + fichier constantes dédié (pas de Joi global)
  • Pourquoi : Cohérent avec le pattern legal-pre.config.ts existant. La validation globale (config.schema.ts) est pour l'infra (DB, Redis), pas pour les modules fonctionnels.
  • Trade-off : Pas de fail-fast au boot pour les params destruction (validation au premier accès via ConfigService.get). Mitigation : appeler validate() dans le onModuleInit() du module.

Tâche 2 — Service d'éligibilité

  • Agent : agent-developer
  • Niveau : 1
  • Dépend de : [T13]
  • Contract : destruction-eligibility
  • Fichiers :
  • src/modules/destruction/services/eligibility.service.ts
  • src/modules/destruction/__tests__/eligibility.service.spec.ts
  • Description : Implémenter la sélection des documents éligibles (triple condition WORM + clockSkewTolerance soustractive), l'exclusion des bordereaux (MIN-13), la sélection de préavis (J+N), et la re-vérification unitaire (SELECT ... FOR UPDATE). La query utilise DocumentSecure existant (PD-63). Tracer les motifs d'exclusion par document.
  • Tests : TC-250-01, TC-250-02, TC-250-03, TC-250-10, TC-250-12
  • Décision architecturale :
  • Choix : QueryBuilder TypeORM avec paramètres bindés (pas de raw SQL)
  • Pourquoi : Sécurité injection SQL + testabilité avec mocks TypeORM. Alternative raw SQL plus performante mais non nécessaire (batchSize max 5000, filtres indexés).
  • Trade-off : Moins de contrôle sur le plan d'exécution PostgreSQL. Mitigation : index idx_documents_had_legal_lock et index existant sur status.

Tâche 3 — Service de génération du bordereau

  • Agent : agent-developer
  • Niveau : 2
  • Dépend de : [T2, T13]
  • Contract : destruction-bordereau
  • Fichiers :
  • src/modules/destruction/services/bordereau.service.ts
  • src/modules/destruction/entities/destruction-bordereau.entity.ts
  • src/modules/destruction/__tests__/bordereau.service.spec.ts
  • Description : Générer un bordereau PDF/A consolidé par batch avec uniquement les champs autorisés (§3, pas de PII), signer via HSM (PD-36), horodater via TSA RFC 3161 (PD-39) avec retry ≤ tsaRetryCount, valider signature+timestamp (fail-closed), persister en S3 (Object Lock COMPLIANCE) + DB avec retentionExpiry = null.
  • Dépendance externe nouvelle : pdf-lib (CJS compatible, HYP-IMPL-05)
  • Tests : TC-250-04, TC-250-05, TC-250-08, TC-250-08b, TC-250-10, TC-250-11
  • Décision architecturale :
  • Choix : pdf-lib pour la génération PDF/A
  • Pourquoi : Compatible CJS (pas de configuration Jest spéciale), API ergonomique pour le format tabulaire, support du standard PDF/A. Alternative pdfkit : moins de support PDF/A natif. Alternative puppeteer : overhead de headless Chrome inacceptable pour un job batch.
  • Trade-off : pdf-lib est principalement un éditeur de PDF, la génération from-scratch est plus verbeuse. Acceptable pour un format tabulaire simple.

Tâche 4 — Service d'exécution de destruction

  • Agent : agent-developer
  • Niveau : 3
  • Dépend de : [T2, T3, T6, T7, T8, T9]
  • Contract : destruction-execution
  • Fichiers :
  • src/modules/destruction/services/destruction-execution.service.ts
  • src/modules/destruction/__tests__/destruction-execution.service.spec.ts
  • Description : Orchestrer la destruction unitaire séquentielle post-validation du bordereau. Boucle for...of (pas Promise.all — MAJ-25). Pour chaque document : re-vérification éligibilité (ERR-250-03), branchement zeroization si hadLegalLock (INV-250-12, fail-closed MAJ-27), S3 DeleteObject avec retry, confirmation HTTP 204, transaction DB atomique (UPDATE DESTROYED + INSERT audit_log). Gestion SLA destructionExecutionSla (MAJ-26 : FAILED si dépassé avant 1er doc, PARTIAL_FAILED sinon). Émission d'alerte unitaire pour chaque ERR-250-03/04 (résolution MAJ-05 Gate 5).
  • Réserve Gate 5 intégrée :
  • MAJ-05 : Émettre une alerte unitaire (via DestructionAlertService) pour chaque document en erreur ERR-250-03 et ERR-250-04, en plus du statut batch global.
  • Tests : TC-250-06, TC-250-07, TC-250-12, TC-250-17, TC-250-25, TC-250-27
  • Décision architecturale :
  • Choix : Transaction DB par document (pas de transaction englobante pour tout le batch)
  • Pourquoi : Conforme à §10.4 « synchrone par unité, après confirmation S3 ». Un crash mid-batch ne corrompt que le document en cours. Alternative transaction globale : un échec unitaire rollback tout le batch (non conforme PARTIAL_FAILED).
  • Trade-off : Plus de commits DB (N transactions vs 1). Acceptable car batchSize ≤ 5000 et chaque commit est rapide.

Tâche 5 — Service de réconciliation

  • Agent : agent-developer
  • Niveau : 3
  • Dépend de : [T6, T7, T8]
  • Contract : destruction-reconciliation
  • Fichiers :
  • src/modules/destruction/services/reconciliation.service.ts
  • src/modules/destruction/__tests__/reconciliation.service.spec.ts
  • Description : Converger vers un état terminal contractuel après crash post-suppression S3. Retry DB avec backoff exponentiel (≤ reconciliationDbRetryCount), vérification reconciliationSla. Si réussi → DESTROYED + audit DESTROYED. Si échec persistant hors SLA → RECONCILIATION_FAILED + audit de type RECONCILIATION_FAILED (pas DESTROYED) + escalade critique. RECONCILIATION_FAILED → * interdit (MAJ-28).
  • Tests : TC-250-07, TC-250-13, TC-250-28

Tâche 6 — Service d'audit de destruction

  • Agent : agent-developer
  • Niveau : 1
  • Dépend de : [T13]
  • Contract : destruction-audit
  • Fichiers :
  • src/modules/destruction/services/destruction-audit.service.ts
  • src/modules/destruction/__tests__/destruction-audit.service.spec.ts
  • src/modules/destruction/__tests__/destruction-audit.integration.spec.ts (BLQ-01)
  • Description : Implémenter l'audit transactionnel avec séquence audit_destruction_seq (nom aligné MAJ-03) pour garantir non-perte, ordre causal et complétude. Méthode logDestruction(queryRunner, params) exécutée dans la même transaction que la finalisation DESTROYED (§10.4b). Inclure parentBatchId dans l'audit log (résolution MAJ-01). Définir les actions d'audit : DOCUMENT_DESTROY, DOCUMENT_DESTROY_BATCH, DOCUMENT_DESTROY_BORDEREAU, DOCUMENT_DESTROY_RECONCILIATION_FAILED, DOCUMENT_DESTROY_ACCESS_DENIED. Méthode ensureAvailable() pour fail-closed si chaîne d'audit indisponible (ERR-250-07).
  • Réserves Gate 5 intégrées :
  • BLQ-01 : Créer un test d'intégration PostgreSQL réel (destruction-audit.integration.spec.ts) pour TC-250-16. Le test simule un crash post-suppression S3 / pré-commit DB et vérifie la réconciliation. Ce test nécessite DATABASE_URL en CI.
  • MAJ-01 : Ajouter parentBatchId comme champ dans l'audit log (paramètre de logDestruction), en plus de l'entity batch.
  • MAJ-03 : Le nom de la séquence est audit_destruction_seq (pas audit_seq). Aligner dans code contracts et migration.
  • Tests : TC-250-09, TC-250-16 (intégration PostgreSQL)
  • Décision architecturale :
  • Choix : Séquence PostgreSQL dédiée (audit_destruction_seq) plutôt que réutilisation de la séquence globale
  • Pourquoi : Isolation des compteurs par domaine fonctionnel. La monotonie est garantie par domaine (destruction), pas globalement. Alternative séquence globale : contention cross-module.
  • Trade-off : Une séquence supplémentaire en DB. Impact négligeable.

Tâche 7 — Service d'alertes et métriques

  • Agent : agent-developer
  • Niveau : 2
  • Dépend de : [T6]
  • Contract : destruction-alert
  • Fichiers :
  • src/modules/destruction/services/destruction-alert.service.ts
  • src/modules/destruction/events/destruction.events.ts
  • src/modules/destruction/__tests__/destruction-alert.service.spec.ts
  • Description : Publier les résultats batch sur EventEmitter2 avec compteurs agrégés (pas d'identifiants individuels). Restriction batch_result aux rôles ADMIN/SYSTEM (MIN-12). Alertes SLA contractuelles : batchFinalizeSla → alerte critique, destructionExecutionSla → alerte, reconciliationSla → escalade critique. Méthode alertUnitaryError(documentId, errorType) pour les alertes unitaires ERR-250-03/04 (résolution MAJ-05).
  • Réserve Gate 5 intégrée :
  • MAJ-05 : Exposer alertUnitaryError(documentId, errorType, batchId) pour émettre une alerte unitaire (pas seulement batch-level) pour chaque erreur ERR-250-03 et ERR-250-04.
  • Tests : TC-250-14, TC-250-26, TC-250-27, TC-250-28

Tâche 8 — Machine à états des documents

  • Agent : agent-developer
  • Niveau : 0
  • Dépend de : []
  • Contract : destruction-state-machine
  • Fichiers :
  • src/modules/destruction/services/document-state-machine.service.ts
  • src/modules/destruction/__tests__/document-state-machine.service.spec.ts
  • Description : Implémenter les gardes de transition d'état pour les documents. Transitions autorisées : PENDING→SEALED, SEALED→EXPIRED, EXPIRED→DESTROYED, EXPIRED→RECONCILIATION_FAILED. Transitions interdites (5 gardes, incluant MAJ-28) : SEALED→PENDING, EXPIRED→SEALED, DESTROYED→EXPIRED, DESTROYED→SEALED, RECONCILIATION_FAILED→*. Méthode validateTransition(current, target) → throw si interdit + audit. Méthode applyTransition(queryRunner, documentId, newStatus).
  • Tests : TC-250-15 (étendu à 5 transitions)
  • Décision architecturale :
  • Choix : Matrice de transitions en constante (Map) plutôt que pattern State (classes par état)
  • Pourquoi : 5 états, 4 transitions autorisées — trop simple pour justifier le pattern State GoF. Une Map<Status, Set<Status>> est lisible, testable et extensible. Alternative pattern State : over-engineering pour ce use case.
  • Trade-off : Moins extensible si le graphe de transitions devient complexe. Acceptable pour PD-250.

Tâche 9 — Service de zeroization document

  • Agent : agent-developer
  • Niveau : 1
  • Dépend de : [T13]
  • Contract : destruction-zeroization
  • Fichiers :
  • src/modules/destruction/services/document-zeroization.service.ts
  • src/modules/destruction/__tests__/document-zeroization.service.spec.ts
  • Description : Implémenter la zeroization cryptographique pour le flux legal_lock (INV-250-12). Pattern PD-81 adapté : transaction SERIALIZABLE, Buffer.fill(0) pour écraser en mémoire, UPDATE ... SET encrypted_metadata = NULL. Fail-closed (MAJ-27) : si zeroization échoue, document non supprimé de S3. Détection flux legal_lock via colonne had_legal_lock (backfillée en T13).
  • Tests : TC-250-17, TC-250-17b (fail-closed zeroization)

Tâche 10 — Contrôleur admin bordereaux

  • Agent : agent-developer
  • Niveau : 3
  • Dépend de : [T3, T6]
  • Contract : destruction-admin-api
  • Fichiers :
  • src/modules/destruction/controllers/bordereau.controller.ts
  • src/modules/destruction/dto/bordereau-query.dto.ts
  • src/modules/destruction/dto/bordereau-response.dto.ts
  • src/modules/destruction/__tests__/bordereau.controller.spec.ts
  • Description : Exposer GET /admin/bordereaux avec @Roles('ADMIN') + AuthorizationGuard. Query params : dateFrom?, dateTo?, batchId?, pagination (offset/limit). Non-ADMIN → HTTP 403 + audit DOCUMENT_DESTROY_ACCESS_DENIED. DTO réponse : bordereauId, batchId, createdAt, documentCount, status, pdfUrl (presigned S3).
  • Tests : TC-250-20, TC-250-21

Tâche 11 — Processor préavis BullMQ

  • Agent : agent-developer
  • Niveau : 2
  • Dépend de : [T1, T2]
  • Contract : destruction-prenotice
  • Fichiers :
  • src/modules/destruction/processors/pre-notice.processor.ts
  • src/modules/destruction/events/pre-notice.events.ts
  • src/modules/destruction/__tests__/pre-notice.processor.spec.ts
  • Description : Job BullMQ sur queue pv-jobs-prenotice (sans :). Scheduling quotidien via preNoticeJobInterval dédié (résolution MAJ-02, distinct de destructionJobInterval). Sélection via eligibility.selectPreNotice(preNoticeDays). Émission EventEmitter2.emit('destruction.pre-notice', { documentId, eligibleAt, preNoticeDays }) — pas de PII. Cas N=0 : jour J, avant run destruction. API BullMQ v5 : getJobSchedulers/removeJobScheduler uniquement.
  • Réserve Gate 5 intégrée :
  • MAJ-02 : Utiliser preNoticeJobInterval de T1 (pas destructionJobInterval) pour le scheduling.
  • Tests : TC-250-22

Tâche 12 — Processor principal destruction BullMQ

  • Agent : agent-developer
  • Niveau : 4
  • Dépend de : [T1, T3, T4, T5, T7]
  • Contract : destruction-processor
  • Fichiers :
  • src/modules/destruction/processors/destruction.processor.ts
  • src/modules/destruction/__tests__/destruction.processor.spec.ts
  • Description : Processor BullMQ sur queue pv-jobs-destruction. Orchestration complète du flux §5.1→§5.10 : validation config → sélection éligible → création batch (PENDING→RUNNING, parentBatchId si reprise MIN-11) → génération bordereau (fail-closed INV-250-03) → chrono destructionExecutionSla (MAJ-26) → destruction séquentielle (MAJ-25) → vérification batchFinalizeSla → publication résultat. API BullMQ v5 uniquement (INV-250-14). parentBatchId non null pour batches de reprise, null sinon.
  • Tests : TC-250-08, TC-250-12, TC-250-19, TC-250-26

Tâche 13 — Migrations de base de données

  • Agent : agent-developer
  • Niveau : 0
  • Dépend de : []
  • Contract : destruction-migrations
  • Fichiers :
  • src/database/migrations/1740700000000-PD-250-destruction-schema.ts
  • src/database/migrations/1740700000001-PD-250-document-status-extension.ts
  • Description : Créer les migrations TypeORM :
  • Extension enum document_status : ADD VALUE IF NOT EXISTS 'DESTROYED', ADD VALUE IF NOT EXISTS 'RECONCILIATION_FAILED'.
  • Colonne had_legal_lock (BOOLEAN, NOT NULL, DEFAULT false) + backfill par batch (résolution MAJ-04 : vérifier historique audit en plus de legal_lock/legal_lock_until).
  • Table destruction_batches (id, status, parent_batch_id, bordereau_id, compteurs, timestamps).
  • Table destruction_bordereaux (id, batch_id, pdf_s3_path, pdf_hash, tsa_token, signature, document_count, retention_expiry nullable).
  • Séquence vault_secure.audit_destruction_seq (nom aligné MAJ-03).
  • Index : idx_destruction_batches_status, idx_destruction_batches_created_at, idx_documents_had_legal_lock. Pattern DDL PD-264 : DROP TRIGGER → backfill → ALTER → constraints → index → TRIGGER (si applicable). Backfill par batch de 1000 pour éviter lock long.
  • Réserves Gate 5 intégrées :
  • MAJ-03 : Séquence nommée audit_destruction_seq (aligné avec le plan, explicite).
  • MAJ-04 : Le backfill had_legal_lock doit vérifier l'historique d'audit (SELECT EXISTS (SELECT 1 FROM audit_log WHERE entity_id = doc.id AND action IN ('legal_lock.applied', 'legal_lock.activated'))) en plus des colonnes legal_lock/legal_lock_until actuelles. Cela couvre le cas où un legal_lock a été retiré (pas expiré).
  • Tests : Validation npm run typeorm migration:run en local

Tâche 14 — Tests contractuels transversaux

  • Agent : agent-qa-unit-integration
  • Niveau : 6
  • Dépend de : [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T15]
  • Contract : Transversal (tous les code contracts)
  • Fichiers :
  • src/modules/destruction/__tests__/contractual/queue-naming.spec.ts
  • src/modules/destruction/__tests__/contractual/deprecated-api.spec.ts
  • src/modules/destruction/__tests__/contractual/state-transitions.spec.ts
  • src/modules/destruction/__tests__/contractual/parent-batch-id.spec.ts
  • src/modules/destruction/__tests__/contractual/pii-exclusion.spec.ts
  • Description : Implémenter les tests contractuels transversaux qui vérifient les invariants cross-cutting :
  • TC-250-18 : Queue naming sans : (regex négative)
  • TC-250-19 : Scan statique absence getRepeatableJobs/removeRepeatableByKey + présence getJobSchedulers/removeJobScheduler
  • TC-250-15 étendu : 5 transitions interdites (incluant RECONCILIATION_FAILED→DESTROYED, MAJ-28)
  • TC-250-17b : Fail-closed zeroization (MAJ-27)
  • TC-250-23 : Config hors bornes — échantillonnage MIN-15 (3 params × min+max)
  • MIN-11 : parentBatchId non null pour batch de reprise, null sinon
  • MIN-12 : Restriction événements batch_result aux rôles ADMIN/SYSTEM
  • PII exclusion : Scan des payloads bordereau et préavis pour absence de données personnelles

Tâche 15 — Module NestJS principal (wiring)

  • Agent : agent-developer
  • Niveau : 5
  • Dépend de : [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]
  • Contract : Transversal
  • Fichiers :
  • src/modules/destruction/destruction.module.ts
  • src/modules/destruction/enums/batch-status.enum.ts
  • src/modules/destruction/enums/destruction-audit-action.enum.ts
  • src/modules/destruction/entities/destruction-batch.entity.ts
  • Description : Assembler le module NestJS : imports (ConfigModule, TypeORM entities, BullModule queues, AuditModule, TsaModule, StorageModule), controllers (BordereauController), providers (tous les services + processors), exports (services publics). Définir les enums BatchStatus et DestructionAuditAction. Entity DestructionBatch avec relation vers DestructionBordereau.

Tâche 16 — Review sécurité adversariale

  • Agent : agent-adversarial
  • Niveau : 6
  • Dépend de : [T15]
  • Contract : Transversal
  • Fichiers : Rapport (pas de production de code)
  • Description : Review sécurité du module complet. Vérifier :
  • Fail-closed : aucune destruction possible sans bordereau signé+horodaté valide
  • PII : absence de données personnelles dans bordereaux, préavis et métriques
  • Timing attacks : crypto.timingSafeEqual pour comparaisons de hashes
  • Injection : paramètres QueryBuilder bindés (pas de concaténation SQL)
  • Contrôle d'accès : endpoint admin protégé, événements restreints
  • Idempotence : pas de double destruction, pas de retraitement DESTROYED
  • Transitions : matrice de transitions complète, pas de chemin non gardé

4. Intégration des réserves Gate 5

Réserve Sévérité Tâche(s) impactée(s) Résolution
BLQ-01 BLOQUANT T6 Test d'intégration PostgreSQL réel pour TC-250-16 dans destruction-audit.integration.spec.ts. Simule crash post-S3/pré-commit et vérifie réconciliation ACID.
MAJ-01 MAJEUR T6, T12 parentBatchId ajouté comme paramètre de logDestruction() et inclus dans chaque entry d'audit (en plus de l'entity batch).
MAJ-02 MAJEUR T1, T11 Variable dédiée DESTRUCTION_PRE_NOTICE_JOB_INTERVAL (défaut 24h) ajoutée à la config. T11 utilise cette variable pour le scheduling.
MAJ-03 MAJEUR T13, T6 Séquence nommée audit_destruction_seq partout (migration et service).
MAJ-04 MAJEUR T13 Backfill enrichi : vérification historique d'audit (événements legal_lock.*) en plus des colonnes courantes.
MAJ-05 MAJEUR T7, T4 alertUnitaryError(documentId, errorType, batchId) ajoutée à T7. T4 l'appelle pour chaque ERR-250-03/04.

5. Decision trace

DT-01 — Structure module : destruction/ séparé vs extension documents/

  • Choix : Module src/modules/destruction/ séparé
  • Pourquoi : Le domaine destruction a son propre cycle de vie (batch, bordereau, réconciliation, préavis), ses propres entities (batch, bordereau), ses propres jobs BullMQ, et ses propres invariants normés (ISO 14641, NF Z42-013). L'intégrer dans documents/ créerait un module de 2000+ LOC avec des responsabilités mélangées. Alternative documents/destruction/ sous-module : possible mais complexifie les imports circulaires (DocumentSecure ↔ destruction).
  • Trade-off : Dépendance croisée vers DocumentSecure entity. Mitigation : import direct de l'entity (pas du module documents entier).

DT-02 — Audit : séquence dédiée vs séquence globale

  • Choix : Séquence audit_destruction_seq dédiée au domaine destruction
  • Pourquoi : L'invariant INV-250-05 exige la monotonie causale par document, pas la monotonie globale cross-domaine. Une séquence dédiée évite la contention avec d'autres modules auditant en parallèle.
  • Trade-off : Si un audit cross-domaine nécessite un ordonnancement global futur, il faudra une séquence supplémentaire. Acceptable pour PD-250.

6. Résumé

Métrique Valeur
Total tâches 16
Niveaux de parallélisation 7
Temps séquentiel estimé 22h
Temps parallèle estimé 16h
Speedup factor 1.37x
Stratégie Git branch_per_level
Réserves Gate 5 intégrées 6/6 (1 BLQ + 5 MAJ)
Tests contractuels 5 fichiers dédiés
Tests d'intégration PostgreSQL 1 (TC-250-16, BLQ-01)
Dépendance externe nouvelle pdf-lib
Fichiers produits (estimation) ~35 fichiers