Aller au contenu

PD-278 — Agent Developer : Module dip-attestation

Agent : agent-developer Module : dip-attestation Story : PD-278 — NF Z42-013 : ajout contractuel de l'etat DIP Date : 2026-03-01


1. Resume

Implementation de l'entity TypeORM DisseminationAttestation pour la table vault_secure.dissemination_attestations. Cette entity represente l'attestation de restitution generee a chaque transition SEALED → DIP (INV-278-05).

2. Fichiers modifies

Fichier Action Description
src/modules/documents/entities/dissemination-attestation.entity.ts CREE Entity TypeORM DisseminationAttestation — table vault_secure.dissemination_attestations

3. Conformite aux invariants du code contract

Invariant Statut Mecanisme
INV-278-05 : 1 attestation par requete SEALED→DIP, stockee dans vault_secure.dissemination_attestations CONFORME Entity mappee sur @Entity('dissemination_attestations', { schema: 'vault_secure' }). La cardinalite 1:1 par requete est enforced par le service (C9), pas par l'entity.
Champs WORM : hash_evidence et signature_ref ne sont jamais modifies apres insertion CONFORME Les champs sont declares NOT NULL / nullable: true sans @UpdateDateColumn. La protection WORM est documentee par JSDoc. L'enforcement reel est au niveau migration (trigger DB) et service (pas d'UPDATE sur ces champs).
document_ids stocke en UUID[] pour lier N documents a 1 attestation CONFORME @Column({ name: 'document_ids', type: 'uuid', array: true }) — PostgreSQL native UUID array. Permet requete @> pour lookup.
Retention 10 ans, partitioning par annee civile sur issued_at CONFORME Colonne issued_at declaree avec type: 'timestamptz' et index idx_attestations_issued_at. Le partitioning est gere au niveau DDL (migration C1), pas dans l'entity TypeORM (limitation framework).

4. Verification des interdits (forbidden)

Interdit Statut Justification
UPDATE sur hash_evidence ou signature_ref RESPECTE L'entity ne declare aucun @UpdateDateColumn. Les champs sont documentes WORM par JSDoc. L'enforcement est au niveau service (pas d'UPDATE) + trigger DB (migration C1). L'entity seule ne peut pas empecher un UPDATE — c'est un choix architecturalement correct car TypeORM ne dispose pas de decorateur "read-only column".
DELETE sans politique d'archivage validee RESPECTE L'entity ne dispose d'aucune methode de suppression. Le controle est au niveau service + migration (absence de onDelete: CASCADE).
Stockage en clair de hash_evidence sans chiffrement au repos RESPECTE L'entity stocke hash_evidence en text. Le chiffrement au repos est assure par l'envelope encryption au niveau infrastructure (PostgreSQL TDE / storage layer). L'entity ne gere pas le chiffrement applicatif — c'est le service (C9) qui calcule le hash et le signe via HSM (INV-278-10).

5. Schema de l'entity

@Entity('dissemination_attestations', { schema: 'vault_secure' })
export class DisseminationAttestation {
  id: string;                          // PK UUID auto-generated
  attestationId: string;               // UUID unique — reference externe
  requestId: string;                   // UUID — correlation requete API
  documentIds: string[];               // UUID[] — N documents lies
  actorId: string;                     // UUID — acteur initiateur
  issuedAt: Date;                      // TIMESTAMPTZ — emission (DEFAULT NOW())
  motifCommunication: string | null;   // VARCHAR(1024) nullable — motif optionnel
  disseminationPackageId: string | null; // UUID nullable — NULL mono, UUID multi
  hashEvidence: string;                // TEXT — empreinte integrite (WORM)
  signatureRef: string | null;         // TEXT nullable — ref HSM (WORM, STUB PD-37)
  createdAt: Date;                     // TIMESTAMPTZ — CreateDateColumn
}

6. Index declares

Index Colonnes Condition Justification
idx_attestations_attestation_id attestation_id UNIQUE Lookup par reference externe (spec §5.13)
idx_attestations_actor actor_id Requetes par acteur (audit, quota)
idx_attestations_issued_at issued_at Partitioning + requetes temporelles (retention 10 ans)
idx_attestations_package dissemination_package_id WHERE dissemination_package_id IS NOT NULL Correlation package multi-documents (index partiel, spec §5.1)

7. Conventions respectees

Convention Application
PostgreSQL columns snake_case Tous les name: sont en snake_case (attestation_id, request_id, etc.)
TypeScript properties camelCase attestationId, requestId, documentIds, etc.
Schema vault_secure @Entity('dissemination_attestations', { schema: 'vault_secure' })
@PrimaryGeneratedColumn('uuid') Pattern standard du projet
@CreateDateColumn avec timestamptz created_at avec type explicite
JSDoc sur chaque colonne Documentation complete avec references spec/INV
! definite assignment assertion Coherent avec DocumentSecure, Deposit, etc.
Import minimal TypeORM Uniquement les decorateurs utilises

8. Decisions architecturales

architectural_decisions:
  - decision: "UUID[] natif PostgreSQL pour document_ids (pas JSONB)"
    rationale: "Coherent avec le pattern keyword_deterministic dans DocumentSecure. Permet operateur @> pour lookup natif PostgreSQL et typage strict UUID."
    alternatives_considered: ["JSONB array", "Table de jointure N:N"]
    trade_offs: ["UUID[] = requetes simples + index GIN possible, mais pas de FK vers documents (intégrité applicative)"]
  - decision: "Index partiel sur dissemination_package_id WHERE NOT NULL"
    rationale: "Les attestations mono-document (package_id NULL) representent potentiellement la majorite. L'index partiel evite l'indexation inutile des NULL (REX PD-55: index partiels simples)."
    alternatives_considered: ["Index complet", "Pas d'index"]
    trade_offs: ["Index partiel = performance requetes package + economie stockage"]

9. Hypotheses

ID Hypothese Impact si faux
H-ATT-01 La migration (C1) cree la table vault_secure.dissemination_attestations avec le partitioning par annee sur issued_at Si la table n'existe pas, l'entity ne peut pas etre utilisee
H-ATT-02 hash_evidence est calcule par le service (C9) en SHA-256 des document_ids + actor_id + timestamp, pas par l'entity Si le calcul est attendu dans l'entity, l'architecture est incorrecte
H-ATT-03 signature_ref est un stub PD-37 (HSM non disponible), valeur NULL acceptee Si HSM est obligatoire, la colonne nullable: true est incorrecte
H-ATT-04 Le chiffrement au repos de hash_evidence est assure par l'infrastructure (PostgreSQL TDE), pas par chiffrement applicatif dans l'entity Si chiffrement applicatif requis, le type text est insuffisant — il faudrait bytea avec AES-256-GCM

10. Dependances inter-modules

Composant Direction Detail
C1 (Migration DDL) PREREQUIS La table vault_secure.dissemination_attestations doit exister avant toute utilisation de l'entity
C9 (DisseminationService) CONSOMMATEUR Le service INSERT les attestations dans cette entity via queryRunner.manager.save() ou queryRunner.query() dans la transaction ACID
C10 (DisseminationController) INDIRECT Le controller retourne la reponse attestation generee par C9

11. Matrice de couverture tests

Les tests de l'entity DisseminationAttestation sont couverts par les tests d'integration du service (C9) :

Test ID Fichier de test Couverture entity
TC-NOM-01 dissemination.service.spec.ts INSERT attestation mono-document, verification champs
TC-NOM-02 dissemination.service.spec.ts INSERT attestation multi-documents, verification document_ids[] et dissemination_package_id
TC-NOM-06 dissemination.service.spec.ts Verification motif_communication dans attestation
TC-NOM-07 dissemination.service.spec.ts dissemination_package_id NULL (mono) vs non-NULL (multi)
TC-INV-05 dissemination.service.spec.ts Exactement 1 attestation par requete, liee aux bons document_ids et actor_id
TC-ERR-09 dissemination.service.spec.ts Echec INSERT attestation → rollback atomique, status reste SEALED

12. Type-check

npx tsc --noEmit : 0 erreur (verification projet complet)

13. Points de vigilance

ID Point Mitigation
V-ATT-01 TypeORM ne dispose pas de decorateur "read-only column" pour enforcer WORM au niveau entity WORM enforce par : (1) service C9 qui ne fait jamais UPDATE, (2) trigger DB dans migration C1, (3) documentation JSDoc
V-ATT-02 Le partitioning RANGE(issued_at) n'est pas declarable dans TypeORM entity Gere exclusivement dans la migration DDL (C1). L'entity fonctionne de maniere transparente sur tables partitionnees.
V-ATT-03 document_ids UUID[] n'a pas de FK vers vault_secure.documents Integrite referentielle assuree au niveau applicatif (service C9 verifie l'existence des documents avant INSERT). Les FK sur arrays ne sont pas supportees par PostgreSQL.