PD-283 — Expression de besoin¶
1. Contexte et motivation¶
PD-85 (backend) prépare le dossier probatoire logique : validation des ProofEnvelopes (RFC PV-PROOF-001 v1.2.0), génération du manifest d'intégrité, chronologie consolidée, URLs signées de téléchargement, guide de procédure statique et README de vérification.
PD-283 est le dernier maillon : côté client, en mode Zero-Knowledge, l'app télécharge les artefacts chiffrés, les déchiffre localement, et assemble le ZIP final prêt à être remis à un commissariat, un avocat ou un procureur.
Pourquoi maintenant¶
- PD-85 (backend export) est en cours de finalisation — l'API
POST /exports/complaint-filesera disponible. - PD-282 (ProofEnvelope seal eIDAS) a finalisé le format d'enveloppe auto-vérifiable.
- PD-34 (key derivation) et PD-242 (recovery envelope) fournissent l'infrastructure cryptographique client pour le déchiffrement local.
- Le cadre juridique français (art. 1366 Code civil) rend l'auto-portance du dossier critique : un ZIP dont l'intégrité est vérifiable indépendamment a une valeur probante supérieure à des captures d'écran.
Learnings injectés¶
- PD-276 : Zero-knowledge validation pattern — validate-only, no key derivation côté serveur.
- PD-262 : Injection fichiers natifs Swift/ObjC obligatoire pour reviews LLM (stories app avec composant natif).
- PD-276 : Qualifier INV probatoire partiel dès v1.
2. Objectif¶
Permettre à un utilisateur (ou son représentant légal) d'assembler localement un dossier probatoire complet, auto-porteur et vérifiable au format .pvproof (conteneur ZIP avec extension dédiée), à partir des données fournies par l'API PD-85, sans qu'aucun contenu en clair ne transite par le serveur.
Format .pvproof — RFC PV-PACK-001¶
Le fichier exporté est conforme au RFC PV-PACK-001 v1.0.0 (ProbatioVault Proof Package Format).
Résumé du RFC : - Extension .pvproof (conteneur ZIP avec extension dédiée) - Fichier pvproof.json en première entrée de l'archive (mode STORED, sans compression) - Structure normalisée : preuves/, enveloppes/, manifest, chronology, readme, guide - 6 invariants de format (INV-PACK-01 à INV-PACK-06) - Règles de validation structurelle (12 règles, 13 codes d'erreur) - Sanitisation obligatoire des noms de fichiers (path traversal, zip slip) - Passthrough strict des artefacts backend
Référence complète : ProbatioVault-doc/docs/normes/pv-pack/RFC-PV-PACK.md
3. Périmètre V1 — Must-have¶
3.1 Appel API backend (PD-85)¶
L'app appelle POST /exports/complaint-file avec la liste des proofIds sélectionnés par l'utilisateur. Le backend retourne :
manifest.json(inventaire, integrityHash SHA3-256)chronology.json(événements probatoires ordonnés)signedUrls[](URLs pré-signées S3, TTL ≤ 30 min)guideUrl(guide_plainte_france.pdf)readmeVerification(texte de vérification inline)rejectedProofs[](preuves rejetées avec motifs)
3.2 Téléchargement des fichiers chiffrés¶
- Téléchargement séquentiel des fichiers via les URLs signées
- Retry automatique : maxRetries = 3, délai exponentiel (1s, 2s, 4s)
- Si URL expirée → demander un refresh au backend (nouvel appel API)
- Si fichier introuvable → abort de l'export avec message explicite
- Si échec final après retries → proposer à l'utilisateur de réessayer
3.3 Déchiffrement local (Zero-Knowledge)¶
- Dérivation de K_doc à partir de kmaster (PD-34) pour chaque fichier
- Déchiffrement AES-256-GCM en mémoire (1 fichier à la fois)
- Aucun contenu en clair ne persiste sur disque en dehors du ZIP final
- Les fichiers temporaires déchiffrés sont écrits directement dans le stream ZIP
3.4 Assemblage ZIP structuré (streaming disque)¶
Architecture obligatoire : assemblage en streaming, 1 fichier en mémoire max. Pas de ZIP en mémoire (crash mobile garanti sur 500 MB).
Processus par fichier : 1. Download fichier chiffré 2. Decrypt en mémoire 3. Append au ZIP sur disque 4. Delete fichier temporaire
Structure interne du conteneur .pvproof :
PV-Dossier-Plainte_{YYYY-MM-DD}_{exportId-short}.pvproof
│
├── pvproof.json ← déclaration de format (PREMIER fichier, obligatoire)
├── manifest.json ← inventaire + integrityHash (depuis backend)
├── chronology.json ← événements probatoires ordonnés (depuis backend)
├── README_VERIFICATION.txt ← instructions de vérification (depuis backend)
├── guide_plainte_france.pdf ← guide de procédure (depuis backend guideUrl)
├── preuves/
│ ├── {originalFilename-1} ← fichier original déchiffré
│ ├── {originalFilename-2}
│ └── ...
└── enveloppes/
├── {proofId-1}-envelope.json ← ProofEnvelope RFC PV-PROOF-001
├── {proofId-2}-envelope.json
└── ...
Nommage du fichier : PV-Dossier-Plainte_{date}_{exportId-8chars}.pvproof Exemple : PV-Dossier-Plainte_2026-03-09_a1b2c3d4.pvproof
3.5 Calcul et affichage du hash SHA3-256¶
- Après assemblage complet du
.pvproof, calcul du hash SHA3-256 en streaming sur le fichier final (pas de chargement complet en mémoire — peut prendre 1-4s sur 500 MB mobile) - Affichage du hash à l'utilisateur (copier/coller possible)
- Ce hash est informatif (vérification de transmission intacte). La force probante juridique repose sur les ProofEnvelopes individuelles (seal HSM, Merkle, TSA, blockchain anchor) — pas sur le hash du conteneur, qui n'est ni scellé ni ancré
3.6 UX — Progression multi-étapes¶
Progression obligatoire. Pas de spinner. L'export peut durer 10 à 60 secondes.
Écran de progression :
Préparation du dossier
──────────────────────
⬇ Téléchargement preuves (3 / 12)
🔓 Déchiffrement fichiers (5 / 12)
📦 Assemblage du dossier
✔ Finalisation
Chaque étape affiche le nombre traité / total. Si blocage détectable, l'utilisateur peut identifier l'étape en cause.
3.7 Partage et sauvegarde post-assemblage¶
Après génération du ZIP, écran avec 3 actions :
- Partager → share sheet native iOS (AirDrop, Mail, Files, Drive, WhatsApp...)
- Sauvegarder → enregistrer dans Files
- Supprimer → suppression immédiate du ZIP
3.8 Rappel et suppression du .pvproof (privacy)¶
Rappel à 24h (notification locale) : "Votre dossier probatoire est toujours sur l'appareil. Pensez à le partager ou le sauvegarder."
Suppression manuelle uniquement — pas d'auto-suppression (risque de perte de preuve si l'utilisateur a oublié de partager).
L'écran du dossier affiche en permanence : "Données sensibles — supprimez ce fichier après l'avoir transmis à votre avocat ou aux autorités."
Justification : la suppression automatique est dangereuse pour un dossier probatoire que l'utilisateur pourrait avoir besoin de retransmettre.
3.9 Gestion des rejets partiels¶
Si le backend retourne des rejectedProofs :
- Afficher la liste des preuves rejetées avec motifs
- Proposer de continuer avec les preuves valides uniquement
- Si l'utilisateur confirme → procéder à l'assemblage partiel
- Si toutes les preuves sont rejetées (422) → message explicite, pas d'assemblage
4. Hors périmètre V1 — Reporté¶
| Fonctionnalité | Raison du report | Story V2 |
|---|---|---|
| Android | Story dédiée | À créer |
| PWA / Web | Story dédiée | À créer |
| Timeline PDF riche | Moteur de rendu PDF complexe | PD-283 V2 |
| Script de vérification automatisé | Complexité multi-plateforme | V2 backend |
Chiffrement du .pvproof lui-même | Le conteneur contient des fichiers en clair — chiffrement optionnel V2 | À évaluer |
Outil CLI pv verify | Vérificateur en ligne de commande pour .pvproof | RFC PV-PACK-001 §10 |
Enregistrement MIME type application/vnd.probatiovault.proof | Association OS pour ouverture automatique | V2 |
| Export en arrière-plan (background task) | iOS limite les background tasks — V1 foreground uniquement | V2 |
5. Use cases principaux¶
UC-01 : Export nominal (adulte, Premium, iOS)¶
- L'utilisateur Premium sélectionne 5 preuves scellées
- L'app appelle
POST /exports/complaint-fileavec les 5proofIds - Le backend retourne manifest + chronology + signedUrls + guide + readme
- Progression : téléchargement ⅕, ⅖... déchiffrement ⅕, ⅖... assemblage
- ZIP final assemblé sur disque (streaming)
- Hash SHA3-256 calculé et affiché
- Écran : Partager / Sauvegarder / Supprimer
- L'utilisateur partage le
.pvproofvia AirDrop à son avocat - Rappel à 24h si le fichier est toujours présent
UC-02 : Export nominal (mineur via représentant légal)¶
Identique à UC-01, avec ajouts : - Le représentant légal initie l'export pour le compte du mineur - Le manifest backend inclut automatiquement les évidences additionnelles (Mandate, Dual Validation, ReKey Lifecycle) - L'app assemble ces évidences dans le ZIP sans traitement spécifique (passthrough)
UC-03 : Export partiel avec preuves rejetées¶
- L'utilisateur sélectionne 10 preuves
- L'app appelle le backend → 2 preuves rejetées (INV-02, INV-03)
- L'app affiche : "2 preuves ne peuvent pas être incluses" + motifs
- L'utilisateur confirme : continuer avec les 8 preuves valides
- Assemblage du
.pvproofavec 8 preuves
UC-04 : Échec réseau pendant téléchargement¶
- Téléchargement en cours (preuve 7/12)
- Perte réseau → retry automatique (1s, 2s, 4s)
- Si 3 retries échoués → message : "Impossible de télécharger 1 preuve. Voulez-vous réessayer ?"
- L'utilisateur réessaie → succès
- Assemblage continue
UC-05 : URL signée expirée¶
- L'utilisateur a mis l'app en background pendant le téléchargement
- Retour au premier plan → URL expirée (> 30 min)
- L'app détecte l'expiration → demande de nouvelles URLs au backend (nouvel appel API)
- Téléchargement reprend avec les nouvelles URLs
UC-06 : Export bloqué (utilisateur gratuit)¶
- L'utilisateur gratuit tente l'export
- Le backend retourne 403 (plan FREE)
- L'app affiche le message de blocage + CTA Premium (conformément à PD-84)
- Bouton export grisé pour les utilisateurs gratuits
6. Architecture haut niveau¶
6.1 Flux de données¶
┌──────────────┐ POST /exports/complaint-file ┌──────────────┐
│ │ ─────────────────────────────────> │ │
│ App iOS │ │ Backend │
│ (PD-283) │ <───────────────────────────────── │ (PD-85) │
│ │ { manifest, chronology, │ │
│ │ signedUrls, guide, readme } │ │
│ │ │ │
│ │ GET signedUrl (x N preuves) │ S3 WORM │
│ │ ─────────────────────────────────> │ (PD-4/44) │
│ │ <───────────────────────────────── │ │
│ │ fichiers chiffrés │ │
└──────┬───────┘ └──────────────┘
│
│ Pour chaque fichier :
│ 1. Download (chiffré)
│ 2. Decrypt (K_doc via kmaster, PD-34)
│ 3. Append au .pvproof (streaming disque)
│ 4. Delete temp
│
▼
.pvproof sur disque (conteneur ZIP, extension dédiée)
│
│ SHA3-256(.pvproof)
│
▼
Share sheet / Save / Delete
Auto-delete 24h
6.2 Responsabilités¶
| Composant | Responsabilité | Justification |
|---|---|---|
| Backend (PD-85) | Validation RFC, manifest, chronologie, URLs signées, guide, readme | Cohérence probatoire, contrôle d'accès |
| App iOS (PD-283) | Téléchargement, déchiffrement, assemblage .pvproof streaming, hash final, UX progression, share sheet | Zero-Knowledge : le serveur ne voit jamais le clair |
| S3 WORM (PD-4/44) | Stockage des fichiers chiffrés | Immuabilité |
| Crypto client (PD-34) | Dérivation K_doc depuis kmaster | Infrastructure cryptographique |
6.3 Choix multi-plateforme¶
| Décision | Choix V1 | Compatibilité future |
|---|---|---|
| Plateforme cible | iOS (React Native) | Android + PWA dans stories dédiées |
| Librairie ZIP | react-native-zip-archive ou JSZip streaming | JSZip compatible web, zip-archive compatible Android |
| Crypto | Existing crypto module PD-34 (kmaster derivation) | Abstraction crypto cross-platform |
| Share | iOS share sheet (react-native-share) | Android share intent natif |
| Hash SHA3-256 | js-sha3 ou noble-hashes | Cross-platform JS |
| Stockage temp | iOS app sandbox (tmp/) | Android cache dir / Web Blob |
7. Invariants et contraintes¶
7.1 Invariants propres à PD-283¶
| ID | Règle | Justification |
|---|---|---|
| INV-283-01 | Aucun contenu probatoire en clair ne persiste hors du .pvproof final | Zero-Knowledge constitutionnel — fichiers temp supprimés immédiatement |
| INV-283-02 | L'assemblage .pvproof est en streaming disque (1 fichier en mémoire max) | Prévention OOM mobile (crash garanti à 500 MB en RAM) |
| INV-283-03 | Le hash SHA3-256 est calculé en streaming sur le fichier .pvproof final complet | Hash informatif (vérification de transmission) — pas de force probante juridique propre |
| INV-283-04 | Un rappel de suppression est émis 24h après génération (notification locale) | Privacy — données sensibles, mais suppression automatique interdite (risque perte preuve) |
| INV-283-05 | Les fichiers temporaires chiffrés sont supprimés après déchiffrement | Réduction surface d'exposition |
| INV-283-06 | Le retry de téléchargement suit un backoff exponentiel (3 tentatives max) | Résilience réseau sans boucle infinie |
| INV-283-07 | L'app ne modifie aucun artefact reçu du backend (manifest, chronology, envelopes) | Intégrité probatoire — passthrough strict |
| INV-283-08 | Le fichier pvproof.json est le PREMIER entry de l'archive, écrit en mode STORED (sans compression) | Convention conteneur identique à mimetype dans EPUB — détection de format par offset fixe |
| INV-283-09 | L'extension du fichier exporté est .pvproof (jamais .zip) | Identité protocolaire ProbatioVault |
| INV-283-10 | Les noms de fichiers originaux sont sanitizés avant insertion dans l'archive (suppression ../, caractères spéciaux, longueur bornée) | Prévention path traversal / zip slip — un fichier uploadé nommé ../../manifest.json ne doit jamais écraser un fichier racine |
7.2 Invariants hérités¶
| ID | Règle | Source |
|---|---|---|
| INV-85-01 | Le backend ne déchiffre jamais les documents exportés | PD-85 (Zero-Knowledge) |
| INV-85-04 | Les URLs signées expirent en ≤ 30 minutes | PD-85 |
| INV-85-07 | Taille totale exportée : recommandé < 500 MB, supporté ≤ 1 GB | PD-85 — 1 GB reste très lourd sur mobile (stockage, partage) |
7.3 Contraintes produit¶
- UX : progression multi-étapes obligatoire (pas de spinner)
- Privacy : rappel 24h + suppression manuelle (pas d'auto-suppression)
- Réseau : retry 3x avec backoff exponentiel
- Mémoire : streaming obligatoire, jamais de ZIP en RAM complète
- Multi-plateforme : choix techniques compatibles Android et PWA futurs
8. Dépendances¶
8.1 Dépendances amont (requises)¶
| Story | Composant | Statut | Impact |
|---|---|---|---|
| PD-85 | Backend export dossier plainte | En cours | API POST /exports/complaint-file |
| PD-34 | Key derivation (kmaster) | DONE | Dérivation K_doc pour déchiffrement local |
| PD-242 | Recovery Envelope | DONE | Gestion des clés de récupération |
| PD-282 | ProofEnvelope seal eIDAS | DONE | Format enveloppe auto-vérifiable |
| PD-84 | Offre gratuite B2C-Mineurs | DONE | Contrôle Premium / CTA |
| PD-4/44 | S3 WORM + Object Lock | DONE | Stockage des fichiers chiffrés |
8.2 RFC et normes¶
| Référence | Usage |
|---|---|
| RFC PV-PACK-001 v1.0.0 | Format conteneur .pvproof (structure, validation, invariants) |
| RFC PV-PROOF-001 v1.2.0 | Format ProofEnvelope (passthrough) |
| RFC 8785 (JCS) | Canonicalisation JSON (manifest, non modifié par l'app) |
| Art. 1366 Code civil | Valeur probante de l'écrit électronique |
9. Critères d'acceptation préliminaires¶
Fonctionnels¶
- L'app appelle
POST /exports/complaint-fileet traite la réponse correctement - Les fichiers chiffrés sont téléchargés via les URLs signées avec retry (3x, backoff exponentiel)
- Chaque fichier est déchiffré localement avec K_doc dérivée de kmaster
- Le
.pvproofest assemblé en streaming sur disque (pas en mémoire) -
pvproof.jsonest le premier entry de l'archive, en mode STORED (sans compression) - La structure interne respecte l'arborescence définie (preuves/, enveloppes/, manifest, chronology, guide, readme)
- Le hash SHA3-256 du
.pvproofest calculé et affiché à l'utilisateur - Le fichier exporté porte l'extension
.pvproof(jamais.zip) - La progression multi-étapes est affichée (téléchargement N/M, déchiffrement N/M, assemblage, finalisation)
- Les rejets partiels sont affichés avec motifs, l'utilisateur peut continuer
- La share sheet native est disponible après génération
- Un rappel notification locale est émis 24h après génération
- La suppression est manuelle uniquement (pas d'auto-suppression)
Sécurité¶
- Aucun fichier en clair ne persiste hors du
.pvprooffinal - Les fichiers temporaires sont supprimés immédiatement après usage
- Aucun artefact backend n'est modifié par l'app (passthrough)
- Le déchiffrement utilise K_doc dérivée (PD-34), jamais kmaster directement
- Les noms de fichiers sont sanitizés avant insertion (pas de
../, caractères spéciaux supprimés, longueur bornée)
Erreurs¶
- URL expirée → refresh automatique via nouvel appel API
- Fichier introuvable → abort export avec message explicite
- Échec réseau → retry 3x puis proposition utilisateur
- 403 (FREE) → message + CTA Premium
- 422 (toutes preuves rejetées) → message explicite, pas d'assemblage
Non-fonctionnels¶
- Export de 12 preuves (50 MB total) en < 30s (Wi-Fi, P95)
- Export de 50 preuves (200 MB total) en < 60s (Wi-Fi, P95)
- Pic mémoire < 50 MB pendant l'assemblage (streaming)
- Compatible React Native iOS, choix extensibles Android/PWA