Utilisateurs (Admin)
Caffette distingue deux niveaux d'utilisateurs :
| Niveau | Portée | Rôle type |
|---|---|---|
| N2 — Plateforme | Cross-organisation | Administrateur plateforme, support |
| N1 — Organisation | Périmètre d'une seule organisation | Gestionnaire, caissier, vendeur |
Utilisateurs plateforme (N2)
Utilisateurs ayant accès à l'interface d'administration système (/admin/system/*). Ils ne sont pas rattachés à une organisation spécifique.
Permissions requises : platform.user.manage
Base URL : /api/v1/admin/system/users
GET /admin/system/users
Liste paginée des utilisateurs plateforme.
| Param | Type | Description |
|---|---|---|
limit | integer | Éléments par page (défaut: 20) |
offset | integer | Décalage (défaut: 0) |
Réponse :
{
"items": [
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"email": "admin@caffette.app",
"display_name": "Admin Global",
"is_active": true,
"last_login_at": "2025-06-15T08:00:00Z",
"created_at": "2025-01-01T00:00:00Z",
"roles": [
{
"id": "uuid",
"name": "Platform Admin",
"description": "Accès complet à toutes les organisations"
}
]
}
],
"total": 3
}
Les rôles sont résolus en une seule requête batch pour tous les utilisateurs de la page (pas de N+1).
POST /admin/system/users
Créer un utilisateur plateforme.
{
"email": "ops@caffette.app",
"password": "s3cur3P@ss123",
"display_name": "Opérateur Plateforme"
}
Le mot de passe est hashé avec PasswordService::hash() (bcrypt/argon2) avant insertion.
Réponse (201) :
{
"message": "Utilisateur créé",
"user": {
"id": "uuid",
"email": "ops@caffette.app",
"display_name": "Opérateur Plateforme"
}
}
GET /admin/system/users/{id}
Détails d'un utilisateur plateforme. Retourne l'objet PlatformUser complet.
PUT /admin/system/users/{id}
Mettre à jour un utilisateur plateforme.
{
"display_name": "Opérateur Plateforme Senior",
"password": "nouveauMotDePasse"
}
| Champ | Type | Description |
|---|---|---|
display_name | string | Nouveau nom d'affichage (optionnel) |
password | string | Nouveau mot de passe (optionnel, hashé avant stockage) |
DELETE /admin/system/users/{id}
Supprimer un utilisateur plateforme.
POST /admin/system/users/{id}/roles
Assigner un rôle à un utilisateur plateforme.
{
"role_id": "550e8400-e29b-41d4-a716-446655440010"
}
DELETE /admin/system/users/{id}/roles/{role_id}
Retirer un rôle d'un utilisateur plateforme.
Utilisateurs organisation (N1)
Utilisateurs d'une organisation spécifique. Chaque utilisateur est isolé dans son organisation via le search_path tenant.
Permissions : user.read, user.create, user.update, user.delete
Base URL : /api/v1/admin/org/users
GET /admin/org/users
Liste paginée des utilisateurs de l'organisation.
| Param | Type | Description |
|---|---|---|
limit | integer | Éléments par page (défaut: 20) |
offset | integer | Décalage (défaut: 0) |
Réponse :
{
"items": [
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"login": "jdupont",
"display_name": "Jean Dupont",
"email": "jean@courslumiere.com",
"phone": "+22890123456",
"code": "AG001",
"is_active": true,
"last_login_at": "2025-06-14T09:30:00Z",
"created_at": "2025-01-15T10:00:00Z",
"roles": [
{
"id": "uuid",
"name": "Caissier",
"description": "Peut encaisser les ventes"
}
]
}
],
"total": 15
}
Les rôles sont résolus en batch comme pour les utilisateurs plateforme.
POST /admin/org/users
Créer un utilisateur organisation.
{
"login": "jsmith",
"password": "s3cur3P@ss",
"display_name": "John Smith",
"email": "john@courslumiere.com",
"phone": "+22890987654"
}
| Champ | Type | Requis | Description |
|---|---|---|---|
login | string | Oui | Identifiant de connexion unique dans l'org |
password | string | Oui | Mot de passe (hashé avant stockage) |
display_name | string | Oui | Nom d'affichage |
email | string | Non | Email de l'utilisateur |
phone | string | Non | Téléphone |
Un code agent (AGxxx) est automatiquement généré à la création via la fonction generate_code().
Le code d'agent suit le format AG + séquence (ex: AG001, AG002). Il est utilisé comme identifiant court pour les opérations en caisse.
Réponse (201) :
{
"message": "Utilisateur créé",
"user": {
"id": "uuid",
"login": "jsmith",
"display_name": "John Smith",
"email": "john@courslumiere.com",
"phone": "+22890987654",
"code": "AG002",
"is_active": true,
"created_at": "2025-07-01T10:00:00Z"
}
}
GET /admin/org/users/{id}
Détails d'un utilisateur avec ses rôles.
Réponse :
{
"id": "uuid",
"login": "jdupont",
"display_name": "Jean Dupont",
"email": "jean@courslumiere.com",
"phone": "+22890123456",
"code": "AG001",
"is_active": true,
"last_login_at": "2025-06-14T09:30:00Z",
"created_at": "2025-01-15T10:00:00Z",
"roles": [
{
"id": "uuid",
"name": "Caissier",
"description": "Peut encaisser les ventes"
}
]
}
PUT /admin/org/users/{id}
Mettre à jour un utilisateur. Tous les champs sont optionnels.
{
"login": "jdupont2",
"display_name": "Jean Dupont",
"email": "jean.nouveau@courslumiere.com",
"phone": "+22890987654"
}
Réponse :
{
"message": "Utilisateur mis à jour",
"user": {
"id": "uuid",
"login": "jdupont2",
"display_name": "Jean Dupont",
"email": "jean.nouveau@courslumiere.com",
"phone": "+22890987654",
"is_active": true,
"created_at": "2025-01-15T10:00:00Z"
}
}
DELETE /admin/org/users/{id}
Désactiver un utilisateur. Il s'agit d'une désactivation logique (soft-delete) : le compte passe is_active = false mais l'enregistrement est conservé.
Un événement d'audit user.deactivated est journalisé.
Réponse :
{
"message": "Utilisateur désactivé"
}
POST /admin/org/users/{id}/activate
Réactive un utilisateur précédemment désactivé.
Permissions : user.update
Réponse :
{
"message": "Utilisateur réactivé"
}
POST /admin/org/users/{id}/reset-password
Réinitialise le mot de passe d'un utilisateur. Retourne le nouveau mot de passe en clair et force son changement à la prochaine connexion.
Permissions : user.update
Réponse :
{
"password": "a1b2c3d4e5f6"
}
POST /admin/org/users/{id}/roles
Assigner un rôle à un utilisateur, optionnellement limité à un site spécifique.
{
"role_id": "550e8400-e29b-41d4-a716-446655440010",
"site_id": "550e8400-e29b-41d4-a716-446655440020"
}
| Champ | Type | Requis | Description |
|---|---|---|---|
role_id | uuid | Oui | Identifiant du rôle |
site_id | uuid | Non | Scope du rôle à un site spécifique |
Un événement d'audit user.role_assigned est journalisé avec le role_id et le site_id.
Réponse :
{
"message": "Rôle assigné"
}
DELETE /admin/org/users/{id}/roles/{role_id}
Retirer un rôle d'un utilisateur.
Cycle de vie d'un utilisateur organisation
flowchart LR
A[Création: POST /users] --> B{Actif}
B -->|Opérations quotidiennes| C[Connexion / Caisses]
B -->|Désactivation| D[DELETE /users/{id}]
D --> E[Désactivé is_active=false]
E -->|Peut être réactivé| B
Bonnes pratiques
- Login : Choisissez un login unique et mémorisable (ex:
jdupont,jsmith). Il sert d'identifiant principal pour la connexion. - Code agent : Le code auto-généré (
AG001) est l'identifiant court utilisé dans les tickets de caisse et les rapports. - Rôles : Un utilisateur peut avoir plusieurs rôles, éventuellement sur des sites différents. Par exemple, "Caissier" sur le site A et "Superviseur" sur le site B.
- Désactivation : Préférez la désactivation à la suppression pour conserver la traçabilité historique des transactions.