Aller au contenu

PD-32 — Synthèse d'implémentation

Produit par l'orchestrateur Claude à l'étape 6c.

Résumé

Critère Statut
Tâches complétées 5/5
Code contracts respectés
Tests implémentés
Review sécurité ✅ CONFORME

Livrables produits

Tâche 1 : Migration + Entity

Fichier Description
src/database/migrations/1738200000000-AddUserProfileFields.ts Migration TypeORM ajoutant name, avatar_url, preferences
src/modules/auth/entities/user.entity.ts Extension avec nouvelles colonnes + @Exclude() sur champs sensibles

Invariants respectés : - Colonnes nullable ou avec défaut pour compatibilité - Migration réversible (down) - @Exclude() sur srpSalt, passwordHash, validationToken

Tâche 2 : DTOs

Fichier Description
src/modules/user/dto/user-preferences.dto.ts Schéma strict pour preferences (locale, timezone, security, notifications)
src/modules/user/dto/update-user-profile.dto.ts Validation PUT (name, avatarUrl, preferences uniquement)
src/modules/user/dto/user-profile-response.dto.ts Réponse GET (name, email, avatarUrl, preferences)

Invariants respectés : - INV-32-05 : UpdateUserProfileDto n'accepte que name, avatar_url, preferences - INV-32-06 : Champs protégés rejetés via whitelist/forbidNonWhitelisted - INV-32-07 : UserPreferencesDto valide strictement le schéma

Tâche 3 : Service + Controller

Fichier Description
src/modules/user/services/user-profile.service.ts getProfile/updateProfile avec RLS
src/modules/user/controllers/user-profile.controller.ts GET/PUT /user/profile avec JwtAuthGuard
src/modules/user/user.module.ts Module NestJS
src/modules/user/index.ts Barrel exports
src/app.module.ts Import UserModule ajouté

Invariants respectés : - INV-32-01 : @UseGuards(JwtAuthGuard) sur le controller - INV-32-02 : Opérations via RlsQueryService + SET LOCAL - INV-32-08 : GET retourne UserProfileResponseDto - INV-32-10 : UPDATE dans transaction

Tâche 4 : Tests

Fichier Type Couverture
src/modules/user/dto/update-user-profile.dto.spec.ts Unit DTOs validation
src/modules/user/services/user-profile.service.spec.ts Unit Service (mocked)
test/user-profile.e2e-spec.ts E2E TC-NOM-, TC-ERR-, TC-INV-*

Scénarios couverts : - ✅ TC-NOM-01 : GET profil réussi - ✅ TC-NOM-02 : PUT profil réussi - ✅ TC-INV-32-03/04 : Champs sensibles exclus - ✅ TC-INV-32-06 : Champs protégés rejetés - ✅ TC-ERR-01 : Auth required (401) - ✅ TC-ERR-02 : Validation errors (400) - ✅ TC-ERR-03/04 : Cross-access RLS

Tâche 5 : Review sécurité

Fichier Verdict
docs/epics/auth-identity/PD-32-user-settings/PD-32-security-review.md ✅ CONFORME

Points audités : - Forbidden patterns : aucune violation - Injection SQL : non vulnérable (ORM paramétré) - Cross-access RLS : protégé - Champs sensibles : @Exclude() appliqué


Structure finale du module

src/modules/user/
├── controllers/
│   └── user-profile.controller.ts
├── dto/
│   ├── update-user-profile.dto.ts
│   ├── update-user-profile.dto.spec.ts
│   ├── user-preferences.dto.ts
│   └── user-profile-response.dto.ts
├── services/
│   ├── user-profile.service.ts
│   └── user-profile.service.spec.ts
├── index.ts
└── user.module.ts

test/
└── user-profile.e2e-spec.ts

src/database/migrations/
└── 1738200000000-AddUserProfileFields.ts

Endpoints exposés

Méthode Route Auth Description
GET /user/profile JWT Récupère le profil courant
PUT /user/profile JWT Met à jour le profil courant

Exemple GET /user/profile

{
  "name": "Jean Dupont",
  "email": "jean@example.com",
  "avatarUrl": "https://cdn.example.com/avatar.png",
  "preferences": {
    "locale": "fr",
    "timezone": "Europe/Paris",
    "security": { "loginNotifications": true },
    "notifications": { "email": true, "push": false }
  }
}

Exemple PUT /user/profile

// Request
{
  "name": "Jean Dupont Updated",
  "preferences": { "locale": "en" }
}

// Response (200 OK)
{
  "name": "Jean Dupont Updated",
  "email": "jean@example.com",
  "avatarUrl": "https://cdn.example.com/avatar.png",
  "preferences": {
    "locale": "en",
    "timezone": "Europe/Paris"
  }
}

Prochaines étapes

  1. Étape 7 : Acceptabilité (ChatGPT)
  2. Étape 8 : Gate CLOSURE
  3. Étape 9 : Retour d'expérience

Synthèse produite le 2026-02-05 par l'orchestrateur Claude