Aller au contenu

PD-284 — Agent Developer : seal-urgent-button (C8)

1. Module

Attribut Valeur
Agent agent-developer
Module seal-urgent-button (C8)
Story PD-284
Projet app (ProbatioVault-app)

2. Fichiers produits

Fichier Action Justification
src/components/seal/UrgentSealButton.tsx Cree Composant bouton de declenchement scellement urgent

3. Couverture des invariants

Invariant Mecanisme implemente Fichier:ligne
INV-284-01 computeEligibility() : visible si accountType !== "minor", enabled si quota > 0 UrgentSealButton.tsx:55-70
INV-284-02 Retour null (aucun noeud UI) si accountType === "minor" UrgentSealButton.tsx:57-59, UrgentSealButton.tsx:105-107
INV-284-04 Tooltips contractuels exacts importes depuis types/seal.ts (TOOLTIP_QUOTA_EXHAUSTED, TOOLTIP_URGENT_ACTIVE) UrgentSealButton.tsx:61,66

4. Couverture des tests contractuels

Test ID Couvert Observable
TC-NOM-01 Oui accountType="minor" → composant retourne null, aucun noeud rendu
TC-NOM-02 Oui accountType="standard", quota > 0 → bouton visible et actif, quota affiche strictement egal au payload serveur
TC-NOM-03 Oui quota = 0 → bouton desactive + raison explicite "Quota epuise ce mois"
TC-ERR-05 Oui accountType hors enum → traite comme minor (non eligible, aucun bouton)

5. Decisions architecturales

D1 — Eligibilite en fonction pure

  • Decision : computeEligibility() est une fonction pure extraite hors du composant
  • Rationale : Testable en isolation, pas d'effet de bord, memoisation triviale via useMemo
  • Alternatives : Inline dans le JSX (rejete : non testable), hook custom (rejete : over-engineering pour logique pure)
  • Trade-offs : Une allocation objet par render (negligeable)

D2 — Selectors granulaires Zustand (CA-284-14)

  • Decision : selectIsLoading et selectActiveSealId importes depuis useSealStore
  • Rationale : CA-284-14 exige un selecteur par champ pour eviter les re-renders en cascade
  • Alternatives : Destructuring du store entier (rejete : viole CA-284-14)
  • Trade-offs : Deux appels useSealStore() au lieu d'un, mais chacun ne re-rend que sur son champ

D3 — TouchableOpacity + ActivityIndicator pendant le chargement

  • Decision : TouchableOpacity au lieu de Pressable, avec ActivityIndicator pendant isLoading
  • Rationale : Feedback visuel immediat conforme TC-NOM-04 ("feedback immediat de chargement visible")
  • Alternatives : Pressable avec style conditionnel (rejete : pas de feedback de chargement natif)
  • Trade-offs : Dependance TouchableOpacity (standard React Native, pas de lib externe)

D4 — Props typees avec branded types et AccountType enum

  • Decision : accountType: AccountType au lieu de string, documentId: DocumentId au lieu de string
  • Rationale : Branded types de types/seal.ts empechent inversion accidentelle des IDs (cf. regle "Refined/branded types obligatoires")
  • Alternatives : string brut (rejete : viole la convention codebase)
  • Trade-offs : Le parent doit cast explicitement via asDocumentId()

6. Hypotheses et points ouverts

ID Hypothese Impact si invalide
H1 Le parent (ecran detail document) fournit accountType, urgentQuotaRemaining et hasActiveUrgentSeal depuis le payload serveur Le bouton ne peut pas evaluer l'eligibilite sans appel API interne
H2 Le callback onTriggerUrgentSeal est connecte au SealOrchestrator.triggerUrgentSeal (C7) par le parent Le debounce SEC-02 ne serait pas applique si connecte a un autre handler
H3 has_active_urgent_seal du payload backend est optionnel avec default false (HT-09 du plan) Le bouton est actif par defaut — acceptable car PD-80 POST est idempotent

7. Fichiers hors perimetre identifies

Aucun fichier hors perimetre n'a ete modifie. Interactions identifiees :

  • src/types/seal.ts : lecture seule (types, tooltips) — deja existant
  • src/store/useSealStore.ts : lecture seule (selecteurs) — deja existant
  • src/seal/orchestrator.ts : le parent doit connecter onTriggerUrgentSeal au C7

8. Matrice de couverture test → fichier

TC-NOM-01 → src/components/seal/UrgentSealButton.tsx (computeEligibility: accountType="minor" → visible=false → null)
TC-NOM-02 → src/components/seal/UrgentSealButton.tsx (computeEligibility: quota > 0 → visible+enabled, quota affiché)
TC-NOM-03 → src/components/seal/UrgentSealButton.tsx (computeEligibility: quota=0 → disabled + TOOLTIP_QUOTA_EXHAUSTED)
TC-ERR-05 → src/components/seal/UrgentSealButton.tsx (isValidAccountType: hors enum → traité comme minor)

9. Conformite code contract

Le composant respecte les contraintes suivantes du plan d'implementation :

  • SEC-02 : Le debounce 2s est gere en amont par le C7 orchestrator (pas duplique ici). Le composant desactive le bouton via isLoading pendant l'orchestration.
  • CA-284-14 : Selecteurs granulaires Zustand (un par champ) pour eviter re-renders cascades.
  • INV-284-10 : Aucun artefact sensible n'est manipule par ce composant. Les tooltips sont des constantes publiques.
  • TC-NOM-04 : Le ActivityIndicator fournit le feedback immediat de chargement exige par le test.