PD-174 — Retour d'expérience¶
📚 Navigation User Story
| Document | | | ---------- | -- | | 📋 [Spécification](PD-174-specification.md) | | | 🛠️ [Plan d'implémentation](PD-174-plan.md) | | | ✅ [Critères d'acceptation](PD-174-acceptability.md) | | | 📝 **Retour d'expérience** | *(ce document)* | [← Retour à mobile-ios](../PD-195-epic.md) · [↑ Index User Story](index.md)1. Résumé exécutif¶
La User Story PD-174 visait à implémenter un mécanisme de verrouillage automatique configurable avec effacement du cache sensible lors du passage en arrière-plan ou après inactivité. L'implémentation fournit le timer d'inactivité, la détection background et l'effacement partiel du cache, mais présente 2 écarts MAJEURS : pas de LockScreen/blocage navigation, et effacement cache incomplet (les données déchiffrées du vault ne sont pas effacées). Verdict : ACCEPTÉ AVEC RÉSERVES.
2. Points fluides¶
- useAutoLock hook : architecture propre avec timer, refs, callbacks et cleanup
- AppState handling : détection foreground/background fonctionnelle via React Native AppState
- useSecurityStore : store Zustand bien structuré avec état
isLocked,autoLockEnabled,autoLockTimeout - useUserActivity : hook dédié pour détecter touches, scrolls, keypresses
- Callbacks extensibles :
onBeforeLocketonAfterLockpermettent d'injecter logique métier - Tests exhaustifs : 400+ lignes de tests couvrant tous les scénarios (timer, background, disabled)
- Protection double-lock : ref
isLockingRefévite les verrouillages concurrents - Timer cleanup :
clearTimers()dans useEffect cleanup évite memory leaks - Options disabled : permet de désactiver l'auto-lock sur écrans onboarding/login
3. Points difficiles¶
| Difficulté | Contexte |
|---|---|
| Bug perte données vault | Vider le vault store via setState({}) déclenchait le persist middleware qui écrasait les données persistées avec des tableaux vides |
| Intégration navigation | Le plan prévoyait un LockScreen modal + blocage navigation, non implémenté dans cette US |
| Délimitation périmètre | La spec mentionne "redirection vers écran de déverrouillage existant" mais cet écran n'existe pas encore |
| Effacement sélectif | Distinguer données sensibles (password) des données fonctionnelles (vault) requiert analyse fine |
4. Hypothèses révélées tardivement¶
| Hypothèse initiale | Réalité découverte |
|---|---|
| L'écran de déverrouillage existe déjà | FAUX — Pas de LockScreen.tsx dans le codebase, dépendance non satisfaite |
| Vider le vault store est safe | FAUX — Le middleware persist écrase les données persistées, causant perte de dossiers |
| Les données vault sont sensibles | PARTIELLEMENT FAUX — Déjà chiffrées en persistence, le password est la vraie donnée sensible |
| Le blocage navigation est simple | FAUX — Nécessite modal overlay ou navigation guard, complexité sous-estimée |
5. Invariants complexes à implémenter¶
| Invariant | Complexité |
|---|---|
| Timer reset sur activité | Coordination entre useUserActivity et useAutoLock via callback |
| Pas de double-lock | Ref isLockingRef nécessaire pour éviter race conditions |
| Lock immédiat sur background | Doit être synchrone, pas d'await possible dans AppState callback |
| Préserver données vault | Ne PAS vider le store pour éviter écrasement persistence |
| Effacement password mémoire | Manipulation directe du state via useAuthStore.setState() |
6. Dette technique¶
| Dette | Impact | Priorité |
|---|---|---|
| Pas de LockScreen | Verrouillage non effectif, juste état isLocked | HAUTE |
| Pas de blocage navigation | Écrans protégés restent accessibles | HAUTE |
| Vault non vidé au lock | Données déchiffrées restent en mémoire | MOYENNE |
| rehydrateVaultAfterUnlock vide | Fonction placeholder, ne fait rien d'utile | BASSE |
| Délais différents plan vs spec | Plan: ⅕/15/30min, Spec: 30s/½/5/10min | BASSE |
7. Risques résiduels¶
| Risque | Probabilité | Impact | Mitigation suggérée |
|---|---|---|---|
| Accès écrans sans déverrouillage | Élevée | ÉLEVÉ | Implémenter LockScreen + navigation guard |
| Données déchiffrées en mémoire | Élevée | MOYEN | Accepté comme compromis vs bug perte données |
| Timer non précis en background | Moyenne | FAIBLE | iOS limite les timers, comportement attendu |
| Race condition lock/unlock | Faible | MOYEN | Protection par ref déjà en place |
| Password reste en mémoire si erreur | Faible | MOYEN | try/finally autour du setState |
8. Améliorations processus¶
| Amélioration | Bénéfice attendu |
|---|---|
| Vérifier existence dépendances | LockScreen "existant" n'existait pas, créer ou lier à une US |
| Tester persist middleware | Le bug perte données aurait été détecté plus tôt |
| Séparer US verrouillage/navigation | Clarifier périmètre : état vs blocage effectif |
| Documenter compromis sécurité | Décision vault non vidé mérite documentation explicite |
| Aligner délais plan/spec | Éviter confusion sur les valeurs attendues |
9. Enseignements clés¶
-
Le persist middleware est piégeux — Appeler
setState({})sur un store Zustand persisté écrase les données en AsyncStorage. Toujours tester le comportement avec les middlewares actifs. -
Une dépendance "existante" doit être vérifiée — La spec suppose un "écran de déverrouillage existant" qui n'existe pas. Vérifier les hypothèses de dépendance avant de commencer l'implémentation.
-
L'effacement cache est un compromis — Vider les données déchiffrées causerait leur perte permanente (bug persist). Le compromis documenté est d'effacer seulement le password (vraie donnée sensible).
-
L'état
isLockedne suffit pas — Un boolean dans le store ne bloque pas l'accès aux écrans. Une vraie protection nécessite un modal overlay ou un navigation guard. -
Les délais de la spec et du plan divergent — Spec: 30s, 1min, 2min, 5min, 10min. Plan: 1min, 5min, 15min, 30min, jamais. Cette incohérence devrait être résolue avant implémentation.