Aller au contenu

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_url attendu 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 https uniquement, longueur maximale 2048 caracteres, valeur nullable (null autorisee).
  • Champs proteges : id, email, plan, status, srpSalt, passwordHash, createdAt, updatedAt, validationToken et 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 60
    • biometric_enabled : booleen
  • notifications : objet optionnel :
    • security_alerts : booleen
    • product_updates : booleen
  • Toute cle hors schema est interdite.
  • Compatibilite PD-106 : la reponse GET /user/profile contient au minimum name, 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

  1. Le client appelle GET /user/profile avec JWT valide.
  2. Le systeme identifie l'utilisateur courant.
  3. Le systeme retourne le profil non sensible de cet utilisateur.
  4. La reponse contient au minimum name, email, avatar_url et peut contenir preferences.

F-32-02 - Mise a jour partielle du profil

  1. Le client appelle PUT /user/profile avec JWT valide et payload.
  2. Le systeme valide strictement le payload.
  3. Si le payload ne contient que des champs modifiables valides, la mise a jour est appliquee au profil de l'utilisateur courant.
  4. 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

  1. Aucun point fonctionnel ouvert dans le perimetre PD-32.
  2. 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