PD-32 - Endpoints gestion profil utilisateur¶
1. Objectif¶
Definir le contrat canonique des endpoints backend permettant a un utilisateur authentifie de : - consulter son propre profil ; - modifier uniquement les champs de profil autorises ; - obtenir un contrat compatible avec PD-106 pour GET /user/profile.
2. Perimetre / Hors perimetre¶
Inclus¶
- Endpoint
GET /user/profile. - Endpoint
PUT /user/profile. - Authentification JWT obligatoire sur ces endpoints.
- Isolation stricte des donnees utilisateur (acces a son propre profil uniquement).
- Validation stricte des donnees d'entree.
- Application du rate limiting global existant.
- Retour des champs profil non sensibles, incluant le socle
name,email,avatar_urlattendu par PD-106. - Gestion du champ
preferences(lecture/ecriture) selon schema contractuel ci-dessous.
Exclu¶
- MFA.
- Changement de mot de passe.
- Suppression de compte.
- Logout / gestion de session.
- Modification de
email. - Modification de
plan. - Upload de fichier avatar.
- Toute lecture/modification de profil d'un autre utilisateur.
3. Definitions¶
- Profil utilisateur : donnees non sensibles exposees par
GET /user/profile. - Utilisateur authentifie : utilisateur porteur d'un JWT valide et non revoque.
- Champs modifiables :
name,avatar_url,preferences. - avatar_url valide : URL absolue en scheme
httpsuniquement, longueur maximale 2048 caracteres, valeur nullable (nullautorisee). - Champs proteges :
id,email,plan,status,srpSalt,passwordHash,createdAt,updatedAt,validationTokenet tout champ non explicitement modifiable. - Preferences : objet JSON conforme au schema contractuel suivant :
locale:"fr" | "en"(optionnel)timezone: chaine IANA timezone (optionnel)security: objet optionnel :auto_lock_minutes: entier entre 1 et 60biometric_enabled: booleen
notifications: objet optionnel :security_alerts: booleenproduct_updates: booleen
- Toute cle hors schema est interdite.
- Compatibilite PD-106 : la reponse
GET /user/profilecontient au minimumname,email,avatar_url(nullable). - Minimisation : exclusion stricte de toute donnee sensible de la reponse profil.
- Hors perimetre : exigence non verifiable dans PD-32 seul et devant etre prouvee par un artefact externe.
4. Invariants (non negociables)¶
| ID | Regle | Justification |
|---|---|---|
| INV-32-01 | GET /user/profile et PUT /user/profile DOIVENT exiger un JWT valide. | Empêche l'acces anonyme. |
| INV-32-02 | Un utilisateur NE DOIT pouvoir consulter/modifier que son propre profil. | Empêche l'acces croise. |
| INV-32-03 | GET /user/profile DOIT retourner uniquement des champs non sensibles. | RGPD minimisation et securite. |
| INV-32-04 | Les champs sensibles/proteges (passwordHash, srpSalt, etc.) NE DOIVENT jamais etre exposes. | Evite la fuite de secrets. |
| INV-32-05 | PUT /user/profile DOIT accepter uniquement name, avatar_url, preferences. | Evite modifications illegitimes. |
| INV-32-06 | Toute tentative de modification d'un champ protege DOIT etre refusee explicitement. | Integrite du modele utilisateur. |
| INV-32-07 | Le schema preferences DOIT etre strictement valide ; aucune cle inconnue n'est acceptee. | Robustesse et prevention injection. |
| INV-32-08 | GET /user/profile DOIT etre compatible PD-106 et inclure name, email, avatar_url (nullable). | Compatibilite mobile contractuelle. |
| INV-32-09 | Les endpoints profil DOIVENT etre couverts par le rate limiting global. | Prevention des abus. |
| INV-32-10 | Toute erreur metier/validation/auth DOIT retourner un echec explicite sans effet partiel silencieux. | Auditabilite et robustesse. |
| INV-32-11 | HORS PERIMETRE PD-32 : la preuve juridique exhaustive RGPD (dossier compliance global) DOIT etre fournie par artefacts conformite. | Non prouvable par tests endpoint seuls. |
5. Flux nominaux¶
F-32-01 - Lecture du profil¶
- Le client appelle
GET /user/profileavec JWT valide. - Le systeme identifie l'utilisateur courant.
- Le systeme retourne le profil non sensible de cet utilisateur.
- La reponse contient au minimum
name,email,avatar_urlet peut contenirpreferences.
F-32-02 - Mise a jour partielle du profil¶
- Le client appelle
PUT /user/profileavec JWT valide et payload. - Le systeme valide strictement le payload.
- Si le payload ne contient que des champs modifiables valides, la mise a jour est appliquee au profil de l'utilisateur courant.
- Le systeme retourne le profil mis a jour (meme contrat de sortie que GET).
5bis. Diagrammes Mermaid¶
SD-32-01 — Lecture du profil (GET /user/profile)¶
Flux nominal F-32-01. Verifie INV-32-01 (JWT obligatoire), INV-32-02 (isolation utilisateur), INV-32-03/04 (exclusion champs sensibles), INV-32-08 (compatibilite PD-106).
sequenceDiagram
participant C as Client
participant GW as API Gateway
participant Auth as AuthGuard (JWT)
participant Ctrl as ProfileController
participant Svc as ProfileService
participant DB as PostgreSQL (RLS)
C->>GW: GET /user/profile + Bearer JWT
GW->>GW: Rate limit check (INV-32-09)
alt Seuil depasse
GW-->>C: 429 ERR-32-RATE-LIMIT
end
GW->>Auth: Validate JWT
alt JWT absent/invalide/revoque
Auth-->>C: 401 ERR-32-UNAUTHENTICATED (INV-32-01)
end
Auth->>Ctrl: req.user = { userId }
Ctrl->>Svc: getProfile(userId)
Svc->>DB: SELECT (name, email, avatar_url, preferences) WHERE id = userId
Note over DB: RLS enforce isolation (INV-32-02)
DB-->>Svc: row (champs non sensibles uniquement)
Note over Svc: Exclut passwordHash, srpSalt,<br/>validationToken (INV-32-03, INV-32-04)
Svc-->>Ctrl: ProfileDTO {name, email, avatar_url, preferences}
Note over Ctrl: Contrat PD-106 : name + email + avatar_url (INV-32-08)
Ctrl-->>C: 200 ProfileDTO SD-32-02 — Mise a jour du profil (PUT /user/profile)¶
Flux nominal F-32-02. Verifie INV-32-01 (JWT), INV-32-05 (champs modifiables), INV-32-06 (rejet champs proteges), INV-32-07 (schema preferences strict), INV-32-10 (echec explicite sans effet partiel).
sequenceDiagram
participant C as Client
participant GW as API Gateway
participant Auth as AuthGuard (JWT)
participant Ctrl as ProfileController
participant Val as ValidationPipe
participant Svc as ProfileService
participant DB as PostgreSQL (RLS)
C->>GW: PUT /user/profile + Bearer JWT + body
GW->>GW: Rate limit check (INV-32-09)
alt Seuil depasse
GW-->>C: 429 ERR-32-RATE-LIMIT
end
GW->>Auth: Validate JWT
alt JWT absent/invalide/revoque
Auth-->>C: 401 ERR-32-UNAUTHENTICATED (INV-32-01)
end
Auth->>Ctrl: req.user = { userId }
Ctrl->>Val: Validate payload
Val->>Val: Verifier champs proteges (INV-32-06)
alt Champ protege detecte (email, plan, id, status...)
Val-->>C: 400 ERR-32-PROTECTED-FIELD
end
Val->>Val: Verifier champs modifiables (INV-32-05)
Val->>Val: Valider schema preferences strict (INV-32-07)
alt Payload invalide (type, format, cle inconnue)
Val-->>C: 400 ERR-32-VALIDATION
end
Ctrl->>Svc: updateProfile(userId, validatedDTO)
Svc->>DB: UPDATE (name, avatar_url, preferences) WHERE id = userId
Note over DB: RLS enforce isolation (INV-32-02)
Note over Svc: Aucune mutation partielle (INV-32-10)
DB-->>Svc: updated row
Svc-->>Ctrl: ProfileDTO {name, email, avatar_url, preferences}
Note over Ctrl: Meme contrat de sortie que GET (INV-32-08)
Ctrl-->>C: 200 ProfileDTO 6. Cas d'erreur¶
Format contractuel de reponse d'erreur : {\"error\":\"ERR-32-XXX\",\"message\":\"...\"}.
| Code erreur | Condition | Comportement attendu |
|---|---|---|
| ERR-32-UNAUTHENTICATED | JWT absent/invalide/revoque | Refus d'acces ; aucune lecture/ecriture effectuee. |
| ERR-32-FORBIDDEN-CROSS-ACCESS | Contexte d'identite non coherent avec la cible de donnees | Refus ; aucune donnee d'un autre utilisateur exposee/modifiee. |
| ERR-32-VALIDATION | Payload invalide (type, taille, format, cle inconnue) | Refus explicite ; aucune mise a jour appliquee. |
| ERR-32-PROTECTED-FIELD | Tentative de modification d'un champ protege | Refus explicite ; aucune mise a jour appliquee. |
| ERR-32-RATE-LIMIT | Seuil global depasse | Refus explicite ; aucune operation effectuee. |
| ERR-32-INTERNAL | Erreur interne non metier | Refus explicite ; aucun succes affiche. |
7. Criteres d'acceptation (testables)¶
| ID | Critere | Observable |
|---|---|---|
| CA-32-01 | GET /user/profile sans JWT est refuse. | Reponse d'erreur auth. |
| CA-32-02 | PUT /user/profile sans JWT est refuse. | Reponse d'erreur auth. |
| CA-32-03 | Un utilisateur ne peut pas lire/modifier un profil autre que le sien. | Tentative d'acces croise refusee. |
| CA-32-04 | GET /user/profile ne contient aucun champ sensible/protege. | Inspection reponse JSON. |
| CA-32-05 | GET /user/profile contient name, email, avatar_url (nullable). | Verification schema reponse. |
| CA-32-06 | PUT /user/profile accepte la mise a jour de name. | Valeur mise a jour en sortie. |
| CA-32-07 | PUT /user/profile accepte la mise a jour de avatar_url. | Valeur mise a jour en sortie. |
| CA-32-08 | PUT /user/profile accepte la mise a jour de preferences conformes. | Valeur preferences mise a jour en sortie. |
| CA-32-09 | PUT /user/profile rejette toute cle inconnue dans preferences. | Erreur validation sans ecriture. |
| CA-32-10 | PUT /user/profile rejette la modification de email et plan. | Erreur champ protege sans ecriture. |
| CA-32-11 | PUT /user/profile rejette la modification de id, status, srpSalt, passwordHash. | Erreur champ protege sans ecriture. |
| CA-32-12 | Les endpoints profil sont soumis au rate limiting global. | Reponse rate limit apres depassement. |
| CA-32-13 | Toute erreur retourne un echec explicite et aucune mutation partielle. | Code erreur + etat inchange. |
| CA-32-14 | HORS PERIMETRE PD-32 : preuve juridique RGPD exhaustive disponible via artefact externe. | Presence d'artefact conformite externe. |
8. Scenarios de test (Given / When / Then)¶
Scenario 1 - Lecture profil nominale¶
GIVEN utilisateur U1 authentifie. WHEN U1 appelle GET /user/profile. THEN la reponse contient name, email, avatar_url (nullable) et n'expose aucun champ sensible.
Scenario 2 - Mise a jour name nominale¶
GIVEN utilisateur U1 authentifie. WHEN U1 appelle PUT /user/profile avec name valide. THEN la mise a jour est appliquee et reflétée dans la reponse.
Scenario 3 - Mise a jour preferences nominale¶
GIVEN utilisateur U1 authentifie. WHEN U1 appelle PUT /user/profile avec preferences conformes au schema. THEN la mise a jour est appliquee et reflétée dans la reponse.
Scenario 4 - Rejet champ protege¶
GIVEN utilisateur U1 authentifie. WHEN U1 appelle PUT /user/profile avec email ou plan. THEN la requete est refusee explicitement sans modification des donnees.
Scenario 5 - Rejet cle inconnue dans preferences¶
GIVEN utilisateur U1 authentifie. WHEN U1 envoie preferences avec une cle non autorisee. THEN la requete est refusee explicitement sans modification.
Scenario 6 - Rejet sans authentification¶
GIVEN aucun JWT valide. WHEN appel GET ou PUT /user/profile. THEN la requete est refusee.
Scenario 7 - Protection acces croise¶
GIVEN utilisateur U1 authentifie et utilisateur U2 existant. WHEN U1 tente d'obtenir/modifier des donnees hors son contexte identite. THEN l'acces est refuse et aucune donnee U2 n'est exposee.
Scenario 8 - Rate limit¶
GIVEN utilisateur authentifie. WHEN l'utilisateur depasse le seuil global de requetes profil. THEN le systeme retourne ERR-32-RATE-LIMIT.
Scenario 9 - Non fuite de champs sensibles¶
GIVEN utilisateur authentifie. WHEN GET /user/profile est execute. THEN passwordHash, srpSalt, validationToken et autres champs proteges sont absents de la reponse.
Scenario 10 - Hors perimetre RGPD global¶
GIVEN perimetre limite a PD-32 endpoints. WHEN l'auditeur demande la preuve juridique RGPD exhaustive. THEN la preuve est marquee hors perimetre PD-32 et reference un artefact conformite externe.
9. Hypotheses explicites¶
| ID | Hypothese | Impact si faux |
|---|---|---|
| H-32-01 | Le mecanisme JWT existant permet d'identifier de facon fiable l'utilisateur courant. | Impossible de garantir INV-32-01/02. |
| H-32-02 | Le mecanisme d'isolation des donnees (RLS/contexte identite) est actif et correct. | Risque d'acces croise critique. |
| H-32-03 | La table utilisateur peut etre etendue avec name, avatar_url, preferences sans rupture de donnees existantes. | Blocage de mise en service PD-32. |
| H-32-04 | Le rate limiting global est actif sur ces routes en environnement cible. | CA-32-12 non atteignable. |
| H-32-05 | Le format des erreurs expose un code exploitable pour les cas contractuels. | CA-32-13 non verifiable. |
| H-32-06 | PD-106 consomme au minimum name, email, avatar_url et tolere la presence de preferences. | Risque d'incompatibilite client. |
| H-32-07 | L'artefact conformite RGPD global est gere hors PD-32. | CA-32-14 non demonstrable dans le lot. |
10. Points a clarifier¶
- Aucun point fonctionnel ouvert dans le perimetre PD-32.
- Hors perimetre : reference exacte de l'artefact conformite RGPD global (preuve juridique exhaustive).
References¶
- Epic : PD-182 - Authentification, identite et controle d'acces
- JIRA : PD-32
- Repos concernes : ProbatioVault-backend