Aller au contenu

PD-298 — Expression de Besoin

Story : [APP] UI de création et gestion des liens de partage sans compte Domaine : sharing (app) Date : 2026-04-22 Statut : BESOIN Dépendance : PD-287 (backend, DONE)


1. Contexte

PD-287 a livré le backend complet de partage de preuve sans compte : création de lien PRE, activation par OTP email, identité éphémère, révocation, expiration, journal d'accès append-only, machine à états 5 états (PENDING_ACTIVATION, ACTIVE, OTP_BLOCKED, REVOKED, EXPIRED), quotas et protections anti-abus.

L'API backend est opérationnelle :

Endpoint Méthode Rôle
/shares POST Créer un lien de partage
/shares GET Lister les liens du propriétaire
/shares/:id GET Détail d'un lien
/shares/:id/revoke POST Révoquer un lien
/shares/:id/events GET Journal des accès d'un lien

Il manque l'UI mobile. Le propriétaire de la preuve n'a aujourd'hui aucun moyen, depuis l'application React Native, de créer un lien, de suivre ses partages actifs, de révoquer un lien ou de consulter qui a accédé à sa preuve partagée.

Cette story implémente les écrans côté propriétaire dans ProbatioVault-app. Elle ne touche pas le portail destinataire (hors périmètre — le destinataire accède via navigateur web, pas via l'app).


2. Objectifs principaux

OBJ-1 — Créer un lien de partage depuis une preuve

Le propriétaire, depuis l'écran de détail d'une preuve, peut ouvrir un formulaire de création de lien. Il saisit l'email du destinataire, choisit un TTL (presets ou custom), configure optionnellement un plafond de consultations et l'activation des notifications. La création appelle POST /shares et affiche le résultat (lien généré, statut PENDING_ACTIVATION).

OBJ-2 — Visualiser et gérer les liens depuis la preuve

Depuis la fiche d'une preuve, le propriétaire voit la liste des liens de partage associés avec leur état courant (badge coloré). Il peut accéder au détail de chaque lien et déclencher une révocation.

OBJ-3 — Écran global "Mes partages"

Un écran transverse, accessible depuis la navigation principale, liste tous les liens de partage du compte, triés par date de création décroissante, filtrable par état. Cet écran agrège les partages de toutes les preuves.

OBJ-4 — Révoquer avec avertissement explicite

La révocation affiche un avertissement UX conforme à ARB-7 PD-287 : "Révoquer ce lien empêchera tout accès futur via ProbatioVault. Les consultations ou copies déjà réalisées ne peuvent pas être annulées." Confirmation requise avant appel POST /shares/:id/revoke.

OBJ-5 — Consulter le journal des accès

Pour chaque lien, le propriétaire consulte le journal via GET /shares/:id/events. Affichage : date/heure, type d'événement (création, activation, consultation, export, échec OTP, révocation), email destinataire, IP partiellement masquée, type de device (mobile/desktop).

OBJ-6 — Afficher l'avertissement absence de DRM

Conforme à ARB-8 PD-287 : à la première création de lien, afficher un avertissement sur l'absence de DRM. L'avertissement est mémorisé localement (AsyncStorage) et peut être consulté à nouveau depuis les paramètres ou le formulaire de création.

OBJ-7 — Afficher l'information RGPD avant activation

Conforme à CA-287-27 : dans le formulaire de création, afficher un encart RGPD visible avant le bouton de soumission, informant le propriétaire que l'email du destinataire sera collecté, la base légale (preuve + intérêt légitime), et la durée de rétention. Note : il s'agit d'un affichage UI côté client, pas d'un pattern outbox — l'envoi de l'email OTP est géré côté backend (PD-287).


3. Non-objectifs (exclusions explicites)

NOBJ-1 — Pas de portail destinataire dans l'app

Le destinataire accède à la preuve partagée via navigateur web. L'app native ne propose aucun écran destinataire. Cette story est strictement côté propriétaire.

NOBJ-2 — Pas de modification backend

L'API PD-287 est livrée et figée. Aucun endpoint ne doit être ajouté ou modifié. Si un besoin de champ additionnel est découvert, il fera l'objet d'une story séparée.

NOBJ-3 — Pas de push notification

Les notifications au propriétaire (si activées) sont gérées côté backend. L'intégration push dans l'app est hors périmètre de cette story (couverte par PD-105 et son infrastructure existante).

NOBJ-4 — Pas de deep linking vers un partage

L'accès direct à un partage via deep link (ex: depuis une notification) est hors périmètre MVP.

NOBJ-5 — Pas de mode hors-ligne

La gestion des partages requiert une connexion réseau. Pas de cache offline, pas de file d'attente de création.

NOBJ-6 — Pas de multi-sélection de preuves

Un lien = une preuve. Le partage groupé est hors périmètre (aligné PD-287 Q-20).


4. Contraintes

4.1 Contraintes techniques

CTR-TECH-1 — React Native / Expo L'app ProbatioVault utilise React Native avec Expo. Tous les composants doivent être compatibles avec l'architecture existante.

CTR-TECH-2 — API PD-287 figée Consommer uniquement les endpoints documentés dans la spec PD-287. Pas de contournement, pas d'appel direct en base.

CTR-TECH-3 — Authentification propriétaire existante Utiliser le mécanisme d'authentification déjà en place dans l'app (token JWT, refresh). Pas de nouveau flux d'auth.

CTR-TECH-4 — react-native-safe-area-context Utiliser react-native-safe-area-context (pas le SafeAreaView deprecated de react-native). Learning PD-107.

CTR-TECH-5 — Validation email côté client Valider le format email avant soumission au backend (regex alignée sur D-287-03 PD-287). Le backend re-valide, mais le client doit filtrer les erreurs évidentes.

CTR-TECH-6 — Français MVP, multilingue-ready Toutes les chaînes de caractères dans des fichiers i18n (pas en dur dans les composants). MVP en français uniquement.

4.2 Contraintes UX

CTR-UX-1 — Cohérence avec le design system existant Utiliser les composants du design system ProbatioVault-app (boutons, modales, badges, couleurs). Pas de composant custom sauf nécessité démontrée.

CTR-UX-2 — Accessibilité correcte par défaut Labels accessibles, contraste suffisant, navigation au clavier si applicable. RGAA complet hors périmètre.

CTR-UX-3 — Formulation UX révocation conforme ARB-7 Le texte de l'avertissement de révocation est contractuel (PD-287 ARB-7), ne pas le reformuler.

4.3 Contraintes sécurité

CTR-SEC-1 — Pas de données sensibles en log Les emails des destinataires ne doivent jamais apparaître dans les logs de l'app (console.log, Sentry, etc.).

CTR-SEC-2 — Pas de cache des données de partage Les données de partage (liens, journal) ne sont pas mises en cache local. Chaque affichage requiert un appel réseau frais. Les données d'état OTP et d'accès sont trop sensibles pour un cache client.

CTR-SEC-3 — Anti-enumeration préservé Le client ne doit pas tenter de déduire l'existence de partages par des appels exploratoires. Seuls les endpoints du propriétaire authentifié sont appelés.


5. Scénarios d'échec et résultats inacceptables

SE-1 — Création avec email invalide envoyée au backend

Le formulaire laisse passer un email mal formé et le backend retourne 400. Inacceptable : la validation client doit intercepter les formats invalides avant soumission.

SE-2 — Révocation sans confirmation

Le propriétaire révoque accidentellement un lien actif sans avertissement. Inacceptable : la modale de confirmation avec le texte ARB-7 est obligatoire.

SE-3 — État incohérent affiché

L'UI affiche "ACTIVE" alors que le lien est REVOKED côté backend (cache périmé, race condition). Inacceptable : pas de cache client, refresh systématique.

SE-4 — Email destinataire visible dans les logs

L'email du destinataire fuite dans Sentry, console.log ou un crash report. Inacceptable : violation RGPD.

SE-5 — Avertissement DRM non affiché à la première création

Le propriétaire crée un lien sans jamais avoir été averti de l'absence de DRM. Inacceptable : le flag AsyncStorage doit être vérifié à chaque ouverture du formulaire.

SE-6 — Journal vide sans explication

Le journal d'accès est vide (aucun événement) mais l'UI n'explique pas pourquoi (lien jamais activé, ou erreur réseau ?). Inacceptable : afficher un message contextuel adapté à l'état du lien.

SE-7 — Formulaire de création accessible sur une preuve non possédée

Par un bug de routing ou de guard, un utilisateur accède au formulaire de partage d'une preuve qui ne lui appartient pas. Inacceptable : le backend rejettera avec 403, mais l'UI ne doit même pas proposer l'action.

SE-8 — TTL custom hors bornes accepté

L'utilisateur entre un TTL de 60 jours via le date-picker custom et le formulaire le soumet. Inacceptable : validation client des bornes 15min-30j.

SE-9 — OTP_BLOCKED sans action possible

Le propriétaire voit un lien en état OTP_BLOCKED mais n'a aucune action disponible (ni révoquer, ni comprendre). Inacceptable : afficher l'explication + proposer la révocation.

SE-10 — Encart RGPD absent avant création

La création du lien se fait sans que l'utilisateur ait vu l'information RGPD (CA-287-27). Inacceptable : l'encart doit être affiché dans le formulaire de création, visible avant le bouton de soumission.


6. Tensions et conflits non résolus

TEN-1 — Rafraîchissement des données vs performance réseau

Pas de cache = appels réseau à chaque affichage. Sur un réseau mobile lent, l'expérience peut être dégradée (spinners fréquents). Mais la fraîcheur des données est critique (un lien révoqué doit immédiatement apparaître comme tel). Non résolue : pull-to-refresh + skeleton suffisent-ils ?

TEN-2 — Écran global "Mes partages" vs complexité UI

L'écran global agrège potentiellement beaucoup de partages (propriétaire actif avec 50 preuves × N liens). Pagination nécessaire, mais le backend retourne-t-il les résultats paginés ? (GET /shares — à vérifier dans la spec PD-287). Non résolue côté spec : la pagination est-elle supportée par l'API ?

TEN-3 — Date-picker custom vs complexité du composant

Le TTL custom via date/heure d'expiration nécessite un composant date-time picker. Les pickers natifs iOS/Android ont des UX très différentes. Non résolue : utiliser un picker natif (via @react-native-community/datetimepicker) ou un composant custom ?


7. Questions ouvertes — Décisions PO (2026-04-22)

Q-1 — Pagination GET /shares

Décision : utiliser la pagination existante du backend (offset/limit). Page de 20 items par défaut, infinite scroll sur l'écran global.

Q-2 — Date-picker custom

Décision : utiliser le picker natif @react-native-community/datetimepicker. UX différente iOS/Android acceptable pour le MVP.

Q-3 — Placement écran "Mes partages" dans la navigation

Décision : accessible depuis le menu/drawer principal, au même niveau que "Mes preuves". Pas d'onglet dans le tab bar principal (trop spécialisé).


8. Invariants

INV-298-01 — Validation email client avant soumission

Le formulaire de création DOIT valider le format email (aligné D-287-03) côté client avant tout appel réseau. Un email invalide ne doit jamais atteindre le backend.

INV-298-02 — Confirmation révocation avec texte contractuel ARB-7

Toute action de révocation DOIT afficher une modale de confirmation contenant le texte exact d'ARB-7 PD-287 : "Révoquer ce lien empêchera tout accès futur via ProbatioVault. Les consultations ou copies déjà réalisées ne peuvent pas être annulées."

INV-298-03 — Avertissement DRM à la première création

À la première ouverture du formulaire de création de lien (par compte, persisté en AsyncStorage), un avertissement sur l'absence de DRM DOIT être affiché (aligné ARB-8 PD-287). L'avertissement est mémorisé et ne se réaffiche pas automatiquement.

INV-298-04 — TTL borné côté client

Le formulaire DOIT interdire tout TTL < 15 minutes ou > 30 jours. Les presets respectent ces bornes. Le date-picker custom DOIT limiter la sélection à [now+15min, now+30j].

INV-298-05 — Pas de cache client pour les données de partage

Les écrans de liste et de détail de partage NE DOIVENT PAS utiliser de cache local. Chaque affichage effectue un appel réseau frais. Pull-to-refresh obligatoire.

INV-298-06 — Encart RGPD visible avant soumission

Le formulaire de création DOIT afficher un encart RGPD (base légale, finalité, durée de rétention) visible sans scroll avant le bouton "Créer le lien" (CA-287-27).

INV-298-07 — Pas de donnée sensible en log

Les emails de destinataires NE DOIVENT JAMAIS apparaître dans les logs applicatifs (console, Sentry, crash reports). Seul l'identifiant du lien (UUID) peut être loggé.

INV-298-08 — Badge d'état coloré fidèle au backend

L'état du lien affiché DOIT correspondre exactement à l'état retourné par le backend. Les 5 états (PENDING_ACTIVATION, ACTIVE, OTP_BLOCKED, REVOKED, EXPIRED) ont chacun un badge distinct (couleur + libellé).

INV-298-09 — IP partiellement masquée dans le journal

L'IP affichée dans le journal des accès DOIT être partiellement masquée (ex: 192.168.xxx.xxx192.168.*.*). Le masquage est fait côté client sur la donnée retournée par le backend.

INV-298-10 — i18n-ready : aucune chaîne en dur

Toutes les chaînes de caractères visibles par l'utilisateur DOIVENT être externalisées dans des fichiers de traduction. Aucune chaîne en dur dans les composants React.

INV-298-11 — Actions contextuelles par état

Les actions disponibles sur un lien DOIVENT dépendre de son état :

État Actions disponibles
PENDING_ACTIVATION Révoquer
ACTIVE Révoquer, Voir journal
OTP_BLOCKED Révoquer (recommandé), Voir journal
REVOKED Voir journal (lecture seule)
EXPIRED Voir journal (lecture seule)

INV-298-12 — Formulaire de création uniquement sur preuve possédée

Le bouton "Partager" et le formulaire de création NE DOIVENT être visibles que sur les preuves dont l'utilisateur est propriétaire (owner_user_id correspond à l'utilisateur connecté).


9. Arbitrages — Décisions PO (2026-04-22)

ARB-1 — Navigation à double entrée

Décision PO : Création depuis la preuve + gestion via écran global "Mes partages" + sous-section dans le détail de preuve.

ARB-2 — TTL UX

Décision PO : Presets (15min, 1h, 24h, 7j défaut, 30j) + option "Personnalisé" (date-picker natif). Rejet slider et date-picker seul.

ARB-3 — OTP_BLOCKED côté propriétaire

Décision PO : Affichage statut + explication risque + action recommandée "Révoquer". Pas de déblocage manuel.

ARB-4 — Niveau de détail journal

Décision PO : Niveau intermédiaire — date/heure, type événement, email, IP masquée, type device. Pas de user-agent complet, durée session, fingerprint.

ARB-5 — Avertissement DRM

Décision PO : Affiché une fois, mémorisé (ARB-8 PD-287). Re-consultable depuis le formulaire.


10. Périmètre MVP (synthèse PO)

Le propriétaire d'une preuve peut, depuis l'application mobile ProbatioVault :

  1. Créer un lien de partage depuis la fiche d'une preuve (email destinataire, TTL via presets ou custom, options plafond consultations et notifications).
  2. Voir les liens de partage d'une preuve depuis sa fiche, avec badge d'état coloré.
  3. Gérer tous ses partages depuis un écran global "Mes partages" (liste, filtre par état, tri par date).
  4. Révoquer un lien avec avertissement explicite conforme ARB-7.
  5. Consulter le journal des accès d'un lien (événements, email, IP masquée, device).
  6. Être informé de l'absence de DRM (première création) et de la collecte RGPD (chaque création).

In scope MVP : - 4 écrans : formulaire création, détail lien, liste par preuve, écran global "Mes partages" - Consommation API PD-287 (POST/GET/shares, revoke, events) - Validation client (email, TTL bornes) - Avertissements UX contractuels (révocation ARB-7, DRM ARB-8, RGPD CA-287-27) - i18n français, multilingue-ready - Accessibilité correcte par défaut

Out of scope MVP : - Portail destinataire - Push notifications - Deep linking vers partage - Mode hors-ligne - Multi-preuves par lien - RGAA complet


Fin de l'Expression de Besoin PD-298.