Aller au contenu

PD-284 — Agent Developer — seal-detail-screen (C14)

Module

seal-detail-screen — Écran détail scellement intégrant C8 (UrgentSealButton), C9 (SealProgressCard), C10 (SealExpertPanel).

Fichier produit

src/screens/vault/SealDetailScreen.tsx

Résumé

Écran React Native composant l'ensemble des modules seal en une vue cohérente. Il orchestre le cycle de vie complet d'un scellement urgent : affichage du bouton, gestion de l'orchestrateur SSE/polling, affichage de la progression, panneau expert, toasts d'erreur contrôlée, et cleanup à la destruction.

Architecture

SealDetailScreen
├── Document header (nom + ID)
├── UrgentSealButton (C8) — visible si pas de seal actif
├── Loading indicator — pendant POST/GET sequence
├── Error message — si orchestration échouée
├── SealProgressCard (C9) — visible si seal actif
├── SealExpertPanel (C10) — visible si seal actif + mode_expert
└── Toast overlay — erreur contrôlée (5s auto-dismiss)

Invariants couverts

Invariant Mécanisme Observable
INV-284-01 / INV-284-02 Délégué à C8 (UrgentSealButton) via props Bouton visible/absent selon account_type
INV-284-05 Aucun calcul local de seuil — tout délégué aux composants enfants Pas de Date.now() ni comparaison de durée
INV-284-09 NetInfo listener → isOffline state → prop SealProgressCard.isOffline Badge "Hors ligne" uniquement si isConnected === false
INV-284-10 Purge purgeSealArtifacts(activeSealId) au unmount via useEffect cleanup Aucun artefact sensible résiduel
INV-284-12 sendTerminalNotification callback → C11 Deep-link inclus dans notification terminale
INV-284-13 Aucun endpoint hors contrat (POST /seals/urgent, GET /seals/{id}/status, SSE) Front-only, pas de nouveau contrat backend

Critères d'acceptation couverts

CA Mécanisme
CA-284-05 Séquence POST→GET→SSE stricte via createSealOrchestrator (C7)
CA-284-14 Sélecteurs Zustand granulaires (un par champ) — pas de re-render cascadant
CA-284-15 modeExpert prop passée au SealExpertPanel — panneau absent si false
CA-284-17 Artefacts sensibles purgés via C12 au démontage écran

Cycle de vie (useEffect)

  1. Mount : Crée l'orchestrateur (C7) + souscrit NetInfo + charge le détail document
  2. Active : Orchestrateur gère POST→GET→SSE automatiquement après clic bouton
  3. Unmount : orchestratorRef.current.dispose() (arrête SSE/polling) + purgeSealArtifacts (C12) + useSealStore.reset()

Gestion des erreurs

Situation Comportement
POST /seals/urgent échoue Toast 5s via orchestrateur, pas de carte
GET status échoue post-POST (R-02) Toast 5s, init RECEIVED, SSE démarre normalement
Événement SSE invalide Délégué à C4/C7, toast via callback
Perte réseau Badge "Hors ligne" via NetInfo + conservation dernier état
Auth token absent Exception propagée, toast d'erreur

Stubs

  • STUB: PD-80 — Le chargement du détail document (loadDocumentDetail) utilise des données stub. En production, ce sera un appel GET /documents/{documentId} retournant account_type, urgent_quota_remaining, has_active_urgent_seal.

Tests associés

Test ID Objet Niveau
TC-NR-05 Cleanup SSE/polling au démontage Integration
TC-NR-06 Purge artefacts sensibles au démontage Integration
TC-NOM-01 minor ne voit pas le bouton (via C8) Unit
TC-NOM-04 POST→GET→SSE sequence (via C7) Integration
TC-NOM-14 Badge "Hors ligne" via NetInfo Unit
TC-INV-09 Aucun artefact sensible résiduel post-unmount Sec

Décisions architecturales

architectural_decisions:
  - decision: "Toast implémenté en state local plutôt qu'en lib tierce"
    rationale: "Évite une dépendance externe pour un composant simple (auto-dismiss 5s). Le contrat §3 impose un comportement précis (non bloquant, auto-dismiss) plus facile à garantir en local."
    alternatives_considered: ["react-native-toast-message", "react-native-snackbar"]
    trade_offs: "Pas de queue de toasts (le dernier remplace le précédent). Acceptable car les erreurs contrôlées sont rares et espacées."
  - decision: "NetInfo listener dans l'écran plutôt que dans un hook partagé"
    rationale: "Le badge offline est spécifique au flux seal (INV-284-09). Un hook partagé imposerait un re-render à toute l'app sur changement réseau."
    alternatives_considered: ["useNetworkStatus global hook", "NetInfo dans SealProgressCard directement"]
    trade_offs: "Duplication si d'autres écrans ont besoin du même signal. Acceptable pour PD-284 (single screen)."

Matrice de couverture

TC-NR-05 → src/screens/vault/__tests__/SealDetailScreen.test.tsx
TC-NR-06 → src/screens/vault/__tests__/SealDetailScreen.test.tsx
TC-NOM-14 → src/screens/vault/__tests__/SealDetailScreen.test.tsx
TC-INV-09 → src/screens/vault/__tests__/SealDetailScreen.test.tsx