PD-298 — UI propriétaire de création et gestion des liens de partage sans compte¶
1. Objectif¶
La User Story PD-298 DOIT permettre au propriétaire authentifié d’une preuve, depuis l’application mobile ProbatioVault, de :
- créer un lien de partage sans compte (email destinataire, TTL, options),
- visualiser ses liens de partage (par preuve et globalement),
- révoquer un lien avec confirmation contractuelle,
- consulter le journal des accès d’un lien,
- voir les avertissements contractuels DRM/RGPD avant action.
La story est strictement côté propriétaire. Aucune capacité destinataire native n’est incluse.
2. Périmètre / Hors périmètre¶
Inclus¶
- Création d’un lien via
POST /sharesdepuis la fiche d’une preuve possédée. - Liste des liens associés à une preuve.
- Écran global “Mes partages” avec tri décroissant de création, filtre par état, pagination
offset/limit. - Détail d’un lien et révocation via
POST /shares/:id/revoke. - Consultation du journal via
GET /shares/:id/events. - Affichage contractuel :
- avertissement révocation (texte ARB-7 exact),
- avertissement absence de DRM (première création + reconsultation),
- encart RGPD visible avant soumission.
- Validation client des entrées (email, TTL).
- i18n FR (chaînes externalisées), multilingue-ready.
Exclu¶
- Portail destinataire dans l’app.
- Modification des endpoints backend PD-287.
- Push notifications côté app.
- Deep linking vers un partage.
- Mode hors-ligne / queue offline.
- Partage multi-preuves.
- RGAA complet (hors périmètre MVP).
3. Définitions¶
| Terme | Définition |
|---|---|
| Propriétaire | Utilisateur authentifié détenteur de la preuve (owner_user_id). |
| Lien de partage | Autorisation d’accès sans compte gérée côté backend PD-287. |
| États du lien | PENDING_ACTIVATION, ACTIVE, OTP_BLOCKED, REVOKED, EXPIRED. |
| TTL | Durée de validité du lien avant expiration automatique. |
| Journal d’accès | Historique append-only des événements d’accès du lien. |
| ARB-7 | Texte contractuel d’avertissement de révocation (PD-287). |
| ARB-8 | Avertissement contractuel d’absence de DRM (PD-287). |
| CA-287-27 | Obligation d’information RGPD avant création. |
Règle non testable marquée hors périmètre : - Validité juridique de la base légale RGPD (qualification légale) : hors périmètre de validation fonctionnelle UI.
4. Invariants (non négociables)¶
| ID | Règle | Justification |
|---|---|---|
| INV-298-01 | Le formulaire DOIT valider l’email avant tout appel réseau ; un email invalide NE DOIT PAS être soumis. | Évite erreurs évitables et fuite de qualité vers backend. |
| INV-298-02 | Toute révocation DOIT afficher le texte ARB-7 exact avant confirmation. | Réduction du risque d’action irréversible non comprise. |
| INV-298-03 | À la première ouverture de création (par compte), l’avertissement DRM DOIT être affiché puis mémorisé localement. | Information explicite sur l’absence de DRM. |
| INV-298-04 | Le TTL DOIT rester dans [15 min, 30 j] ; valeur par défaut 7 j. | Cohérence avec PD-287 et contrôle abus. |
| INV-298-05 | Les données de partage (listes, détail, events) NE DOIVENT PAS être mises en cache local ; chaque affichage DOIT être frais réseau. | Évite incohérences d’état sensibles. |
| INV-298-06 | L’encart RGPD DOIT être visible avant le bouton de soumission du formulaire. | Conformité CA-287-27. |
| INV-298-07 | Les emails destinataires NE DOIVENT JAMAIS être loggés ; seul shareId est loggable. | Protection PII / RGPD. |
| INV-298-08 | Le badge d’état affiché DOIT refléter strictement l’état backend parmi 5 états contractuels. | Source de vérité unique backend. |
| INV-298-09 | L’IP affichée dans le journal DOIT être partiellement masquée côté UI. | Minimisation exposition données réseau. |
| INV-298-10 | 100% des chaînes visibles DOIVENT être externalisées i18n (aucune chaîne en dur). | Maintenabilité locale + conformité linguistique. |
| INV-298-11 | Les actions disponibles DOIVENT dépendre de l’état du lien (matrice contractuelle §5.5). | Prévention actions invalides. |
| INV-298-12 | L’action “Partager” NE DOIT être visible que sur preuve possédée par l’utilisateur connecté. | Empêche tentative de partage hors propriété. |
| INV-298-13 | L’écran global DOIT paginer en offset/limit, limit=20 fixe MVP, tri created_at desc. | Scalabilité fonctionnelle MVP. |
| INV-298-14 | Toute transition d’état non listée en §5.5 est INTERDITE contractuellement. | Fermeture explicite de la machine à états. |
| INV-298-15 | REVOKED et EXPIRED sont terminaux : -> * : INTERDITE (état terminal, résolution manuelle uniquement). | Irréversibilité métier explicite. |
| INV-298-16 | Le client NE DOIT PAS effectuer d’appels exploratoires pour inférer des partages non autorisés. | Préservation anti-enumeration. |
| INV-298-17 | Le module de gestion des partages requiert réseau disponible ; aucune exécution offline n’est autorisée. | Cohérence sécurité/fraîcheur. |
5. Flux nominaux¶
5.1 Modèle de données contractuel (source unique formats)¶
| Donnée | Format / Encodage | Taille | Jeu de caractères | Case-sensitivity | Regex / Validation | Comportement si invalide |
|---|---|---|---|---|---|---|
shareId | UUID v4 texte | 36 chars | [0-9a-f-] | case-insensitive | /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/ | Rejet UI de la navigation détail, erreur bloquante. |
proofId | UUID v4 texte | 36 chars | [0-9a-f-] | case-insensitive | même regex UUID v4 | Action “Partager” masquée si absent/invalide. |
ownerUserId | UUID v4 texte | 36 chars | [0-9a-f-] | case-insensitive | même regex UUID v4 | Partage interdit côté UI. |
recipientEmail | Email RFC 5322 simplifié (référence PD-287 D-287-03) | 3..254 chars | ASCII printable sans espace terminal | comparaison case-insensitive | Regex exacte D-287-03 requise (non fournie ici) | Blocage soumission + message validation. |
shareState | Enum texte | 1 valeur | A-Z_ | case-sensitive | {PENDING_ACTIVATION, ACTIVE, OTP_BLOCKED, REVOKED, EXPIRED} | État inconnu => erreur bloquante + non-actionnable. |
ttlMinutes | Entier signé base10 | 1..5 digits | [0-9] | n/a | 15 <= ttlMinutes <= 43200 | Rejet client (pas d’appel API). |
maxViews (optionnel) | Entier base10 ou null | null ou 1..10 digits | [0-9] | n/a | null ou entier >=1 ; borne max backend à clarifier | Valeur <=0 rejet client ; > max backend => erreur backend propagée. |
notificationsEnabled | Booléen | 1 bit logique | true/false | n/a | bool strict | Valeur non-bool = rejet client. |
createdAt, expiresAt, eventAt | ISO 8601 UTC | 20..35 chars | ASCII | case-sensitive | Date parseable ISO8601 | Affichage “date indisponible” + pas de crash UI. |
eventType | Enum texte | 1 valeur | A-Z_ | case-sensitive | {CREATION, ACTIVATION, CONSULTATION, EXPORT, ECHEC_OTP, REVOCATION} (mapping backend à figer) | Valeur inconnue => libellé UNKNOWN_EVENT, journal conservé. |
eventRecipientEmail | Même contrat que recipientEmail | 3..254 chars | ASCII printable | cf. email | cf. D-287-03 | Si invalide, masquer valeur, garder événement. |
eventIpRaw | IPv4 ou IPv6 texte | 7..45 chars | [0-9a-fA-F:.] | case-insensitive | IPv4/IPv6 valide | Affichage “IP masquée indisponible”. |
eventIpMasked | IP masquée texte | v4: x.x.*.* ; v6: 4 hextets + *:*:*:* | [0-9a-fA-F*:.] | case-insensitive | Transformation déterministe de eventIpRaw | Si masquage impossible: fallback “IP masquée indisponible”. |
deviceType | Enum texte | 1 valeur | A-Z_ | case-sensitive | {MOBILE, DESKTOP} | Valeur inconnue => UNKNOWN_DEVICE. |
drmWarningSeen | Booléen persistant local par compte | 1 bit logique | true/false | n/a | bool strict | Si absent => considéré false (premier affichage obligatoire). |
5.2 Bornes numériques contractuelles¶
| Paramètre | Valeur par défaut | Min | Max | Unité | Contexte / Percentile | Comportement hors bornes |
|---|---|---|---|---|---|---|
ttlMinutes | 10080 (7j) | 15 | 43200 (30j) | minutes | n/a (pas d’objectif perf chiffré) | Rejet client bloquant. |
| Presets TTL | {15,60,1440,10080,43200} | 15 | 43200 | minutes | n/a | Preset hors liste impossible en UI. |
pagination.limit | 20 | 20 | 20 | éléments/page | n/a | Valeur différente interdite en MVP. |
pagination.offset | 0 | 0 | 2147483620 | éléments | n/a | Valeur hors bornes => clamp [0,max]. |
maxViews (optionnel) | null (illimité) | 1 | Non défini dans besoin/PD-287 accessible | consultations | n/a | <=0: rejet client ; >max backend: erreur backend, non masquée. |
Note contractuelle : - Aucun objectif de performance chiffré (latence P95/P99, mémoire) n’est fourni pour cette story ; ces SLA de performance sont hors périmètre.
5.3 SLA temporels (transitions)¶
| SLA | Valeur par défaut | Borne min | Borne max | Configurabilité | Comportement à expiration |
|---|---|---|---|---|---|
Validité lien (share_ttl) | 7j | 15min | 30j | Configurable par propriétaire (preset/custom) | État backend -> EXPIRED, accès futur révoqué, UI en lecture seule (journal consultable). |
Aucune autre transition temporelle identifiée côté UI propriétaire.
5.4 Flux nominaux contractuels¶
F-298-01 — Création d’un lien depuis une preuve
- Le propriétaire ouvre la fiche d’une preuve.
- Le système vérifie la propriété (
ownerUserId == user connecté). - Le propriétaire ouvre le formulaire de partage.
- Le système vérifie l’indicateur
drmWarningSeen: false=> affiche avertissement DRM avant saisie effective.true=> pas de réaffichage automatique.- Le formulaire expose : email destinataire, TTL (presets/custom),
maxViewsoptionnel, notifications, encart RGPD visible avant CTA. - À soumission, validations client obligatoires (email, TTL, types).
- Si valide, appel
POST /shares. - En succès, affichage du lien créé avec état
PENDING_ACTIVATION. - Rafraîchissement de la liste des liens.
F-298-02 — Liste des liens d’une preuve
- Depuis une preuve possédée, le propriétaire ouvre la section partages.
- Le système récupère les partages du propriétaire et affiche uniquement ceux liés à la preuve.
- Chaque ligne affiche au minimum : statut (badge), date création, email (non loggé), actions contextuelles.
- Pull-to-refresh force un rechargement réseau.
F-298-03 — Écran global “Mes partages”
- Le propriétaire ouvre l’écran via navigation principale.
- Le système appelle
GET /sharesavecoffset/limit. - Résultats triés par création décroissante, filtrables par état.
- Infinite scroll par incrément d’offset de 20.
- Aucun cache local des données de partage.
F-298-04 — Détail et révocation
- Le propriétaire ouvre le détail d’un
shareId. - Le système affiche données du lien + actions autorisées selon état.
- Sur action “Révoquer”, affichage obligatoire de la modale ARB-7.
- Si confirmation explicite, appel
POST /shares/:id/revoke. - En succès, rafraîchissement état et verrouillage des actions non autorisées.
F-298-05 — Journal des accès
- Le propriétaire ouvre le journal d’un lien.
- Le système appelle
GET /shares/:id/events. - Chaque entrée affiche : date/heure, type, email, IP masquée, device.
- Si journal vide, un message contextuel explicite est affiché (pas de vide silencieux).
F-298-06 — Consultation répétée des avertissements
- Le propriétaire peut reconsulter l’avertissement DRM depuis paramètres ou formulaire.
- L’encart RGPD est affiché à chaque création, avant soumission.
5.5 Machine d’états, transitions retour et états terminaux¶
Matrice des transitions
| État source | -> PENDING_ACTIVATION | -> ACTIVE | -> OTP_BLOCKED | -> REVOKED | -> EXPIRED |
|---|---|---|---|---|---|
PENDING_ACTIVATION | INTERDITE | AUTORISÉE (activation OTP) | AUTORISÉE (blocage OTP) | AUTORISÉE (révocation propriétaire) | AUTORISÉE (TTL atteint) |
ACTIVE | INTERDITE | INTERDITE | INTERDITE | AUTORISÉE (révocation propriétaire) | AUTORISÉE (TTL atteint) |
OTP_BLOCKED | INTERDITE | INTERDITE | INTERDITE | AUTORISÉE (révocation propriétaire) | AUTORISÉE (TTL atteint) |
REVOKED | INTERDITE (terminal) | INTERDITE (terminal) | INTERDITE (terminal) | INTERDITE (terminal) | INTERDITE (terminal) |
EXPIRED | INTERDITE (terminal) | INTERDITE (terminal) | INTERDITE (terminal) | INTERDITE (terminal) | INTERDITE (terminal) |
Transitions retour (obligatoire)
ACTIVE -> PENDING_ACTIVATION: INTERDITE (pas de rollback activation).OTP_BLOCKED -> PENDING_ACTIVATION: INTERDITE (pas de déblocage manuel en MVP).REVOKED -> ACTIVE: INTERDITE (révocation irréversible).EXPIRED -> ACTIVE: INTERDITE (expiration irréversible).REVOKED -> *: INTERDITE (état terminal, résolution manuelle uniquement).EXPIRED -> *: INTERDITE (état terminal, résolution manuelle uniquement).
Comportement downgrade/retour
- Données historiques (journal, métadonnées) : conservées en lecture seule.
- Quotas/limites : réappliqués immédiatement par état backend.
- Fonctionnalités : re-verrouillées immédiatement en
REVOKED/EXPIRED. - Aucune transition bidirectionnelle autorisée : Aucune transition retour applicable au sens A↔B autorisé.
Checklist machine à états
- Chaque état liste ses transitions sortantes autorisées/interdites.
- Chaque état terminal mentionne explicitement
-> * : INTERDITE. - Modèle d’états couvert par invariant dédié (
INV-298-14,INV-298-15).
5.6 Mécanismes de protection distribuée¶
Aucun mécanisme de protection distribuée applicable (module synchrone mono-instance).
5.7 Atomicité multi-composant¶
Aucune atomicité multi-composant applicable côté PD-298 (pas de transaction DB/queue côté app).
5.8 Contraintes inter-modules¶
| Élément | Contrat |
|---|---|
| Routes/écrans d’un autre module à protéger | Écran détail preuve (module preuves) : action “Partager” visible uniquement pour preuve possédée. |
| Mécanisme de protection | Garde UI de propriété (ownerUserId de la preuve vs utilisateur connecté). |
| Données nécessaires de l’autre schéma/module | proof.id, proof.owner_user_id, auth.user.id. |
| Résolution FK cross-module | share.proof_id référence logique proof.id (contrat API). |
| Scope d’enregistrement du guard | Scope local à la feature partage dans l’écran preuve, non global app-wide. |
| Exceptions d’accès | Aucune exception rôle spécifiée dans le besoin. |
5.9 Stratégie de migration DDL¶
Aucune migration DDL applicable (story UI mobile, aucune modification de colonne/base).
5bis. Diagrammes (obligatoires)¶
Diagramme d’état¶
stateDiagram-v2
[*] --> PENDING_ACTIVATION : creation share (POST /shares)
PENDING_ACTIVATION --> ACTIVE : OTP valide (backend)
PENDING_ACTIVATION --> OTP_BLOCKED : seuil OTP atteint (backend)
PENDING_ACTIVATION --> REVOKED : revoke owner
PENDING_ACTIVATION --> EXPIRED : ttl atteint
PENDING_ACTIVATION --> PENDING_ACTIVATION : INTERDITE
ACTIVE --> REVOKED : revoke owner
ACTIVE --> EXPIRED : ttl atteint
ACTIVE --> PENDING_ACTIVATION : INTERDITE
ACTIVE --> OTP_BLOCKED : INTERDITE
ACTIVE --> ACTIVE : INTERDITE
OTP_BLOCKED --> REVOKED : revoke owner
OTP_BLOCKED --> EXPIRED : ttl atteint
OTP_BLOCKED --> PENDING_ACTIVATION : INTERDITE
OTP_BLOCKED --> ACTIVE : INTERDITE
OTP_BLOCKED --> OTP_BLOCKED : INTERDITE
REVOKED --> PENDING_ACTIVATION : INTERDITE (terminal)
REVOKED --> ACTIVE : INTERDITE (terminal)
REVOKED --> OTP_BLOCKED : INTERDITE (terminal)
REVOKED --> EXPIRED : INTERDITE (terminal)
REVOKED --> REVOKED : INTERDITE (terminal)
EXPIRED --> PENDING_ACTIVATION : INTERDITE (terminal)
EXPIRED --> ACTIVE : INTERDITE (terminal)
EXPIRED --> OTP_BLOCKED : INTERDITE (terminal)
EXPIRED --> REVOKED : INTERDITE (terminal)
EXPIRED --> EXPIRED : INTERDITE (terminal) Diagramme de séquence¶
sequenceDiagram
participant U as Propriétaire
participant APP as App ProbatioVault
participant LS as Stockage local
participant API as API Sharing (PD-287)
U->>APP: Ouvre formulaire création
APP->>LS: Lire drmWarningSeen(userId)
LS-->>APP: true/false
alt drmWarningSeen == false
APP-->>U: Afficher avertissement DRM (ARB-8)
U->>APP: Accepte avertissement
APP->>LS: Ecrire drmWarningSeen(userId)=true
end
APP-->>U: Afficher encart RGPD avant CTA
U->>APP: Saisit email + TTL + options
APP->>APP: normaliser(email), valider(regex D-287-03), valider TTL [15..43200]
APP->>API: POST /shares {proofId, recipientEmail, ttlMinutes, maxViews?, notificationsEnabled}
API-->>APP: 201 {shareId, state=PENDING_ACTIVATION, expiresAt}
APP-->>U: Afficher résultat + état
U->>APP: Ouvre journal du lien
APP->>API: GET /shares/:id/events
API-->>APP: events[{eventAt, eventType, recipientEmail, ip, deviceType}]
APP->>APP: transformer ip -> ipMasked
APP-->>U: Afficher events (IP masquée) 6. Cas d’erreur¶
| Code erreur | Condition | Comportement attendu |
|---|---|---|
| ERR-298-01 | Email invalide en création | Blocage local, aucun appel réseau, message de validation. |
| ERR-298-02 | Tentative révocation sans confirmation | Action annulée, aucun appel POST /revoke. |
| ERR-298-03 | État UI obsolète vs backend | Rechargement réseau immédiat, état backend prioritaire. |
| ERR-298-04 | Email présent dans logs | Non-conformité sécurité (échec test invariant). |
| ERR-298-05 | Avertissement DRM non affiché à première création | Blocage de la soumission tant que non affiché. |
| ERR-298-06 | Journal vide sans contexte | Afficher message contextualisé (jamais activé / pas d’événement / erreur réseau). |
| ERR-298-07 | Preuve non possédée (action partage) | Action non affichée ; si contournement, backend 403 géré sans fuite. |
| ERR-298-08 | TTL hors bornes | Rejet local avant appel API. |
| ERR-298-09 | État OTP_BLOCKED sans action | Afficher explication + action recommandée “Révoquer”. |
| ERR-298-10 | Encart RGPD absent avant soumission | Soumission interdite tant que non visible. |
| ERR-298-11 | 401/session expirée sur endpoint share | Afficher erreur d’auth, redirection flux auth existant. |
| ERR-298-12 | Échec réseau (timeout/offline) | Afficher erreur réseau explicite, pas de faux succès local. |
7. Critères d’acceptation (testables)¶
| ID | Critère | Observable |
|---|---|---|
| CA-298-01 | Création valide appelle POST /shares et retourne un état initial affiché. | Requête observée + badge PENDING_ACTIVATION. |
| CA-298-02 | Email invalide n’atteint jamais le backend. | Aucune requête réseau quand format invalide. |
| CA-298-03 | TTL hors [15min,30j] est bloqué côté client. | Bouton submit inopérant + message d’erreur. |
| CA-298-04 | Révocation affiche le texte ARB-7 exact avant appel API. | Modal avec texte strict + appel seulement après confirmation. |
| CA-298-05 | Écran global liste les partages triés desc et paginés offset/limit=20. | Ordre vérifié + chargement page suivante. |
| CA-298-06 | Filtres par état appliquent la matrice des 5 états. | Résultats filtrés cohérents à l’état sélectionné. |
| CA-298-07 | Aucune donnée de partage n’est lue depuis cache local persistant. | Chaque entrée d’écran déclenche appel réseau frais. |
| CA-298-08 | Journal affiche date/type/email/IP masquée/device. | Colonnes visibles et remplies selon payload. |
| CA-298-09 | IP affichée est masquée, jamais brute. | Pattern x.x.*.* (v4) / masquage v6. |
| CA-298-10 | Avertissement DRM est affiché à la première ouverture uniquement. | Première ouverture: visible ; seconde ouverture: non automatique. |
| CA-298-11 | Encart RGPD est visible avant CTA de création. | Encart visible à l’écran au moment de soumission. |
| CA-298-12 | Action “Partager” absente sur preuve non possédée. | Aucun CTA partage si ownerUserId différent. |
| CA-298-13 | Toutes les chaînes UI de la feature sont externalisées i18n. | Audit statique sans chaînes littérales hardcodées. |
| CA-298-14 | Emails destinataires absents des logs applicatifs. | Inspection logs/tests: aucun email brut. |
| CA-298-15 | Actions disponibles respectent la matrice par état. | Boutons visibles/invisibles selon shareState. |
8. Scénarios de test (Given / When / Then)¶
Scénario 1 — Création nominale
- GIVEN propriétaire authentifié sur preuve possédée
- WHEN il soumet email valide + TTL 7j
- THEN
POST /sharesréussit - AND le lien apparaît avec état
PENDING_ACTIVATION
Scénario 2 — Email invalide
- GIVEN formulaire de création ouvert
- WHEN email invalide est saisi
- THEN la soumission est bloquée localement
- AND aucune requête backend n’est envoyée
Scénario 3 — TTL hors borne haute
- GIVEN formulaire ouvert
- WHEN TTL custom > 30j
- THEN la soumission est refusée côté client
- AND un message de borne est affiché
Scénario 4 — Révocation confirmée
- GIVEN un lien
ACTIVE - WHEN propriétaire clique “Révoquer” puis confirme
- THEN modal ARB-7 exacte est visible avant appel
- AND
POST /shares/:id/revokeest envoyé après confirmation - AND l’état devient
REVOKED
Scénario 5 — Révocation annulée
- GIVEN un lien
ACTIVE - WHEN propriétaire ferme la modal sans confirmer
- THEN aucun appel
revoken’est effectué - AND l’état reste inchangé
Scénario 6 — Première création et avertissement DRM
- GIVEN
drmWarningSeen=false - WHEN formulaire création est ouvert
- THEN l’avertissement DRM est affiché avant soumission
- AND le flag est mémorisé après acquittement
Scénario 7 — Journal d’accès
- GIVEN un lien ayant des événements
- WHEN propriétaire ouvre “Voir journal”
- THEN
GET /shares/:id/eventsest appelé - AND chaque ligne affiche IP masquée, pas IP brute
Scénario 8 — Journal vide contextualisé
- GIVEN un lien sans événement retourné
- WHEN écran journal est affiché
- THEN un message explicatif contextuel est visible
- AND l’écran n’est pas silencieusement vide
Scénario 9 — Preuve non possédée
- GIVEN preuve dont
ownerUserId != user connecté - WHEN utilisateur ouvre le détail de preuve
- THEN action “Partager” est absente
- AND aucun endpoint de création n’est appelé
Scénario 10 — Pas de cache local
- GIVEN un lien révoqué depuis un autre terminal
- WHEN propriétaire rouvre la liste partages
- THEN un appel réseau frais est effectué
- AND l’état affiché est
REVOKED
9. Hypothèses explicites¶
| ID | Hypothèse | Impact si faux |
|---|---|---|
| H-298-01 | La regex email contractuelle D-287-03 est disponible côté référence backend. | Validation client non alignée backend, écarts UX/API. |
| H-298-02 | GET /shares expose pagination offset/limit utilisable en app. | Infinite scroll non réalisable tel que spécifié. |
| H-298-03 | Le backend accepte limit=20 constant pour le MVP. | Liste globale inopérante ou tronquée. |
| H-298-04 | Le payload events contient bien eventAt, eventType, recipientEmail, ip, deviceType. | Journal incomplet vs objectif métier. |
| H-298-05 | La borne maximale backend pour maxViews existe mais n’est pas fournie ici. | Validation client incomplète, risque de 400 backend. |
| H-298-06 | Les transitions backend réelles sont compatibles avec la matrice §5.5. | Divergence machine d’états UI/backend (écart majeur). |
| H-298-07 | La durée de rétention RGPD à afficher est fournie par source juridique produit. | Encart RGPD incomplet/non conforme. |
| H-298-08 | Validation juridique de la base légale RGPD n’est pas un test fonctionnel UI. | À traiter en conformité légale (hors périmètre tests fonctionnels). |
10. Points à clarifier¶
10.1 Contraintes techniques contractuelles (stack réelle)¶
| Élément | Valeur contractuelle |
|---|---|
| Projet cible | ProbatioVault-app |
| Stack mobile | React Native + Expo SDK 54 + TypeScript |
| Contrainte Safe Area | react-native-safe-area-context (obligatoire) |
| Picker TTL custom | @react-native-community/datetimepicker (décision PO du 2026-04-22) |
| Backend consommé | ProbatioVault-backend (NestJS + TypeORM + PostgreSQL) via endpoints PD-287 uniquement |
| Interdictions explicites | Aucun Swift/SwiftUI, aucun framework backend alternatif dans cette spec |
10.2 Données manquantes / arbitrages restants¶
| ID | Point à clarifier | Donnée manquante |
|---|---|---|
| PC-298-01 | Regex email D-287-03 exacte | Motif regex normatif backend non fourni dans l’expression de besoin. |
| PC-298-02 | Borne max maxViews côté backend | Valeur max contractuelle absente. |
| PC-298-03 | Codes exacts eventType backend | Mapping backend->UI à figer (labels FR vs enums API). |
| PC-298-04 | Comportement exact transitions non listées (ex: ACTIVE -> OTP_BLOCKED) | Matrice backend PD-287 détaillée non jointe. |
| PC-298-05 | Gestion normative IPv6 masquée | Règle UI v6 à valider produit/sécurité. |
| PC-298-06 | Texte exact “durée de rétention” RGPD | Valeur juridique à afficher non fournie. |
| PC-298-07 | Message contextuel journal vide par état | Copywriting final non fourni (i18n clés à valider). |
Références¶
- Epic : Référence épique non fournie dans l’expression de besoin.
- JIRA :
PD-298. - Repos concernés :
ProbatioVault-app(principal),ProbatioVault-backend(dépendance API PD-287). - Documents associés :
- Expression de besoin PD-298 (date
2026-04-22), - PD-287 (backend, DONE, date
2026-04-19), - ARB-7 / ARB-8 PD-287,
- CA-287-27 (encart RGPD).