Aller au contenu

PD-248 — Retour d'Expérience (REX)

1. Résumé de la story

Champ Valeur
ID PD-248
Titre [INV-242-10] Implémenter protection screenshot native iOS
Projet ProbatioVault-app
Domaine crypto
Durée totale ~8 heures
Complexité Medium

2. Contexte et objectif

Cette story implémente la protection anti-screenshot native iOS pour les écrans sensibles de l'application ProbatioVault (phrase de récupération BIP-39, codes TOTP, clés API). L'objectif est d'empêcher la capture d'écran pour protéger les données cryptographiques sensibles conformément à l'invariant INV-242-10 de PD-242.

3. Résultats

Livrables produits

Livrable Fichier Couverture tests
Hook useScreenshotProtection src/hooks/useScreenshotProtection.ts 100%
Service screenshotProtectionLogger src/services/screenshotProtection.ts 100%
Intégration écrans recovery src/screens/recovery/*.tsx >80%
Tests unitaires src/__tests__/hooks/useScreenshotProtection.*.ts 100%
Tests E2E src/__tests__/e2e/screenshot-protection.e2e.ts N/A (OCR)

Métriques finales

Métrique Valeur Seuil
new_coverage >80% ≥80% ✅
new_violations 0 0 ✅
Tests passants 1452 -
Pipeline CI SUCCESS

4. Itérations de gates

Gate Itération Verdict Score Écarts majeurs
3 1 GO 8.75/10 Aucun
5 1 RESERVE 7.875/10 REC-248-01: Robustesse OCR
8 1 RESERVE 7.75/10 DIV-248-02: Intégration écrans non testée

Analyse des écarts

Gate 5 (Plan): - REC-248-01: Robustesse OCR pour tests E2E insuffisamment documentée - Action: Ajout de retry et seuil de confiance dans les tests E2E

Gate 8 (Closure): - DIV-248-02: Tests d'intégration des écrans recovery incomplets - Action: Ajout de RecoveryRestoreScreen.integration.test.tsx avec couverture >90%

5. Écarts Sonar résolus

Règle Description Fichiers impactés Correction
S6479 Do not use Array index in keys MnemonicDisplay, MnemonicInput Utilisation de clés statiques
S7723 Use new Array() instead of Array() MnemonicInput Syntaxe corrigée
S1874 SafeAreaView deprecated RecoveryScreens Import depuis react-native-safe-area-context

6. Patterns techniques identifiés

Pattern 1: Protection screenshot avec useFocusEffect

// Pattern efficace pour activer/désactiver sur navigation
useFocusEffect(
  useCallback(() => {
    if (Platform.OS !== "ios") {
      screenshotProtectionLogger.logIncompatibleEnvironment();
      return;
    }

    preventScreenCaptureAsync().catch((e) =>
      screenshotProtectionLogger.logActivationError("SCR-248-01", e)
    );

    return () => {
      allowScreenCaptureAsync().catch((e) =>
        screenshotProtectionLogger.logActivationError("SCR-248-01", e)
      );
    };
  }, [])
);

Pattern 2: Tests d'intégration pour callbacks React

// Pour couvrir les callbacks non-mockés, utiliser des tests d'intégration
// qui triggent les vrais callbacks via les composants enfants
describe("handlePhraseComplete - success path", () => {
  it("should call recovery service functions", async () => {
    render(<RecoveryRestoreScreen />);
    const inputs = screen.getAllByPlaceholderText("word");
    for (let i = 0; i < 24; i++) {
      fireEvent.changeText(inputs[i], validMnemonicWords[i]);
    }
    await act(async () => {
      fireEvent.press(screen.getByText("Verify"));
    });
    await waitFor(() => {
      expect(mockDeriveRecoveryKey).toHaveBeenCalled();
    });
  });
});

7. Points positifs

  1. Implémentation simple et efficace: Le hook useScreenshotProtection est une solution élégante et réutilisable
  2. Logging technique silencieux: Respect de l'invariant INV-248-04 (pas d'alerte utilisateur)
  3. Compatibilité Expo SDK 54: Utilisation de expo-screen-capture sans code natif custom
  4. Couverture exhaustive: 100% sur le code core, tests multi-plateformes

8. Points d'amélioration

  1. Tests d'intégration dès le départ: Les tests unitaires avec mocks ne couvrent pas les callbacks React. Prévoir des tests d'intégration dès la phase de plan.

  2. Sonar new_coverage difficile à atteindre: La métrique new_coverage calcule uniquement sur les fichiers modifiés. Toucher un fichier existant avec faible couverture impacte la moyenne.

  3. E2E OCR: Les tests E2E avec OCR sont complexes à mettre en place et nécessitent un environnement spécifique (Tesseract, simulateur).

9. Leçons apprises

Learning 1: Tests d'intégration pour callbacks React

Tags: #testing #react #coverage Description: Les tests unitaires avec mocks des composants enfants ne couvrent pas les callbacks passés en props. Pour atteindre >80% de couverture sur les écrans React, il faut des tests d'intégration qui utilisent les vrais composants enfants.

Learning 2: Sonar S6479 et clés de liste

Tags: #sonar #react #lint Description: Sonar détecte key={index} et key={\prefix-${index}`}` comme violations de S6479. Solutions: utiliser des IDs uniques, ou un tableau constant de clés statiques.

Learning 3: SafeAreaView deprecated

Tags: #react-native #migration Description: SafeAreaView de react-native est deprecated. Utiliser SafeAreaView de react-native-safe-area-context à la place.

10. Propositions d'amélioration du process

10.1 Template de tests d'intégration

Fichier: templates/prompts/6b-agent-qa-integration.md Priorité: haute Description: Ajouter une section explicite demandant des tests d'intégration pour les écrans React, en plus des tests unitaires.

10.2 Checklist pré-merge couverture

Fichier: CLAUDE.md Priorité: moyenne Description: Ajouter une vérification locale de la couverture avant le merge vers dev pour éviter les échecs Sonar.

10.3 Exclusions Sonar pour screens UI

Fichier: sonar-project.properties Priorité: basse Description: Considérer l'exclusion partielle des screens UI purement déclaratifs de la couverture (discussion avec l'équipe).

11. Conclusion

PD-248 a été implémenté avec succès. La protection screenshot est opérationnelle sur iOS pour tous les écrans sensibles. Les gates ont permis d'identifier des points d'amélioration (robustesse OCR, tests d'intégration) qui ont été corrigés avant le merge.

Recommandation: Planifier un test manuel sur device physique avec build EAS production pour valider le comportement réel de la protection screenshot.


Document généré le 2026-02-20 Co-Authored-By: Claude Opus 4.5 noreply@anthropic.com