Skip to content

Profiles Domain

Definition

Le domaine profiles couvre une ressource composite:

  • le compte utilisateur dans auth.users
  • le profil applicatif dans public.profiles

Le backend expose cette ressource pour centraliser les regles d'acces, le controle d'entreprise et les operations sensibles de cycle de vie utilisateur.

References:

  • back/src/profiles/profiles.controller.ts
  • back/src/profiles/profiles.service.ts

Donnees exposees

Partie auth.users

ChampTypeUsage
idstringIdentifiant auth Supabase
emailstring | nullEmail de connexion
lastSignInAtstring | nullDerniere connexion connue
bannedUntilstring | nullDate d'archivage technique
isArchivedbooleanDerive de bannedUntil

Partie profiles

ChampTypeModifiable
idnumberNon
uuidstringNon
userIdstringNon
usernamestring | nullOui
firstnamestring | nullOui
lastnamestring | nullOui
matriculestring | nullOui
addressstring | nullOui
enterpriseIdnumberNon
photoIdstring | nullOui
photoUrlstring | nullNon, derive par l'API
roleIdnumber | nullNon dans cette V1
jobstring | nullOui
createdAtstringNon
updatedAtstringNon

Champs explicitement hors perimetre des updates:

  • email
  • password
  • roleId
  • enterpriseId

Le changement d'email passe par des endpoints dedies avec audit:

  • POST /profiles/me/email
  • POST /profiles/:id/email

Le changement de mot de passe passe par des endpoints dedies avec audit:

  • POST /profiles/me/password
  • POST /profiles/:id/password

Le changement de role passe par un endpoint dedie avec audit:

  • POST /profiles/:id/role

La double authentification console:

  • ne passe pas par une API backend dediee
  • est geree directement par Supabase Auth MFA cote frontend
  • utilise un facteur TOTP via application d'authentification
  • se pilote depuis Mon Profil
  • s'applique au flux de connexion email + mot de passe
  • le magic link reste une alternative de connexion sans etape TOTP supplementaire
  • le nom affiche dans l'application TOTP est configurable via NUXT_PUBLIC_MFA_ISSUER ou VITE_MFA_ISSUER
  • le nom amical du facteur est configurable via NUXT_PUBLIC_MFA_FRIENDLY_NAME ou VITE_MFA_FRIENDLY_NAME

Regles d'acces

Endpointsuper-adminadministrateurutilisateur
GET /profiles/meOuiOuiOui
PATCH /profiles/meOuiOuiOui
POST /profiles/me/emailOuiOuiOui
POST /profiles/me/passwordOuiOuiOui
POST /profiles/me/photoOuiOuiOui
DELETE /profiles/me/photoOuiOuiOui
POST /profiles/me/enterpriseOui, uniquement super-adminNonNon
GET /enterprises/:enterpriseId/profilesOuiOui, si enterpriseId == profile.enterprise_idNon
POST /enterprises/:enterpriseId/profilesOuiOui, si enterpriseId == profile.enterprise_idNon
GET /profiles/:idOuiOui, si le profil cible est sur son entrepriseOui, pour lui-meme uniquement
PATCH /profiles/:idOuiOui, si le profil cible est sur son entrepriseOui, pour lui-meme uniquement
POST /profiles/:id/emailOuiOui, si le profil cible est sur son entrepriseOui, pour lui-meme uniquement
POST /profiles/:id/passwordOuiOui, si le profil cible est sur son entrepriseOui, pour lui-meme uniquement
POST /profiles/:id/roleOuiOui, si le profil cible est sur son entrepriseNon
POST /profiles/:id/photoOuiOui, si le profil cible est sur son entrepriseOui, pour lui-meme uniquement
DELETE /profiles/:id/photoOuiOui, si le profil cible est sur son entrepriseOui, pour lui-meme uniquement
DELETE /profiles/:idOuiOui, si le profil cible est sur son entrepriseNon
POST /profiles/:id/archiveOuiOui, si le profil cible est sur son entrepriseNon
POST /profiles/:id/unarchiveOuiOui, si le profil cible est sur son entrepriseNon
POST /profiles/bulk/archiveOuiOui, pour des profils de son entreprise uniquementNon
POST /profiles/bulk/deleteOuiOui, pour des profils de son entreprise uniquementNon

Contraintes fortes:

  • pas d'auto-suppression
  • pas d'auto-archivage
  • pas d'auto-desarchivage
  • pas d'auto-changement de role
  • un administrateur ne peut pas creer un compte super-admin
  • un administrateur peut attribuer uniquement administrateur, valideur, utilisateur
  • un administrateur ne peut pas modifier un profil actuellement super-admin
  • un administrateur ne peut pas changer le mot de passe d'un profil actuellement super-admin
  • quand un profil devient administrateur ou super-admin, ses rattachements profiles_organisations et profiles_services sont purges
  • les routes bulk valident tous les profils cibles avant de commencer la mutation
  • les routes bulk sont disponibles par API key avec le scope profiles:write

Endpoints

Lire son propre profil

EndpointAuthDescription
GET /profiles/meBearer SupabaseRetourne la ressource composite du user connecte

Exemple de reponse:

json
{
  "user": {
    "id": "f7a7d6ce-4fd8-4ca8-8f8d-5d9d4f6f9d8c",
    "email": "[email protected]",
    "lastSignInAt": "2026-04-04T08:30:00.000Z",
    "bannedUntil": null,
    "isArchived": false
  },
  "profile": {
    "id": 10,
    "uuid": "6a2e7e98-6fb4-4a5e-8a36-7f3b9899e5ec",
    "userId": "f7a7d6ce-4fd8-4ca8-8f8d-5d9d4f6f9d8c",
    "username": "jdoe",
    "firstname": "John",
    "lastname": "Doe",
    "matricule": "M-001",
    "address": "1 rue de Paris",
    "enterpriseId": 66,
    "photoId": null,
    "photoUrl": null,
    "roleId": 3,
    "job": "Nurse",
    "createdAt": "2026-04-04T08:30:00.000Z",
    "updatedAt": "2026-04-04T08:30:00.000Z",
    "role": {
      "id": 3,
      "name": "Utilisateur",
      "slug": "utilisateur"
    },
    "enterprise": {
      "id": 66,
      "name": "Heriade",
      "type": "enterprise"
    }
  }
}

Mettre a jour son profil

EndpointAuthDescription
PATCH /profiles/meBearer SupabaseMet a jour les champs profil autorises
POST /profiles/me/emailBearer SupabaseChange l'email du profil courant avec audit
POST /profiles/me/passwordBearer SupabaseChange le mot de passe du profil courant avec audit
POST /profiles/me/photoBearer SupabaseUpload multipart de la photo du profil courant
DELETE /profiles/me/photoBearer SupabaseSupprime la photo du profil courant
POST /profiles/me/enterpriseBearer Supabase super-admin uniquementChange l'entreprise courante du super-admin et purge ses rattachements metier

Payload autorise:

json
{
  "username": "jdoe",
  "firstname": "John",
  "lastname": "Doe",
  "matricule": "M-001",
  "address": "1 rue de Paris",
  "job": "Nurse",
  "organisationIds": [11, 12],
  "serviceIds": [21]
}

Upload photo:

  • champ multipart attendu: file
  • formats acceptes: JPG, PNG, WEBP
  • taille max: 5 Mo

Payload pour le changement d'entreprise courant:

json
{
  "enterpriseId": 66
}

Pour desaffecter l'entreprise courante:

json
{
  "enterpriseId": null
}

Contraintes:

  • endpoint reserve au super-admin
  • endpoint reserve a un bearer utilisateur; les API keys ne peuvent pas appeler /profiles/me/*
  • les scopes API key ne s'appliquent donc pas a cette route

Payload pour le changement d'email:

json
{
  "email": "[email protected]"
}

Payload pour le changement de mot de passe:

json
{
  "newPassword": "StrongPassword123!"
}

Lister les profils d'une entreprise

EndpointAuthDescription
GET /enterprises/:enterpriseId/profiles?page=1&pageSize=20Bearer SupabaseRetourne une liste paginee de ressources composites
GET /enterprises/:enterpriseId/profiles?page=1&pageSize=20&archived=falseBearer SupabaseRetourne uniquement les profils actifs
GET /enterprises/:enterpriseId/profiles?page=1&pageSize=20&archived=trueBearer SupabaseRetourne uniquement les profils archives

Reponse:

json
{
  "items": [],
  "page": 1,
  "pageSize": 20,
  "total": 0
}

Creer un utilisateur et son profil

EndpointAuthDescription
POST /enterprises/:enterpriseId/profilesBearer SupabaseCree auth.users puis profiles

Payload V1:

json
{
  "email": "[email protected]",
  "password": "StrongPassword123!",
  "username": "nuser",
  "firstname": "New",
  "lastname": "User",
  "matricule": "M-002",
  "address": "2 rue de Lyon",
  "photoId": null,
  "job": "Caregiver",
  "roleId": 3
}

Archiver ou supprimer plusieurs utilisateurs

EndpointAuthDescription
POST /profiles/bulk/archiveBearer Supabase ou API key profiles:writeArchive plusieurs profils gerables en une seule operation
POST /profiles/bulk/deleteBearer Supabase ou API key profiles:writeSupprime plusieurs profils gerables en une seule operation

Payload:

json
{
  "profileIds": [101, 103]
}

Reponse:

json
{
  "success": true,
  "count": 2
}

Regles de creation:

  • email et password sont obligatoires
  • roleId est autorise a la creation uniquement
  • un administrateur ne peut pas assigner le role super-admin
  • le quota enterprise.maxUsers est controle avant creation, hors comptes super-admin

Lire ou modifier un profil cible

EndpointAuthDescription
GET /profiles/:idBearer SupabaseRetourne un profil cible selon le perimetre autorise
PATCH /profiles/:idBearer SupabaseMet a jour un profil cible selon le perimetre autorise
POST /profiles/:id/emailBearer Supabase ou x-api-keyChange l'email d'un profil cible avec audit
POST /profiles/:id/passwordBearer Supabase ou x-api-keyChange le mot de passe d'un profil cible avec audit
POST /profiles/:id/roleBearer Supabase ou x-api-keyChange le role d'un profil cible avec audit
POST /profiles/:id/photoBearer SupabaseAjoute ou remplace une photo de profil cible
DELETE /profiles/:id/photoBearer SupabaseSupprime une photo de profil cible

Payload pour le changement de mot de passe cible:

json
{
  "newPassword": "StrongPassword123!"
}

Payload pour le changement de role:

json
{
  "roleId": 4
}

Archiver, desarchiver, supprimer

EndpointEffet
POST /profiles/:id/archiveMet a jour auth.users.banned_until
POST /profiles/:id/unarchiveRetire banned_until si le quota le permet
DELETE /profiles/:idSupprime auth.users, profiles, profiles_organisations, profiles_services et l'entreprise personnelle associee si presente

Pagination

La pagination s'applique sur:

  • GET /enterprises
  • GET /enterprises/:enterpriseId/profiles
ParametreDefautMax
page1n/a
pageSize20100

Filtre additionnel sur les profils:

ParametreValeursEffet
archivedtrue / falseFiltre les profils selon l'etat d'archivage (auth.users.banned_until)

Regles metier detaillees

Changement d'entreprise du super-admin

Quand un super-admin change d'entreprise courante:

  • son profile.enterprise_id est mis a jour
  • ses liaisons profiles_organisations sont supprimees
  • ses liaisons profiles_services sont supprimees
  • le front passe desormais par POST /profiles/me/enterprise, plus par des writes Supabase directes

Objectif:

  • eviter tout reliquat de contexte metier issu de l'entreprise precedente
  • garantir qu'un super-admin nouvellement rattache a une entreprise ne conserve aucun etablissement ou service personnel associe

Quota utilisateurs

Le backend controle enterprise.maxUsers:

  • a la creation d'un utilisateur
  • au desarchivage d'un utilisateur

Les comptes super-admin sont exclus du quota.

Validation des rattachements metier

Quand organisationIds et serviceIds sont fournis sur les endpoints de creation ou mise a jour profil:

  • chaque etablissement doit appartenir a l'entreprise du profil
  • chaque service doit appartenir a l'entreprise du profil
  • chaque service doit etre lie a au moins un des etablissements selectionnes
  • la synchronisation des tables profiles_organisations et profiles_services est faite par le backend

Stockage des photos

Les photos de profil sont stockees dans Supabase Storage.

  • bucket par defaut: profile-photos
  • variable backend: SUPABASE_PROFILE_PHOTOS_BUCKET
  • mode recommande: bucket prive
  • l'API genere une photoUrl signee a chaque lecture profil
  • profiles.photo_id stocke l'identifiant technique UUID de la photo
  • le chemin storage est derive par le backend sous la forme <user_id>/<photo_id>

Audit de changement d'email

Le changement d'email passe par un audit persistant dans public.profile_email_change_audits.

Chaque enregistrement contient notamment:

  • l'acteur (user ou api_key)
  • actor_user_id ou actor_api_key_id
  • actor_role_slug
  • target_profile_id
  • target_user_id
  • old_email
  • new_email
  • status (success ou failed)
  • error_message

Bonne pratique appliquee ici:

  • ne pas lier fortement cette table aux comptes utilisateurs pour conserver l'historique meme si le createur ou la cible sont supprimes plus tard

Audit de changement de role

Le changement de role passe par un audit persistant dans public.profile_role_change_audits.

Chaque enregistrement contient notamment:

  • l'acteur (user ou api_key)
  • actor_user_id ou actor_api_key_id
  • actor_role_slug
  • target_profile_id
  • target_user_id
  • old_role_id
  • old_role_slug
  • new_role_id
  • new_role_slug
  • status (success ou failed)
  • error_message

Audit de changement de mot de passe

Le changement de mot de passe passe par un audit persistant dans public.profile_password_change_audits.

Chaque enregistrement contient notamment:

  • l'acteur (user ou api_key)
  • actor_user_id ou actor_api_key_id
  • actor_role_slug
  • target_profile_id
  • target_user_id
  • status (success ou failed)
  • error_message

Important:

  • aucun mot de passe en clair n'est journalise
  • l'audit trace seulement qui a change le mot de passe de quel profil, et avec quel resultat

Archivage

L'archivage n'est pas une suppression logique dans profiles.

Le mecanisme retenu est:

  • ecriture sur auth.users.banned_until
  • calcul de isArchived dans la reponse backend

Suppression definitive

La suppression est destructive et suit cet ordre:

  1. suppression des relations profiles_organisations
  2. suppression des relations profiles_services
  3. suppression des lignes profiles
  4. suppression du compte auth.users
  5. suppression de l'entreprise personnelle si elle existe encore

Reaffectation d'etablissements

Quand un utilisateur est rattache a un autre ensemble d'etablissements dans le formulaire console:

  • les service_ids du formulaire sont reinitialises
  • l'operateur doit reselectionner explicitement les services compatibles

Cette regle est volontairement stricte:

  • elle evite de conserver des services devenus invalides apres un changement d'etablissements
  • elle rend la reaffectation explicite au lieu de tenter une conservation partielle implicite

Flux technique

text
Bearer Supabase
  -> SupabaseAuthGuard
  -> RolesGuard
  -> ProfilesController
  -> ProfilesService
    -> controle role + entreprise
    -> lecture/ecriture profiles
    -> lecture/ecriture auth.users admin
    -> controle quota si creation ou desarchivage

Tests

NiveauFichierCouverture
Unitaireback/src/profiles/profiles.service.spec.tspagination, perimetre entreprise, auto-archivage interdit
Integrationback/src/profiles/profiles.integration.spec.tsguards reels, /profiles/me, listing entreprise, blocage utilisateur
E2E consoleconsole/e2e/utilisateurs.spec.tspurge des affectations du super-admin au changement d'entreprise, reinitialisation des services lors d'un changement d'etablissements

Points de vigilance

  • le front n'utilise pas encore ces endpoints
  • organisation_ids et service_ids ne sont pas exposes dans cette V1 backend
  • le changement de mot de passe et le changement de role restent separes des updates profil generiques