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 urgentconditionné 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 expertconditionnel 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_typeetseal_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¶
- L’utilisateur ouvre le détail document.
- Le client évalue les conditions d’affichage du bouton urgent selon données serveur (
account_type,urgent_quota_remaining,has_active_urgent_seal). - Si activable, l’action envoie
POST /seals/urgentavec payload{ document_id }(contrat exact — payload de réponse, codes d’erreur métier — défini par PD-80, hypothèse H-284-01). - Le client affiche un feedback immédiat (chargement) et reçoit
seal_id. - Nouvelle étape obligatoire : le client appelle
GET /seals/{seal_id}/statuspour récupérer l’état initial canonique. - Le client affiche la carte de progression associée au
seal_idavec l’état initial issu du GET. - 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)¶
- Le client ouvre un flux SSE sur le scellement.
- À chaque événement valide, l’UI met à jour :
- étape visuelle (Capture, TSA, Merkle, Blockchain, Scellé),
- badge de dégradation (si fourni),
- disponibilité des détails expert.
- Le client maintient un cache local FIFO des
N=100derniersevent_id(politique d'éviction : lesevent_idles plus anciens sont éjectés en premier — FIFO, pas LRU). - si
event_iddéjà vu : événement ignoré silencieusement (déduplication, pas de toast, trace telemetry uniquement en mode debug). - Chaque événement contient aussi
sequence_number(entier croissant). - 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_numbermanquant(s) avant réordonnancement et rendu ; - en cas de gap persistant après la fenêtre de grâce (
current_sequence - previous_sequence > 1après 200 ms), le client déclencheGET /seals/{seal_id}/statuspour resynchroniser. - En cas de coupure SSE, le client tente une reconnexion avec backoff exponentiel :
- tentative 1 : 1s,
- tentative 2 : 2s,
- tentative 3 : 4s.
- Après 3 échecs consécutifs SSE, le client bascule en polling toutes les
5 s. - Badge
Hors ligne: - oui si perte réseau détectée (
navigator.onLine=falseou équivalent RN), - non si simple échec SSE sans perte réseau (bascule polling silencieuse).
- Re-tentative SSE depuis mode polling : à chaque cycle de polling (toutes les
polling_interval_after_sse_failoversecondes), 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 undegradation_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èsRECEIVED.tsa_token_ref: dèsTSA_SEALED.merkle_root,merkle_proof[]: dèsANCHOR_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 → SEALEDdirect. 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. SEALEDSEALED → * : INTERDITE (état terminal, résolution manuelle uniquement).FAILED_TIMEOUTFAILED_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 maisdisabled+ tooltipQuota épuisé ce mois. - Urgent déjà actif (
has_active_urgent_seal=true) : bouton visible maisdisabled+ tooltipScellement urgent déjà en cours. POSTurgent rejeté (4xx/5xx) : message d’échec, aucun passage en progression active.- Événement SSE invalide (format, état inconnu,
seal_idincohérent) : événement ignoré, erreur contrôlée, continuité UI. - Événement SSE dupliqué (
event_iddéjà vu) : ignoré silencieusement. - Réception SSE désordonnée : tri par
sequence_number. - Gap de séquence (>1) :
GET /seals/{id}/statusde 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)¶
- Éligibilité standard avec quota disponible
- Given un utilisateur
standard,urgent_quota_remaining > 0,has_active_urgent_seal=false - When il ouvre le détail document
-
Then le bouton urgent est visible, actif, et le quota est affiché
-
Compte minor
- Given un utilisateur
minor - When il ouvre le détail document
-
Then le bouton urgent est absent
-
Quota épuisé
- Given un utilisateur
standardavecurgent_quota_remaining=0 - When il ouvre le détail document
-
Then le bouton urgent est visible mais disabled avec tooltip
Quota épuisé ce mois -
Déjà en urgent
- Given un utilisateur
standardavechas_active_urgent_seal=true - When il ouvre le détail document
-
Then le bouton urgent est visible mais disabled avec tooltip
Scellement urgent déjà en cours -
Déclenchement urgent réussi
- Given bouton urgent actif
- When l’utilisateur déclenche l’action et la réponse POST est succès
-
Then le client appelle
GET /seals/{id}/status, initialise la carte avec cet état, puis démarre SSE -
Échec SSE sans perte réseau
- Given une carte active, réseau disponible
- When la connexion SSE échoue 3 fois (1s, 2s, 4s)
-
Then le client bascule en polling 5s sans badge
Hors ligne -
Perte réseau
- Given une carte active
- When le device passe offline (
navigator.onLine=falseou équivalent RN) -
Then le badge
Hors lignes’affiche immédiatement et le dernier état connu est conservé -
Déduplication événement
- Given un événement
event_id=42déjà traité - When le même
event_id=42est reçu à nouveau -
Then l’événement est ignoré silencieusement sans impact UI
-
Désordre / gap de séquence
- Given événements SSE avec
sequence_number10 puis 12 - When le client détecte un gap de 2
-
Then le client lance
GET /seals/{id}/statuspour resynchronisation -
Dégradation retard
- Given un scellement en cours
- When le backend envoie un flag retard
-
Then l’UI affiche le badge
En retardsans calcul local de seuil -
État terminal succès
- Given un scellement en
ANCHOR_PENDING - When un événement
SEALEDest reçu -
Then la carte passe en terminal succès et la notification succès est émise
-
État terminal échec
- Given un scellement en cours
- When un événement
FAILED_TIMEOUTest reçu -
Then la carte passe en terminal échec et la notification échec est émise
-
Mode expert progressif
- Given
mode_expert=true - When les états progressent
- 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.