Aller au contenu

PD-284 — UX de scellement urgent et suivi temps réel (v3 corrigée)

1. Objectif

Spécifier le comportement contractuel de l’interface client ProbatioVault pour :

  • déclencher un scellement urgent lorsque l’utilisateur est éligible ;
  • afficher la progression du scellement en temps réel ;
  • exposer des états de dégradation lisibles et actionnables ;
  • notifier l’utilisateur à la clôture (succès/échec) ;
  • afficher, en mode expert, les artefacts probatoires disponibles selon l’état.

La présente spécification couvre le front mobile ProbatioVault-app et dépend de PD-80 pour les états backend, SLA et événements temps réel.


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

Inclus

  • Bouton Scellement urgent conditionné par éligibilité, quota et scellement urgent déjà actif.
  • Carte de progression à 5 étapes alignée sur la machine d’états PD-80.
  • Abonnement temps réel via SSE avec reprise et fallback polling.
  • Affichage des badges de dégradation dérivés des indicateurs serveur.
  • Panneau Mode expert conditionnel aux préférences utilisateur.
  • Notifications mobile de fin de traitement avec deep-link de retour.

Exclu

  • Pipeline backend de scellement (orchestration, BullMQ, TSA, Merkle, ancrage).
  • Facturation.
  • Monitoring opérationnel interne.
  • Android/Web.
  • API d’administration (retry/resubmit manuels).
  • Toute migration DDL (Aucune modification de schéma en front).

3. Définitions

  • Scellement urgent : traitement prioritaire d’un document selon PD-80.
  • SSE : flux unidirectionnel d’événements serveur vers client.
  • Fallback polling : interrogation périodique d’un endpoint d’état lorsque SSE est indisponible.
  • Mode expert : vue avancée affichant les détails probatoires.
  • État terminal : état sans transition sortante autorisée (SEALED, FAILED_TIMEOUT).
  • Dégradation : état UX indiquant un retard ou une situation critique signalée par le backend.
  • Erreur contrôlée : toast non bloquant affiché 5 secondes (auto-dismiss), journalisation telemetry obligatoire avec event_type et seal_id, sans blocage de l’UI ni interruption du flux utilisateur.

4. Invariants (non négociables)

ID Règle Justification
INV-284-01 Le bouton urgent est visible pour tout utilisateur account_type != minor ; il n’est jamais masqué pour un utilisateur éligible au parcours urgent. Cohérence UX et déterminisme d’affichage.
INV-284-02 Pour account_type = minor, aucun bouton urgent n’est affiché ; le fast-track est implicite. Décision PO et cohérence UX.
INV-284-03 Pour account_type != minor, le bouton est enabled uniquement si urgent_quota_remaining > 0 et has_active_urgent_seal = false; sinon il est disabled avec tooltip explicite. Contrat métier univoque.
INV-284-04 Tooltips disabled contractuels : quota nul → Quota épuisé ce mois; urgent déjà actif → Scellement urgent déjà en cours. Suppression des ambiguïtés CTR-01 / AMB-03.
INV-284-05 L’UI n’invente aucun seuil de dégradation ; elle consomme les indicateurs serveur comme source de vérité. Learning PD-81/PD-264.
INV-284-06 Toute transition d’état affichée doit correspondre à une transition autorisée PD-80 ; transition inconnue => erreur contrôlée. Conformité machine d’états.
INV-284-07 Chaque état du modèle d’affichage déclare explicitement ses transitions sortantes autorisées ou interdites. Exigence gate transitions inverses.
INV-284-08 SEALED et FAILED_TIMEOUT sont terminaux : → * : INTERDITE (état terminal, résolution manuelle uniquement). Fermeture explicite des états terminaux.
INV-284-09 Badge Hors ligne affiché uniquement en perte réseau détectée (navigator.onLine=false ou équivalent RN). Un échec SSE sans perte réseau ne déclenche pas ce badge. Distinction CTR-02.
INV-284-10 Aucun artefact sensible (tsa_token_ref, clés de session SSE, tokens d’authentification) n’est persisté en clair en stockage durable non protégé. Invariant sécurité domaine probatoire.
INV-284-11 Les artefacts publics (hash_document, merkle_root, blockchain_tx_hash) ne sont pas classés sensibles. Clarification NT-01.
INV-284-12 Les notifications de fin incluent un deep-link valide vers l’écran de détail du scellement concerné. Traçabilité utilisateur.
INV-284-13 Aucune contrainte inter-module backend supplémentaire n’est créée par cette story. Scope front-only.

5. Flux nominaux

5.1 Flux A — Déclenchement d’un scellement urgent

  1. L’utilisateur ouvre le détail document.
  2. Le client évalue les conditions d’affichage du bouton urgent selon données serveur (account_type, urgent_quota_remaining, has_active_urgent_seal).
  3. Si activable, l’action envoie POST /seals/urgent avec payload { document_id } (contrat exact — payload de réponse, codes d’erreur métier — défini par PD-80, hypothèse H-284-01).
  4. Le client affiche un feedback immédiat (chargement) et reçoit seal_id.
  5. Nouvelle étape obligatoire : le client appelle GET /seals/{seal_id}/status pour récupérer l’état initial canonique.
  6. Le client affiche la carte de progression associée au seal_id avec l’état initial issu du GET.
  7. Le client ouvre ensuite le flux SSE pour ce seal_id ; SSE prend le relais du suivi.

5.2 Flux B — Suivi temps réel de progression (SSE + reprise)

  1. Le client ouvre un flux SSE sur le scellement.
  2. À chaque événement valide, l’UI met à jour :
  3. étape visuelle (Capture, TSA, Merkle, Blockchain, Scellé),
  4. badge de dégradation (si fourni),
  5. disponibilité des détails expert.
  6. Le client maintient un cache local FIFO des N=100 derniers event_id (politique d'éviction : les event_id les plus anciens sont éjectés en premier — FIFO, pas LRU).
  7. si event_id déjà vu : événement ignoré silencieusement (déduplication, pas de toast, trace telemetry uniquement en mode debug).
  8. Chaque événement contient aussi sequence_number (entier croissant).
  9. en cas de réception désordonnée, le client attend une fenêtre de grâce de 200 ms pour recevoir le(s) sequence_number manquant(s) avant réordonnancement et rendu ;
  10. en cas de gap persistant après la fenêtre de grâce (current_sequence - previous_sequence > 1 après 200 ms), le client déclenche GET /seals/{seal_id}/status pour resynchroniser.
  11. En cas de coupure SSE, le client tente une reconnexion avec backoff exponentiel :
  12. tentative 1 : 1s,
  13. tentative 2 : 2s,
  14. tentative 3 : 4s.
  15. Après 3 échecs consécutifs SSE, le client bascule en polling toutes les 5 s.
  16. Badge Hors ligne :
  17. oui si perte réseau détectée (navigator.onLine=false ou équivalent RN),
  18. non si simple échec SSE sans perte réseau (bascule polling silencieuse).
  19. Re-tentative SSE depuis mode polling : à chaque cycle de polling (toutes les polling_interval_after_sse_failover secondes), le client tente en parallèle une connexion SSE. Si la connexion SSE réussit, le client revient en mode SSE et arrête le polling. Si elle échoue, le polling continue sans interruption.

5.3 Flux C — Gestion des dégradations

Le champ degradation_flag (optionnel dans les événements SSE, cf. §5.12) prend les valeurs suivantes :

Valeur degradation_flag Badge UI Comportement
absent ou none aucun Progression normale sans badge
delayed En retard Badge jaune affiché
critical Critique Badge rouge affiché
  • Échec timeout : état terminal FAILED_TIMEOUT (transition d’état, pas un degradation_flag) avec message de contact support.

Le client n’effectue aucun calcul local de seuil ; il applique les indicateurs reçus. Toute valeur de degradation_flag non listée ci-dessus est traitée comme none + trace telemetry.

5.4 Flux D — Mode expert

  • Le panneau expert est visible uniquement si la préférence utilisateur mode_expert=true.
  • Disponibilité conditionnelle des champs :
  • hash_document : dès RECEIVED.
  • tsa_token_ref : dès TSA_SEALED.
  • merkle_root, merkle_proof[] : dès ANCHOR_PENDING.
  • blockchain_tx_hash, proof_package_url : à SEALED.

5.5 Flux E — Notifications de clôture

  • À SEALED : notification succès + deep-link détail.
  • À FAILED_TIMEOUT : notification échec + deep-link détail.
  • Si push indisponible : fallback email (conformément à PD-80).

5.6 Modèle de données contractuel (formats)

Donnée Format/encodage Taille Caractères / casse Regex (si applicable) Si invalide
document_id UUID v4 (texte) 36 chars hex + -, case-insensitive ^[0-9a-fA-F-]{36}$ rejet requête (4xx)
seal_id UUID v4 (texte) 36 chars hex + -, case-insensitive ^[0-9a-fA-F-]{36}$ ignorer événement + erreur contrôlée UI
account_type enum n/a minor|standard|premium|enterprise (case-sensitive) n/a traiter comme non éligible
urgent_quota_remaining integer 0..9999 base 10 ^[0-9]+$ bouton disabled + erreur contrôlée
has_active_urgent_seal boolean n/a true|false n/a valeur par défaut false + telemetry
hash_document SHA-256 hex 64 chars [a-f0-9], case-sensitive ^[a-f0-9]{64}$ masquer champ expert + alerte non bloquante
tsa_token_ref string ASCII 1..256 chars ASCII alphanumérique + :_- ^[A-Za-z0-9:_-]{1,256}$ masquer champ expert
merkle_root hex 64 chars [a-f0-9], case-sensitive ^[a-f0-9]{64}$ masquer champ expert
merkle_proof[] array 0..128 éléments [a-f0-9] ^[a-f0-9]{64}$ par élément masquer preuve Merkle
blockchain_tx_hash hex préfixé 0x 66 chars [a-f0-9x], case-sensitive ^0x[a-f0-9]{64}$ masquer lien explorateur
proof_package_url URL HTTPS 1..2048 chars UTF-8 ^https://.+$ masquer action téléchargement
event_id entier positif séquentiel croissant (par seal_id) 1..19 chars digits ^[1-9][0-9]{0,18}$ ignorer événement
sequence_number entier positif strictement croissant (par seal_id) 1..19 chars digits ^[1-9][0-9]{0,18}$ resync immédiat via GET status
timestamp ISO-8601 UTC 20..35 chars RFC3339 n/a ignorer événement + telemetry

5.7 Machine d’états d’affichage et transitions inverses

États couverts : RECEIVED, QUEUED_PRIORITY, TSA_PENDING, TSA_SEALED, ANCHOR_PENDING, SEALED, FAILED_TIMEOUT.

  • RECEIVED
  • Autorisées : RECEIVED → QUEUED_PRIORITY, RECEIVED → FAILED_TIMEOUT
  • Interdites : RECEIVED → SEALED direct.
  • QUEUED_PRIORITY
  • Autorisées : QUEUED_PRIORITY → TSA_PENDING, QUEUED_PRIORITY → FAILED_TIMEOUT
  • Transition retour QUEUED_PRIORITY → RECEIVED : INTERDITE.
  • TSA_PENDING
  • Autorisées : TSA_PENDING → TSA_SEALED, TSA_PENDING → FAILED_TIMEOUT
  • Transition retour TSA_PENDING → QUEUED_PRIORITY : INTERDITE.
  • TSA_SEALED
  • Autorisées : TSA_SEALED → ANCHOR_PENDING, TSA_SEALED → FAILED_TIMEOUT
  • Transition retour TSA_SEALED → TSA_PENDING : INTERDITE.
  • ANCHOR_PENDING
  • Autorisées : ANCHOR_PENDING → SEALED, ANCHOR_PENDING → FAILED_TIMEOUT
  • Transition retour ANCHOR_PENDING → TSA_SEALED : INTERDITE.
  • SEALED
  • SEALED → * : INTERDITE (état terminal, résolution manuelle uniquement).
  • FAILED_TIMEOUT
  • FAILED_TIMEOUT → * : INTERDITE (état terminal, résolution manuelle uniquement).

Aucune transition retour applicable dans ce flux (modèle monotone vers terminal).

5.8 Paramètres numériques contractuels

Paramètre Défaut Min Max Unité Contexte Percentile Hors bornes
sse_reconnect_max_attempts_before_polling 3 1 10 tentatives client mobile n/a clamp
sse_reconnect_base_delay 1 0.5 5 secondes client mobile n/a clamp
sse_reconnect_backoff_factor 2 1 3 multiplicateur client mobile n/a clamp
sse_reconnect_max_cumulative_delay 30 5 120 secondes client mobile — plafond cumulé backoff avant failover n/a clamp
sequence_reorder_grace_window 200 50 1000 ms client mobile — délai avant détection gap n/a clamp
polling_interval_after_sse_failover 5 2 60 secondes client mobile n/a clamp
critical_delay_threshold 60 1 1440 minutes valeur backend consommée par UI n/a valeur invalide => badge indisponible + état normal conservateur
failed_timeout_threshold 120 1 2880 minutes valeur backend consommée par UI n/a événement invalide => erreur contrôlée
push_title_max_length 50 1 50 caractères iOS notification n/a troncature
push_body_max_length 100 1 100 caractères iOS notification n/a troncature
render_latency_after_valid_event 100 0 500 ms référence iPhone 12+ / iOS compatible Expo SDK 54 P95 > max => non-conformité perf

Backoff attendu avec paramètres par défaut : 1s, 2s, 4s puis failover polling. Si le délai cumulé de backoff dépasse sse_reconnect_max_cumulative_delay (défaut 30s) avant d'atteindre max_attempts, le client bascule immédiatement en polling sans attendre les tentatives restantes.

5.9 SLA temporels (checklist)

Paramètre Défaut Min Max Configurabilité Comportement à expiration
Seuil retard étape (badge En retard) fourni backend 1 min 1440 min configurable serveur badge retard actif
Seuil critique global 60 min 1 min 1440 min configurable serveur badge critique actif
Seuil échec timeout global 120 min 1 min 2880 min configurable serveur transition vers FAILED_TIMEOUT
TTL connexion SSE côté client (heartbeat) 30s (défaut PD-80, hypothèse H-284-02) 10s 120s configurable serveur absence de heartbeat au-delà du TTL → client déclenche séquence de reconnexion §5.2

5.10 Clauses structurelles obligatoires

  • Migration DDL : non applicable (aucune colonne backend modifiée par cette story).
  • Atomicité multi-composant DB+queue : non applicable côté client (dépend de PD-80).
  • Protection distribuée (locks/idempotence/réconciliation/rate-limit/clearing) : non applicable au module UI ; gérée contractuellement par PD-80 côté backend.
  • Contraintes inter-modules : aucune contrainte inter-module backend supplémentaire introduite.

5.11 Classification des artefacts

Artefact Sensible Nature Règle de stockage client Persistance autorisée
tsa_token_ref Oui Référence probatoire sensible iOS Keychain / Expo SecureStore Oui, chiffrée uniquement — purgé à la déconnexion et à la suppression de compte
Clé de session SSE (si utilisée) Oui Secret de session iOS Keychain / Expo SecureStore Oui, chiffrée uniquement — purgé à la fermeture de session SSE
Token d’authentification Oui Secret d’accès iOS Keychain / Expo SecureStore Oui, chiffrée uniquement — purgé à la déconnexion et à la suppression de compte
hash_document Non Empreinte publique mémoire app / cache standard Oui
merkle_root Non Artefact public mémoire app / cache standard Oui
blockchain_tx_hash Non Référence publique on-chain mémoire app / cache standard Oui

Règle explicite : le cache mémoire React (state/context) n’est pas une persistance durable.

Politique de purge des artefacts sensibles : tous les artefacts sensibles persistés en iOS Keychain / Expo SecureStore DOIVENT être purgés lors de la déconnexion utilisateur (logout) et lors de la suppression de compte (deleteAccount). Les clés de session SSE sont purgées à la fermeture de la session SSE. La restauration iCloud Keychain ne doit pas restaurer ces artefacts (attribut kSecAttrAccessible = kSecAttrAccessibleWhenUnlockedThisDeviceOnly ou équivalent Expo).

5.12 Contenu événement SSE par état

Champs communs à tous les états SSE :

  • event_id (séquentiel croissant),
  • sequence_number (entier croissant),
  • seal_id,
  • status,
  • timestamp,
  • degradation_flag? (optionnel),
  • document_id.
État (status) Champs obligatoires additionnels
RECEIVED hash_document
QUEUED_PRIORITY hash_document, position_in_queue
TSA_PENDING hash_document
TSA_SEALED hash_document, tsa_token_ref, tsa_timestamp
ANCHOR_PENDING hash_document, merkle_root, merkle_proof[]
SEALED hash_document, merkle_root, merkle_proof[], blockchain_tx_hash, proof_package_url
FAILED_TIMEOUT hash_document, failure_reason

5.13 Diagrammes

5.13.1 Machine d’états d’affichage (statechart)

Transitions autorisées conformes à §5.7. Les états terminaux SEALED et FAILED_TIMEOUT n’ont aucune transition sortante (INV-284-08). Toute transition retour est interdite — modèle monotone (INV-284-06, INV-284-07).

stateDiagram-v2
    [*] --> RECEIVED

    RECEIVED --> QUEUED_PRIORITY
    RECEIVED --> FAILED_TIMEOUT

    QUEUED_PRIORITY --> TSA_PENDING
    QUEUED_PRIORITY --> FAILED_TIMEOUT

    TSA_PENDING --> TSA_SEALED
    TSA_PENDING --> FAILED_TIMEOUT

    TSA_SEALED --> ANCHOR_PENDING
    TSA_SEALED --> FAILED_TIMEOUT

    ANCHOR_PENDING --> SEALED
    ANCHOR_PENDING --> FAILED_TIMEOUT

    SEALED --> [*]
    FAILED_TIMEOUT --> [*]

    note right of SEALED : Terminal — INV-284-08
    note right of FAILED_TIMEOUT : Terminal — INV-284-08

5.13.2 Flux de déclenchement et suivi temps réel (séquence)

Couvre le flux A (§5.1) et le flux B (§5.2). L’état initial est récupéré par GET canonique avant ouverture SSE (INV-284-06). Les artefacts sensibles (tsa_token_ref, clés SSE) transitent uniquement vers le stockage sécurisé (INV-284-10). Les artefacts publics (hash_document, merkle_root, blockchain_tx_hash) sont affichés en mode expert (INV-284-11).

sequenceDiagram
    participant U as Utilisateur
    participant App as ProbatioVault-app
    participant API as Backend PD-80
    participant SSE as Flux SSE
    participant KS as iOS Keychain

    U->>App: Appui bouton urgent
    Note over App: Vérifie INV-284-01/02/03<br/>account_type, quota, active_seal

    App->>API: POST /seals/urgent {document_id}
    API-->>App: 201 {seal_id}

    App->>API: GET /seals/{seal_id}/status
    API-->>App: État initial (RECEIVED)
    App->>App: Affiche carte progression

    App->>SSE: Ouvre connexion SSE (seal_id)

    loop Événements temps réel
        SSE-->>App: event {event_id, sequence_number, status, ...}
        App->>App: Déduplication event_id (cache FIFO N=100)
        App->>App: Ordonnancement sequence_number (grâce 200ms)
        alt Gap séquence détecté
            App->>API: GET /seals/{seal_id}/status (resync)
        end
        App->>App: Transition état (INV-284-06/07)
        alt Artefact sensible reçu (tsa_token_ref)
            App->>KS: Stockage sécurisé (INV-284-10)
        end
    end

    alt SEALED
        App->>U: Notification succès + deep-link (INV-284-12)
    else FAILED_TIMEOUT
        App->>U: Notification échec + deep-link (INV-284-12)
    end

5.13.3 Résilience SSE : reconnexion et fallback polling (séquence)

Couvre la stratégie de reprise §5.2 étapes 5-8. Le badge Hors ligne est conditionné à la perte réseau réelle (INV-284-09), pas à un simple échec SSE.

sequenceDiagram
    participant App as ProbatioVault-app
    participant SSE as Flux SSE
    participant API as Backend PD-80
    participant Net as Réseau (navigator.onLine)

    Note over App,SSE: Connexion SSE active
    SSE--xApp: Coupure SSE

    App->>Net: Vérifier connectivité
    alt Perte réseau (onLine=false)
        App->>App: Badge "Hors ligne" (INV-284-09)
        App->>App: Conserver dernier état connu
    else Réseau OK
        App->>SSE: Reconnexion tentative 1 (délai 1s)
        SSE--xApp: Échec
        App->>SSE: Reconnexion tentative 2 (délai 2s)
        SSE--xApp: Échec
        App->>SSE: Reconnexion tentative 3 (délai 4s)
        SSE--xApp: Échec

        Note over App: 3 échecs — failover polling<br/>Pas de badge Hors ligne (INV-284-09)

        loop Polling toutes les 5s
            App->>API: GET /seals/{seal_id}/status
            API-->>App: État courant
            App->>SSE: Tentative SSE parallèle
            alt SSE rétabli
                App->>App: Retour mode SSE, arrêt polling
            end
        end
    end

6. Cas d’erreur

  • Éligibilité refusée minor : bouton absent.
  • Quota nul (urgent_quota_remaining=0) : bouton visible mais disabled + tooltip Quota épuisé ce mois.
  • Urgent déjà actif (has_active_urgent_seal=true) : bouton visible mais disabled + tooltip Scellement urgent déjà en cours.
  • POST urgent rejeté (4xx/5xx) : message d’échec, aucun passage en progression active.
  • Événement SSE invalide (format, état inconnu, seal_id incohérent) : événement ignoré, erreur contrôlée, continuité UI.
  • Événement SSE dupliqué (event_id déjà vu) : ignoré silencieusement.
  • Réception SSE désordonnée : tri par sequence_number.
  • Gap de séquence (>1) : GET /seals/{id}/status de resynchronisation.
  • Perte réseau : badge Hors ligne, dernier état conservé, reprise auto.
  • Échec reconnection SSE sans perte réseau : pas de badge Hors ligne, passage en polling après 3 tentatives.
  • Timeout terminal : affichage état terminal + call-to-action support.
  • Donnée expert invalide : section concernée masquée sans casser la carte globale.
  • Push impossible : fallback email.

7. Critères d’acceptation (testables)

ID Critère Observable
CA-284-01 Utilisateur minor ne voit jamais le bouton urgent Aucune occurrence UI du bouton pour account_type=minor
CA-284-02 Utilisateur account_type != minor voit le bouton urgent Bouton présent même si non activable
CA-284-03 Quand quota épuisé (urgent_quota_remaining=0), bouton urgent disabled + tooltip quota État disabled + texte exact Quota épuisé ce mois
CA-284-04 Quand has_active_urgent_seal=true, bouton urgent disabled + tooltip état actif État disabled + texte exact Scellement urgent déjà en cours
CA-284-05 Après déclenchement réussi, le client fait GET /seals/{id}/status avant ouverture SSE Traces réseau ordonnées : POST -> GET status -> SSE
CA-284-06 La carte suit les états backend autorisés sans saut interdit Historique transitions conforme à §5.7
CA-284-07 Déduplication SSE active sur event_id (cache N=100) Un doublon n’entraîne aucun rerender ni régression d’état
CA-284-08 Ordonnancement SSE par sequence_number; gap détecté => resync GET status Log client de resynchronisation en cas de trou
CA-284-09 Après 3 échecs SSE, fallback polling à 5s est actif (1s/2s/4s avant failover) Journal client montre backoff puis polling
CA-284-10 Badge Hors ligne uniquement en perte réseau réelle Présent si offline, absent si simple panne SSE
CA-284-11 Badge dégradation reflète les flags serveur uniquement Aucune divergence entre flag backend et badge UI
CA-284-12 À SEALED, notification succès avec deep-link est envoyée Notification reçue, ouverture écran détail correct
CA-284-13 À FAILED_TIMEOUT, notification échec avec deep-link est envoyée Notification reçue, écran détail terminal
CA-284-14 Perf rendu événement→UI respecte P95 ≤ 100ms Mesure instrumentée conforme
CA-284-15 Mode expert masqué si préférence désactivée Panneau absent
CA-284-16 Champs expert apparaissent uniquement quand disponibles selon état Affichage progressif conforme §5.4 et §5.12
CA-284-17 Artefacts sensibles persistent uniquement via stockage sécurisé Audit stockage conforme §5.11

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

  1. Éligibilité standard avec quota disponible
  2. Given un utilisateur standard, urgent_quota_remaining > 0, has_active_urgent_seal=false
  3. When il ouvre le détail document
  4. Then le bouton urgent est visible, actif, et le quota est affiché

  5. Compte minor

  6. Given un utilisateur minor
  7. When il ouvre le détail document
  8. Then le bouton urgent est absent

  9. Quota épuisé

  10. Given un utilisateur standard avec urgent_quota_remaining=0
  11. When il ouvre le détail document
  12. Then le bouton urgent est visible mais disabled avec tooltip Quota épuisé ce mois

  13. Déjà en urgent

  14. Given un utilisateur standard avec has_active_urgent_seal=true
  15. When il ouvre le détail document
  16. Then le bouton urgent est visible mais disabled avec tooltip Scellement urgent déjà en cours

  17. Déclenchement urgent réussi

  18. Given bouton urgent actif
  19. When l’utilisateur déclenche l’action et la réponse POST est succès
  20. Then le client appelle GET /seals/{id}/status, initialise la carte avec cet état, puis démarre SSE

  21. Échec SSE sans perte réseau

  22. Given une carte active, réseau disponible
  23. When la connexion SSE échoue 3 fois (1s, 2s, 4s)
  24. Then le client bascule en polling 5s sans badge Hors ligne

  25. Perte réseau

  26. Given une carte active
  27. When le device passe offline (navigator.onLine=false ou équivalent RN)
  28. Then le badge Hors ligne s’affiche immédiatement et le dernier état connu est conservé

  29. Déduplication événement

  30. Given un événement event_id=42 déjà traité
  31. When le même event_id=42 est reçu à nouveau
  32. Then l’événement est ignoré silencieusement sans impact UI

  33. Désordre / gap de séquence

  34. Given événements SSE avec sequence_number 10 puis 12
  35. When le client détecte un gap de 2
  36. Then le client lance GET /seals/{id}/status pour resynchronisation

  37. Dégradation retard

  38. Given un scellement en cours
  39. When le backend envoie un flag retard
  40. Then l’UI affiche le badge En retard sans calcul local de seuil

  41. État terminal succès

  42. Given un scellement en ANCHOR_PENDING
  43. When un événement SEALED est reçu
  44. Then la carte passe en terminal succès et la notification succès est émise

  45. État terminal échec

  46. Given un scellement en cours
  47. When un événement FAILED_TIMEOUT est reçu
  48. Then la carte passe en terminal échec et la notification échec est émise

  49. Mode expert progressif

  50. Given mode_expert=true
  51. When les états progressent
  52. Then les champs expert apparaissent uniquement selon les jalons contractuels

8.1 Cas nominaux de non-régression (TC-NOM)

ID Objet Résultat attendu
TC-NOM-08 Échec SSE sans perte réseau Failover polling silencieux, pas de badge Hors ligne
TC-NOM-14 Perte réseau effective Badge Hors ligne immédiat + conservation dernier état

9. Hypothèses explicites

ID Hypothèse Impact si faux
H-284-01 PD-80 expose des événements SSE corrélables par seal_id et numérotés (event_id, sequence_number) Progression UI non fiable / resync fréquent
H-284-02 Les flags de dégradation sont fournis par le backend Impossible de respecter INV-284-05
H-284-03 Le backend fournit urgent_quota_remaining et has_active_urgent_seal dès le chargement du détail document (GET ou snapshot SSE initial) Impossible d’appliquer le contrat bouton
H-284-04 Le deep-linking mobile est disponible dans l’app cible Notifications sans redirection utile
H-284-05 Le backend expose les artefacts expert de manière progressive Mode expert partiellement vide
H-284-06 Le fallback email est assuré côté backend Perte d’alerte utilisateur sans push

10. Points à clarifier (restants)

ID Point Donnée manquante / décision requise
Q-284-01 Nom et identifiant exacts de l’épic Valeur épique non fournie dans le besoin
Q-284-02 Contrat exact payload POST /seals/urgent et réponses d’erreur métier détaillées Schéma JSON versionné + catalogue de codes
Q-284-03 Valeurs SLA étape par étape (target/max) côté PD-80 Tableau exhaustif des seuils
Q-284-04 Politique iOS hors foreground (notification locale vs push distante) Comportement attendu en arrière-plan
Q-284-05 Quota max par plan (standard/premium/enterprise) Valeurs numériques contractuelles par segment

Références

  • Epic : à compléter
  • JIRA : PD-284
  • Repos concernés : ProbatioVault-app (React Native + Expo SDK 54 + TypeScript), ProbatioVault-backend (dépendance PD-80)
  • Documents associés : PD-80 (machine d’états/SLA/flags), expression de besoin PD-284, learnings PD-81/PD-264/PD-80.