Aller au contenu

PD-101 — Upload probatoire mobile chiffré avec progression, reprise et annulation orchestrée

1. Objectif

Spécifier contractuellement le flux de dépôt mobile d'un document dans ProbatioVault, de la sélection locale jusqu'à la confirmation backend, avec chiffrement local préalable, suivi de progression, gestion d'erreurs, annulation orchestrée et mode optionnel de capture optimisée, sans compromettre le modèle zero-knowledge ni l'intégrité probatoire.

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

Inclus

  • Sélection document via Photos picker et File picker.
  • Détection de transcodage iOS côté Photos picker et avertissement utilisateur.
  • Vérification de taille fichier et rejet si dépassement.
  • Chiffrement local FILE-LEVEL avant envoi réseau (AES-256-GCM, clé dérivée HKDF).
  • Calcul du hash SHA3-256 du fichier effectivement probatoire avant chiffrement.
  • Upload simple (< 10 MB) et multipart (>= 10 MB) via URL pré-signées.
  • Suivi UX de progression (pourcentage, ETA, vitesse), y compris en background.
  • Retry automatique avec backoff exponentiel et jitter.
  • Annulation orchestrée client + S3 + backend (statut CANCELLED).
  • Mode "capture optimisée" explicite avec consentement traçable.

Exclu

  • Proxy Re-Encryption (PRE) et gestion Legal PRE.
  • Ancrage blockchain immédiat côté mobile.
  • Génération de preuve composite.
  • Synchronisation multi-device.
  • Suppression sélective de métadonnées EXIF.

3. Définitions

  • Fichier original : fichier binaire présent dans la photothèque ou le système de fichiers avant toute interaction avec l'app.
  • Fichier soumis : fichier binaire effectivement reçu par l'app après sélection (peut différer de l'original si transcodage iOS).
  • Fichier probatoire : fichier sur lequel porte le hash probatoire et qui sera scellé. En mode par défaut = fichier soumis. En mode optimisé = version transformée.
  • Mode par défaut : dépôt strictement fidèle bit-à-bit au fichier soumis (reçu par l'app).
  • Mode capture optimisée : dépôt d'une version transformée après consentement explicite.
  • Zero-knowledge : backend incapable d'accéder au contenu en clair.
  • doc_id : identifiant unique du dépôt, format UUID v4.
  • Upload simple : envoi en une seule requête pour fichier < 10 MB (10 000 000 bytes, SI base 10).
  • Upload multipart : envoi chunké pour fichier >= 10 MB (10 000 000 bytes, SI base 10).
  • Retryable : erreur pouvant déclencher un retry automatique.
  • Terminal : état sans transition sortante autorisée.

3.1 Modèle d'états contractuel

  • États UI : UPLOADING, FAILED, COMPLETED, CANCELLED.
  • États backend document : PENDING, READY, PENDING_SEAL, CANCELLED.

3.2 Formats et contraintes de données (source unique)

Donnée Format/encodage Taille Jeu de caractères Case Regex/validation Si invalide
doc_id UUID v4 texte 36 caractères [0-9a-f-] insensitive pour hex ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$ Rejet (400)
sha3_256 hex 64 caractères (32 bytes) [0-9a-f] case-sensitive (lowercase requis) ^[a-f0-9]{64}$ + vérification fonctionnelle côté mobile (recalcul post-chiffrement) Rejet (400)
nonce AES-GCM binaire (base64 en transport) 12 bytes N/A binaire N/A longueur exacte 12 bytes + unicité par doc_id Échec chiffrement, flux abort
auth_tag GCM binaire (base64 en transport) 16 bytes N/A N/A longueur exacte 16 bytes Rejet (400)
optimized booléen JSON 1 booléen true/false N/A type booléen strict Rejet (400)
ios_transcoded booléen JSON 1 booléen true/false N/A type booléen strict Rejet (400)
mime_type MIME RFC 6838 3..255 caractères ASCII printable case-insensitive pattern MIME standard Rejet (400)
filename UTF-8 1..255 caractères UTF-8 sans \0 case-sensitive non vide Rejet UX
file_size_bytes entier 1..524288000 bytes N/A N/A entier positif <= 500 MB Refus UX + aucun upload

Règle de référence : toute section citant ces données doit référencer cette table, sans redéfinition de format.

3.3 Architecture de chiffrement (FILE-LEVEL)

Le chiffrement s'applique au fichier entier (FILE-LEVEL), avant tout découpage multipart :

  1. Le mobile génère un nonce unique de 12 bytes par doc_id.
  2. Le fichier probatoire complet est chiffré en une seule opération AES-256-GCM avec ce nonce.
  3. Le ciphertext résultant (fichier chiffré complet) est ensuite découpé en chunks pour l'upload multipart si nécessaire.
  4. Les chunks uploadés sont des morceaux du ciphertext, jamais du plaintext.
  5. Le auth_tag GCM est calculé sur la totalité du fichier chiffré.

Interdit : chiffrement chunk-level (un nonce par chunk) — un nonce unique par chunk avec la même clé créerait une réutilisation de (key, nonce) et briserait la sécurité GCM.

3.4 Format de preuve de consentement

Pour le mode capture optimisée (INV-04), la preuve de consentement est un objet JSON :

{
  "action": "optimized_consent",
  "timestamp": "2026-03-10T14:30:00.000Z",
  "doc_id": "550e8400-e29b-41d4-a716-446655440000",
  "user_confirmed": true
}

Cet objet est : - Persisté dans les metadata backend du document. - Enregistré dans le journal d'audit. - Horodaté en ISO 8601 UTC.

4. Invariants (non négociables)

ID Règle Justification
INV-01-zero-knowledge Aucun octet en clair ne doit être envoyé au backend ou à S3. Respect architecture zero-knowledge.
INV-02-pre-encryption Le chiffrement FILE-LEVEL doit être terminé avant la première requête d'upload. Empêche fuite réseau de contenu clair.
INV-03-probatory-fidelity-default En mode par défaut, le fichier probatoire est bit-à-bit identique au fichier soumis (reçu par l'app). Intégrité juridique de la preuve.
INV-04-explicit-optimized-consent Toute transformation (compression/conversion) exige consentement explicite traçable avant dépôt (cf. §3.4). Interdiction des transformations silencieuses.
INV-05-hash-functional-validation Le hash SHA3-256 est validé fonctionnellement côté mobile par recalcul contrôlé (hash avant chiffrement, puis recalcul sur le plaintext déchiffré pour vérifier l'intégrité du pipeline). Le backend ne fait que valider le format (regex + longueur). Évite faux positifs de conformité tout en respectant le zero-knowledge.
INV-06-nonce-uniqueness Le nonce AES-GCM est unique par document (doc_id). Un seul nonce par fichier (chiffrement FILE-LEVEL). Sécurité cryptographique GCM.
INV-07-sensitive-purge Aucun artefact sensible en clair persistant sur disque ; purge fichier stricte + purgeStale() au démarrage du flux. La purge mémoire RAM est best-effort sur Hermes/React Native (cf. H-06). Résilience crash et conformité sécurité.
INV-08-envelope-encryption Tout artefact cryptographique temporaire (clé, fragment, DEK, ReKey) est chiffré au repos (AES-256-GCM ou HSM envelope). Aucun secret en clair en base. Invariant crypto-proof obligatoire.
INV-09-state-transitions Toute transition d'état (UI et backend) doit être explicitement autorisée ou interdite (cf. §5.6). Évite ambiguïtés de machine à états.
INV-10-no-sensitive-logs Les logs ne doivent contenir ni plaintext, ni clés, ni nonce brut, ni hash corrélable au contenu sans besoin métier explicite. Réduction surface de fuite.

5. Flux nominaux

5.1 Flux nominal A — Dépôt fidèle (mode par défaut)

  1. L'utilisateur sélectionne un fichier (Photos ou File picker).
  2. Le système récupère métadonnées locales (filename, mime_type, file_size_bytes) et génère doc_id.
  3. Contrôle taille : file_size_bytes <= 500 MB ; sinon refus.
  4. Si source Photos et transcodage détecté :
  5. Affichage avertissement explicite.
  6. L'utilisateur peut continuer ou changer de source.
  7. Si l'utilisateur continue, ios_transcoded: true est enregistré dans les metadata. Le fichier probatoire est le fichier reçu par l'app (post-transcodage), et INV-03 s'applique à ce fichier soumis.
  8. Affichage disclaimer métadonnées EXIF : l'utilisateur doit confirmer explicitement avant que l'upload ne puisse continuer.
  9. Calcul sha3_256 sur fichier probatoire (ici = fichier soumis), puis chiffrement local AES-256-GCM FILE-LEVEL (cf. §3.3).
  10. Vérification d'intégrité mobile : recalcul du hash sur le plaintext conservé en mémoire et comparaison avec le hash calculé à l'étape 6. Si divergence, abort du flux (ERR-02).
  11. Initialisation backend : création enregistrement PENDING + URL pré-signée(s).
  12. Sélection stratégie upload :
  13. < 10 MB (10 000 000 bytes) : upload simple.
  14. >= 10 MB (10 000 000 bytes) : multipart (chunks du ciphertext).
  15. Exécution upload avec progression UI en continu.
  16. Confirmation de finalisation au backend ; transition backend PENDING -> READY -> PENDING_SEAL.

5.2 Flux nominal B — Dépôt en mode capture optimisée

  1. L'utilisateur active explicitement "Capture optimisée".
  2. Le système affiche avertissement d'altération probatoire ; consentement explicite requis (cf. §3.4 pour le format de preuve).
  3. Le fichier probatoire devient la version transformée.
  4. optimized = true est enregistré. La preuve de consentement (§3.4) est persistée en metadata backend et dans le journal d'audit.
  5. Le hash probatoire porte sur la version transformée.
  6. Chiffrement et upload suivent le même flux que 5.1.
  7. Retour vers mode fidèle pour ce dépôt : interdit après confirmation.

5.3 Flux nominal C — Continuité en background

  1. Si application passe en arrière-plan pendant UPLOADING, l'upload continue.
  2. À terminaison, notification locale unique (succès ou échec) si app non active.
  3. Au retour foreground, l'état affiché reflète l'état réel sans doublon.

5.4 Flux nominal D — Retry après échec

Après FAILED, l'utilisateur peut retenter le dépôt. Le retry crée un nouveau flux complet : nouveau doc_id, nouveau nonce, nouveau chiffrement, nouvel upload. L'ancien enregistrement backend reste en état FAILED / PENDING (non modifié). Aucune réutilisation de doc_id ou de nonce n'est autorisée.

5.5 Paramètres numériques contractuels

Paramètre Défaut Min Max Unité Contexte Hors bornes
Taille max fichier 500 1 500 MB Tous devices supportés app Rejet UX
Seuil multipart 10 10 10 MB (10 000 000 bytes, SI base 10) Règle fixe produit N/A (règle fixe)
Taille chunk multipart 5 5 50 MB Mobile, streaming, RAM maîtrisée Clamp [5,50] puis upload
Retry max 3 0 5 tentatives Par chunk multipart / global simple Clamp [0,5]
Backoff base 1 1 10 seconde Réseau mobile/WiFi Clamp [1,10]
Backoff séquence 1,2,4 N/A N/A secondes Tentatives 1..3 N/A
Jitter activé N/A N/A booléen Anti-thundering herd Si désactivé: non conforme
Mémoire claire en RAM N/A 0 100 MB Device iOS cible Échec flux + erreur UX
Upload perf cible 100MB 30 N/A 30 secondes (P95) WiFi stable, device de référence iPhone 12/A14 Alerte perf (non blocant métier)

5.6 SLA temporels

  • Aucune transition temporelle réglementaire de type TTL/expiration métier n'est identifiée dans cette story.
  • Point à clarifier : TTL des URL pré-signées non fourni dans le besoin (impact sécurité/disponibilité).

5.7 Transitions d'états (avec transitions inverses)

État Transitions sortantes autorisées Transitions interdites
UI UPLOADING -> COMPLETED, -> FAILED, -> CANCELLED -> UPLOADING (boucle sans événement)
UI FAILED -> UPLOADING (nouveau flux complet, cf. §5.4) -> COMPLETED direct
UI COMPLETED (terminal) aucune -> * : INTERDITE (état terminal)
UI CANCELLED (terminal) aucune -> * : INTERDITE (état terminal)
Backend PENDING -> READY, -> CANCELLED -> PENDING_SEAL direct
Backend READY -> PENDING_SEAL, -> CANCELLED (garde : si PENDING_SEAL non encore atteint) -> PENDING
Backend PENDING_SEAL (hors scope story) géré par worker d'ancrage -> PENDING, -> CANCELLED
Backend CANCELLED (terminal) aucune -> * : INTERDITE (état terminal, résolution manuelle uniquement)

Règle retour explicite : toute transition inverse non listée est interdite.

Race condition documentée : une annulation READY -> CANCELLED peut être en concurrence avec le worker d'ancrage effectuant READY -> PENDING_SEAL. La garde est implémentée par un UPDATE ... WHERE status = 'READY' atomique. Si le worker a déjà transitionné vers PENDING_SEAL, l'annulation échoue et le client reçoit une erreur indiquant que le scellement est déjà en cours. Le document ne peut plus être annulé après PENDING_SEAL.

5.8 Atomicité multi-composant (DB + async)

Scope Synchrone/Async Garantie
Création/MAJ enregistrement backend upload Synchrone (transaction DB) Atomicité ACID
Notification/traitement d'ancrage (READY -> PENDING_SEAL) Async post-commit Idempotent, retry-safe
Annulation READY -> CANCELLED Synchrone (UPDATE WHERE atomique) Exclusion mutuelle avec transition PENDING_SEAL
AbortMultipartUpload S3 Async, best-effort Reconciliation par job périodique (cf. §5.9)
Crash pré-commit N/A Rollback complet, aucun état persistant incomplet
Crash post-commit N/A État DB valide, reprise asynchrone par worker de réconciliation

5.9 Nettoyage S3 best-effort

AbortMultipartUpload est best-effort côté S3. Des parts orphelines peuvent persister en cas d'échec de l'appel d'abort. Deux mécanismes complémentaires assurent le nettoyage :

  1. S3 Lifecycle Policy : règle d'expiration automatique des uploads multipart incomplets (configurable, recommandé 7 jours).
  2. Job de réconciliation backend : job périodique qui liste les uploads multipart actifs (ListMultipartUploads) et aborte ceux dont le doc_id associé est en état CANCELLED ou FAILED depuis plus de 24h.

5.10 Contraintes inter-modules

Aucune contrainte inter-module applicable (aucun guard cross-module requis par cette story).

5.11 Migration DDL

Aucune modification de colonne existante identifiée dans le périmètre de cette story.

5bis. Diagrammes

5bis.1 Diagramme d'états — UI (client mobile)

stateDiagram-v2
    [*] --> UPLOADING : Dépôt confirmé (chiffrement terminé, INV-02)

    UPLOADING --> COMPLETED : Upload finalisé + backend READY
    UPLOADING --> FAILED : Erreur non retryable ou retries épuisés (ERR-02..06)
    UPLOADING --> CANCELLED : Annulation utilisateur (ERR-07)

    FAILED --> UPLOADING : Retry utilisateur (nouveau flux complet §5.4)

    COMPLETED --> [*]
    CANCELLED --> [*]

    note right of COMPLETED : Terminal — aucune transition sortante (INV-09)
    note right of CANCELLED : Terminal — aucune transition sortante (INV-09)
    note left of FAILED : Retry = nouveau doc_id, nouveau nonce (INV-06)

5bis.2 Diagramme d'états — Backend (document)

stateDiagram-v2
    [*] --> PENDING : Initialisation upload (création enregistrement)

    PENDING --> READY : Upload finalisé avec succès
    PENDING --> CANCELLED : Annulation utilisateur

    READY --> PENDING_SEAL : Worker d'ancrage (async post-commit)
    READY --> CANCELLED : Annulation utilisateur (garde atomique UPDATE WHERE)

    PENDING_SEAL --> [*] : Hors scope story (worker ancrage PD-55)

    CANCELLED --> [*]

    note right of PENDING_SEAL : Après PENDING_SEAL, annulation impossible (§5.7)
    note right of CANCELLED : Terminal — résolution manuelle uniquement (INV-09)
    note left of READY : Race condition READY→CANCELLED vs READY→PENDING_SEAL\nExclusion mutuelle par UPDATE WHERE atomique (§5.7)

5bis.3 Diagramme de séquence — Flux nominal upload (mode par défaut)

sequenceDiagram
    actor User
    participant App as Mobile App
    participant Crypto as Module Crypto (local)
    participant Backend as Backend API
    participant S3 as S3 (stockage)

    User->>App: Sélectionne fichier (Photos/File picker)
    App->>App: Métadonnées (filename, mime, size) + génère doc_id
    App->>App: Contrôle taille ≤ 500 MB (ERR-01 si KO)

    opt Transcodage iOS détecté
        App->>User: Avertissement transcodage
        User->>App: Confirme (ios_transcoded=true)
    end

    App->>User: Disclaimer EXIF
    User->>App: Confirmation explicite

    App->>App: purgeStale() — purge artefacts résiduels (INV-07)
    App->>Crypto: Hash SHA3-256 du fichier probatoire (INV-05)
    Crypto-->>App: sha3_256

    App->>Crypto: Chiffrement AES-256-GCM FILE-LEVEL (nonce unique, INV-06)
    Crypto-->>App: ciphertext + auth_tag + nonce

    App->>Crypto: Recalcul hash sur plaintext en mémoire (INV-05)
    Crypto-->>App: sha3_256_verify
    App->>App: Comparaison hash (abort si divergence, ERR-02)

    App->>Backend: POST /upload/init {doc_id, sha3_256, nonce, auth_tag, metadata}
    Backend-->>App: URL(s) pré-signée(s) + état PENDING

    alt Fichier < 10 MB (upload simple)
        App->>S3: PUT ciphertext via URL pré-signée
        S3-->>App: 200 OK
    else Fichier ≥ 10 MB (upload multipart)
        loop Pour chaque chunk du ciphertext
            App->>S3: PUT chunk via URL pré-signée
            S3-->>App: 200 OK + ETag
            App->>User: Progression (%, ETA, vitesse)
        end
    end

    App->>Backend: POST /upload/finalize {doc_id, parts}
    Backend->>Backend: PENDING → READY (transaction ACID)
    Backend-->>App: 200 OK

    Backend-)Backend: READY → PENDING_SEAL (async, worker ancrage)

    App->>User: État COMPLETED
    App->>Crypto: Purge artefacts sensibles (INV-07)

6. Cas d'erreur

ID Cas Type Réponse attendue
ERR-01 file_size_bytes > 500 MB Métier Refus immédiat, message utilisateur clair, aucun upload initié
ERR-02 Échec chiffrement local ou échec vérification intégrité hash (§5.1 étape 7) Technique Abort immédiat, purge artefacts sensibles, état FAILED
ERR-03 Timeout réseau/S3 Retryable Retry auto selon stratégie, puis FAILED si épuisé
ERR-04 Perte connectivité Retryable Retry auto, conservation état UPLOADING jusqu'à épuisement
ERR-05 HTTP 5xx backend/S3 Retryable Retry auto selon mode
ERR-06 HTTP 4xx fonctionnel (400, 403, 404, 409, 413, 422) Non retryable Échec immédiat, état FAILED, message explicite mappé au code HTTP
ERR-07 Annulation utilisateur Contrôlée Stop client, abort multipart si initié (best-effort, cf. §5.9), backend CANCELLED (avec garde si READY, cf. §5.7), purge async
ERR-08 Duplication notification retour foreground UX Interdit : au plus une notification locale par session d'upload
ERR-09 Format métadonnée invalide (doc_id, sha3_256, etc.) Validation Rejet 400 côté API, pas de transition READY
ERR-10 Annulation en état READY alors que worker a déjà transitionné vers PENDING_SEAL Race condition L'annulation échoue, le client reçoit un message d'erreur indiquant que le scellement est en cours

7. Critères d'acceptation (testables)

ID Critère Observable
CA-01 En mode par défaut, aucune transformation silencieuse n'est appliquée. Hash du fichier soumis (reçu par l'app) = hash probatoire stocké.
CA-02 En mode optimisé, consentement explicite est requis et optimized=true est tracé. Journal d'audit + metadata backend contiennent la preuve de consentement (§3.4).
CA-03 Aucun upload en clair n'est possible. Inspection trafic : pas de payload document en clair.
CA-04 Nonce unique par document. Deux dépôts distincts n'ont jamais le même nonce.
CA-05 Fichier > 500 MB est refusé avant chiffrement/upload. Message UI + absence d'appel upload.
CA-06 Seuil multipart appliqué strictement à 10 MB (10 000 000 bytes). 9.99 MB simple, 10.00 MB multipart.
CA-07 Retry multipart s'applique par chunk, retry simple s'applique globalement. Traces d'exécution conformes.
CA-08 Annulation orchestre client + S3 + backend CANCELLED. État final CANCELLED + absence de parts actives S3.
CA-09 Upload continue en background et état reste cohérent au retour. Pas de perte de progression ni doublon notification.
CA-10 purgeStale() est exécuté au démarrage d'un nouveau flux. Traces startup flux + suppression artefacts obsolètes.
CA-11 Hash SHA3-256 validé fonctionnellement côté mobile (recalcul post-chiffrement), pas seulement syntaxiquement. Test de corruption détecté et rejeté.
CA-12 Performance cible : upload 100 MB <= 30 s en WiFi P95 sur iPhone 12/A14. Campagne de mesure P95 conforme.
CA-13 Aucun secret cryptographique (DEK, KEK, nonce brut) n'est persisté en clair en base de données. Inspection DB : tous les secrets au repos sont chiffrés (envelope encryption).
CA-14 Aucun log ne contient de plaintext, clé, nonce brut, ou hash corrélable au contenu. Scan automatisé des journaux d'audit sans correspondance de patterns sensibles.

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

  • ST-01 (flux fidèle nominal) Given un fichier valide de 20 MB en mode par défaut When l'utilisateur confirme le dépôt Then le flux est multipart, l'état final est COMPLETED, backend passe PENDING -> READY -> PENDING_SEAL, et le hash probatoire correspond au fichier soumis (reçu par l'app).

  • ST-02 (seuil multipart) Given un fichier de 9 MB puis un fichier de 10 MB When l'upload démarre Then le premier est en simple upload et le second en multipart.

  • ST-03 (annulation orchestrée multipart) Given un upload multipart en cours When l'utilisateur annule Then la tâche client s'arrête, AbortMultipartUpload est déclenché (best-effort), backend est CANCELLED, et les artefacts temporaires sont purgés.

  • ST-04 (retry chunk) Given une erreur réseau transitoire sur un chunk multipart When la tentative échoue Then ce chunk est retenté au plus 3 fois avec backoff 1s/2s/4s + jitter.

  • ST-05 (mode optimisé explicite) Given un utilisateur active "Capture optimisée" When il confirme l'avertissement Then optimized=true, le hash porte sur la version optimisée, la preuve de consentement (§3.4) est persistée, et aucune réversion vers original n'est autorisée pour ce dépôt.

  • ST-06 (transcodage Photos détecté) Given une photo transcodée par iOS When l'utilisateur la sélectionne via Photos picker et continue malgré l'avertissement Then ios_transcoded=true est enregistré dans les metadata, le hash probatoire porte sur le fichier reçu par l'app.

  • ST-07 (purge crash recovery) Given des artefacts sensibles résiduels d'un crash précédent When un nouveau flux démarre Then purgeStale() supprime ces artefacts avant toute opération de chiffrement.

  • ST-08 (fichier hors limite) Given un fichier de 700 MB When l'utilisateur tente le dépôt Then le dépôt est refusé immédiatement avec message clair et sans appel backend d'initialisation.

  • ST-09 (retry après FAILED) Given un flux d'upload terminé en état FAILED When l'utilisateur retente le dépôt Then un nouveau flux complet démarre (nouveau doc_id, nouveau nonce, nouveau chiffrement). L'ancien enregistrement n'est pas modifié.

  • ST-10 (disclaimer EXIF) Given un fichier contenant des métadonnées EXIF When l'utilisateur sélectionne le fichier pour dépôt Then un disclaimer EXIF est affiché et une confirmation explicite est requise avant que l'upload puisse continuer.

  • ST-11 (annulation en READY — race condition) Given un document en état backend READY When l'utilisateur annule ET le worker d'ancrage tente simultanément READY -> PENDING_SEAL Then un seul des deux réussit (atomicité UPDATE WHERE). Si le worker gagne, l'annulation échoue et le client est informé.

  • ST-12 (chiffrement FILE-LEVEL vérifié) Given un fichier de 25 MB When le chiffrement est effectué Then un seul nonce est utilisé pour l'ensemble du fichier. Les chunks uploadés sont des morceaux du ciphertext, pas du plaintext.

9. Hypothèses explicites

ID Hypothèse Impact si faux
H-01 Le projet cible est ProbatioVault-app (React Native + Expo SDK 54 + TypeScript), et non une app Swift native. §10 contraint technique invalide, gate de conformité échoue.
H-02 Le backend expose les endpoints pré-signés et de finalisation attendus (PD-63 DONE). Blocage du flux d'upload en production.
H-03 Le worker d'ancrage asynchrone (PD-55 DONE) traite READY/PENDING_SEAL. Perte de continuité probatoire post-upload.
H-04 La taille de chunk multipart peut être bornée à [5 MB, 50 MB] côté configuration. Si non accepté, critères perf/mémoire doivent être redéfinis.
H-05 Le format de transport des champs binaires (nonce, auth_tag) est base64 côté API. Contrat API incompatible, erreurs de validation.
H-06 La purge mémoire RAM sur Hermes/React Native est best-effort. Le garbage collector Hermes ne garantit pas l'effacement immédiat des buffers en mémoire. La purge fichier disque est stricte (suppression explicite). Les tests de purge RAM sont limités à la vérification que les références sont nullifiées, sans garantie d'effacement physique immédiat.
H-07 La protection TLS (HTTPS) est supposée pour tous les transports réseau (client ↔ backend, client ↔ S3). Fuite de données en transit si TLS absent.

10. Points à clarifier

ID Point manquant Pourquoi c'est bloquant ou risqué
Q-01 Nom exact de l'épopée (valeur "Référence épique" non fournie). Référence documentaire incomplète.
Q-02 TTL exact des URL pré-signées (défaut/min/max, comportement à expiration). Risque d'échec upload et faille d'exposition temporelle.
Q-03 Règles exactes de validation MIME/UTType autorisés (liste blanche). Ambiguïté sécurité et UX de rejet.
Q-04 Politique de persistance des états UI après redémarrage app. Incohérence possible expérience utilisateur.
Q-05 Table/contrat backend exact pour optimized, ios_transcoded et champs probatoires. Risque de divergence mobile/backend sur traçabilité légale.
Q-06 Exigence formelle de nettoyage mémoire (niveau/langage/critère d'audit). Difficilement testable sans protocole d'audit défini (cf. H-06).

Références

  • Epic : Référence épique (à compléter)
  • JIRA : PD-101
  • Repos concernés : ProbatioVault-app, ProbatioVault-backend
  • Documents associés : PD-63 (URL pré-signées), PD-55 (worker ancrage), expression de besoin PD-101, learnings PD-264 / PD-251 / PD-283 / PD-262 / PD-282, contraintes constitutionnelles de gouvernance IA.