Aller au contenu

PD-240 — Plan d'implémentation

1. Références

  • Spec : PD-240-specification.md (v3)
  • Tests : PD-240-tests.md (v3)
  • Verdict Gate 3 : GO v3

2. Découpage en composants

2.1 Composants à créer

Composant Responsabilité Agent
DeleteAccountController Endpoint REST DELETE /user/account agent-developer
DeleteAccountService Orchestration du flux de suppression agent-developer
SessionInvalidationService Invalidation des sessions Redis agent-developer
UserDataPurgeService Anonymisation/purge RGPD agent-developer
KeycloakUserService Suppression compte Keycloak agent-developer
AuditController Endpoint admin GET /admin/audit/user/{userId} agent-developer
DeleteAccountE2ETests Tests d'intégration agent-qa-unit-integration

2.2 Composants existants à modifier

Composant Modification Agent
ReauthMiddleware (PD-238) Aucune modification, réutilisation
JwtAuthGuard Aucune modification, réutilisation

3. Flux de traitement

3.1 Flux nominal (F-240-01)

Client                 Controller           Service              External
  |                        |                    |                    |
  |-- DELETE /user/account |                    |                    |
  |   + JWT                |                    |                    |
  |   + X-Reauth-Token     |                    |                    |
  |   + body: {confirm}    |                    |                    |
  |                        |                    |                    |
  |                        |-- validateJWT() ---|                    |
  |                        |-- validateReauth() |                    |
  |                        |-- validateConfirm()|                    |
  |                        |                    |                    |
  |                        |-- deleteAccount() ----------------->   |
  |                        |                    |                    |
  |                        |                    |-- invalidateSessions()
  |                        |                    |   |                |
  |                        |                    |   |-- Redis.del() -|
  |                        |                    |                    |
  |                        |                    |-- purgeUserData() -|
  |                        |                    |   |                |
  |                        |                    |   |-- PostgreSQL   |
  |                        |                    |                    |
  |                        |                    |-- deleteKeycloakUser()
  |                        |                    |   |                |
  |                        |                    |   |-- Keycloak API |
  |                        |                    |                    |
  |<-- 200 OK -------------|                    |                    |

3.2 Ordre transactionnel

  1. Validation (pré-conditions)
  2. JWT valide (JwtAuthGuard)
  3. Reauth token valide (ReauthMiddleware)
  4. Confirmation renforcée valide (confirm === "DELETE_MY_ACCOUNT")

  5. Invalidation sessions (point de non-retour si succès)

  6. Supprimer toutes les clés Redis session:{userId}:*
  7. Si échec → rollback, retourner ERR-240-SESSION-INVALIDATION-FAILED

  8. Purge RGPD

  9. Anonymiser table users (email, name)
  10. Purger tables liées (à définir selon schéma)
  11. Créer entrée audit { status: "purged", purgedAt }
  12. Si échec → ERR-240-DELETE-FAILED (sessions déjà invalidées, compte non supprimé)

  13. Suppression Keycloak

  14. Appeler DELETE /admin/realms/{realm}/users/{keycloakId}
  15. Si échec → ERR-240-DELETE-FAILED

  16. Réponse succès

  17. Retourner 200 OK avec body vide ou { success: true }

4. Diagrammes Mermaid

4.1 Graphe de dépendances des composants

graph TD
    subgraph "Couche HTTP"
        DAC[DeleteAccountController]
        AC[AuditController]
    end

    subgraph "Guards & Middleware"
        JAG[JwtAuthGuard]
        RAM[ReauthMiddleware<br/><i>PD-238</i>]
    end

    subgraph "Couche Services"
        DAS[DeleteAccountService]
        SIS[SessionInvalidationService]
        UDPS[UserDataPurgeService]
        KUS[KeycloakUserService]
    end

    subgraph "Externes"
        Redis[(Redis)]
        PG[(PostgreSQL)]
        KC[Keycloak API]
    end

    DAC -->|"protège"| JAG
    DAC -->|"protège"| RAM
    DAC -->|"appelle"| DAS

    AC -->|"protège"| JAG

    DAS -->|"1. invalidate"| SIS
    DAS -->|"2. purge"| UDPS
    DAS -->|"3. delete"| KUS

    SIS -->|"DEL session:userId:*"| Redis
    UDPS -->|"anonymise + audit"| PG
    KUS -->|"DELETE /users/keycloakId"| KC
    AC -->|"SELECT audit"| PG

4.2 Diagramme de séquence — Flux nominal (F-240-01)

sequenceDiagram
    actor Client
    participant Ctrl as DeleteAccountController
    participant Guard as JwtAuthGuard
    participant Reauth as ReauthMiddleware<br/>(PD-238)
    participant Svc as DeleteAccountService
    participant Session as SessionInvalidationService
    participant Purge as UserDataPurgeService
    participant KC as KeycloakUserService
    participant Redis as Redis
    participant PG as PostgreSQL
    participant KCApi as Keycloak API

    Client->>Ctrl: DELETE /user/account<br/>JWT + X-Reauth-Token<br/>body: {confirm}
    Ctrl->>Guard: validateJWT()
    Guard-->>Ctrl: userId
    Ctrl->>Reauth: validateReauth()
    Reauth-->>Ctrl: OK
    Ctrl->>Ctrl: validateConfirm("DELETE_MY_ACCOUNT")

    Ctrl->>Svc: deleteAccount(userId)
    activate Svc

    Svc->>Session: invalidateSessions(userId)
    activate Session
    Session->>Redis: DEL session:{userId}:*
    Redis-->>Session: OK
    Session-->>Svc: sessions invalidées
    deactivate Session

    Svc->>Purge: purgeUserData(userId)
    activate Purge
    Purge->>PG: UPDATE users SET email=anon, name=anon
    Purge->>PG: INSERT audit_log (status: purged)
    PG-->>Purge: OK
    Purge-->>Svc: données purgées
    deactivate Purge

    Svc->>KC: deleteKeycloakUser(keycloakId)
    activate KC
    KC->>KCApi: DELETE /admin/realms/{realm}/users/{id}
    KCApi-->>KC: 204 No Content
    KC-->>Svc: OK
    deactivate KC

    deactivate Svc
    Ctrl-->>Client: 200 OK

4.3 Diagramme de séquence — Échec purge après invalidation sessions

sequenceDiagram
    actor Client
    participant Ctrl as DeleteAccountController
    participant Svc as DeleteAccountService
    participant Session as SessionInvalidationService
    participant Purge as UserDataPurgeService
    participant Redis as Redis
    participant PG as PostgreSQL

    Client->>Ctrl: DELETE /user/account
    Ctrl->>Svc: deleteAccount(userId)

    Svc->>Session: invalidateSessions(userId)
    Session->>Redis: DEL session:{userId}:*
    Redis-->>Session: OK
    Session-->>Svc: sessions invalidées

    Svc->>Purge: purgeUserData(userId)
    Purge->>PG: UPDATE users ...
    PG-->>Purge: ERROR (constraint violation)
    Purge-->>Svc: échec

    Note over Svc: État dégradé :<br/>sessions mortes,<br/>Keycloak intact.<br/>Audit log + job réconciliation.

    Svc-->>Ctrl: ERR-240-DELETE-FAILED
    Ctrl-->>Client: 500 Internal Server Error

5. Mapping Invariants → Mécanismes

Invariant Mécanisme technique Observable
INV-240-01 JwtAuthGuard sur route 401 si JWT absent/invalide
INV-240-02 ReauthMiddleware (PD-238) 403 si reauth token invalide
INV-240-03 Validation body confirm === "DELETE_MY_ACCOUNT" 400 ERR-240-DELETE-CONFIRMATION
INV-240-04 Keycloak Admin API DELETE Échec auth ultérieure
INV-240-05 PostgreSQL UPDATE/DELETE + audit entry Endpoint /admin/audit/user/{userId}
INV-240-06 Redis DEL avant suppression Keycloak Tokens précédents refusés
INV-240-07 Combinaison INV-240-04 + INV-240-06 Compte inutilisable
INV-240-08 ExceptionFilter avec format {error, message} Réponses JSON conformes
INV-240-09 Messages d'erreur explicites dans ExceptionFilter Message actionnable

6. Mapping Critères d'acceptation → Tests

CA Test Mécanisme vérifié
CA-240-01 T-240-ERR-01 JwtAuthGuard
CA-240-02 T-240-ERR-02 ReauthMiddleware
CA-240-03 T-240-ERR-03 Validation confirmation
CA-240-04 T-240-POST-01 Keycloak DELETE
CA-240-05 T-240-POST-02 Endpoint admin /admin/audit/user/{userId}
CA-240-06 T-240-NOM-01 Redis DEL
CA-240-07 T-240-ERR-* ExceptionFilter format
CA-240-08 T-240-ERR-04/05/06 Messages explicites

7. Gestion des erreurs

Code Condition HTTP Implémentation
ERR-240-UNAUTHENTICATED JWT absent/invalide 401 JwtAuthGuard exception
ERR-240-UNAUTHORIZED-REAUTH Reauth token invalide 403 ReauthMiddleware exception
ERR-240-DELETE-CONFIRMATION confirm !== "DELETE_MY_ACCOUNT" 400 Controller validation
ERR-240-DELETE-FAILED Échec purge ou Keycloak 500 Service exception avec cause
ERR-240-SESSION-INVALIDATION-FAILED Échec Redis 500 Service exception + rollback
ERR-240-INTERNAL Autre erreur 500 Global ExceptionFilter

8. Sécurité

8.1 Contrôles d'accès

  • Route protégée par JwtAuthGuard (authentification)
  • ReauthMiddleware exige une re-authentification récente (< 5 min)
  • Confirmation explicite empêche suppression accidentelle

8.2 Données sensibles

  • Les tokens JWT ne sont jamais loggés
  • Les données purgées sont anonymisées, pas supprimées (audit trail)
  • L'endpoint admin est protégé par rôle ADMIN

8.3 Atomicité

  • L'ordre (sessions → purge → Keycloak) garantit qu'aucune session ne survit à une suppression réussie
  • Si échec sessions → rollback complet
  • Si échec purge/Keycloak après invalidation sessions → compte verrouillé (sessions mortes, Keycloak intact) — état dégradé acceptable

9. Hypothèses techniques

ID Hypothèse Validation
HT-01 Keycloak Admin API accessible depuis le backend Test de connexion au démarrage
HT-02 Redis accessible et contient les sessions au format session:{userId}:* Conforme à PD-30
HT-03 Le schéma PostgreSQL a une table users avec email, name Conforme à PD-23
HT-04 ReauthMiddleware de PD-238 est disponible et fonctionnel PD-238 DONE

10. Points de vigilance

  1. Rollback limité : Si la purge RGPD échoue après invalidation des sessions, le compte est dans un état "limbo" (sessions mortes mais Keycloak actif). Mitigation : logs d'audit + job de réconciliation.

  2. Performance : La purge RGPD peut impacter plusieurs tables. Considérer une exécution asynchrone pour les tables volumineuses, mais garantir l'atomicité sur les tables critiques.

  3. Keycloak latence : La suppression Keycloak est synchrone. S'assurer du timeout approprié.

11. Livrables

Fichier Description
src/modules/user/controllers/delete-account.controller.ts Endpoint REST
src/modules/user/services/delete-account.service.ts Orchestration
src/modules/user/services/session-invalidation.service.ts Invalidation Redis
src/modules/user/services/user-data-purge.service.ts Purge RGPD
src/modules/auth/services/keycloak-user.service.ts Intégration Keycloak
src/modules/admin/controllers/audit.controller.ts Endpoint admin
src/modules/user/dto/delete-account.dto.ts DTO confirmation
test/e2e/delete-account.e2e-spec.ts Tests E2E