# Users

Ce répertoire gère les utilisateurs, l'authentification par identifiants, les sessions, les rôles et les permissions. Il constitue la couche de données auth du projet : les features l'appellent, il ne connaît pas les features.

---

## Structure

```
src/core/users/
├── index.js          re-exports publics
├── auth.js           register, login, mot de passe, vérification email
├── session.js        création, validation, suppression de sessions
├── queries.js        lecture et mise à jour des utilisateurs
├── roles.js          CRUD des rôles, assignation aux utilisateurs
├── permissions.js    hasPermission, getUserPermissions
├── constants.js      PERMISSIONS, PERMISSION_DEFINITIONS, getPermissionGroups
├── verifications.js  tokens de vérification email et de réinitialisation
├── emailChange.js    tokens de changement d'adresse email
├── password.js       hashPassword, verifyPassword, generateToken, generateId
└── db.js             helpers internes
```

---

## Import

```js
import {
  register, login, requestPasswordReset, resetPassword, verifyUserEmail, updateUser,
  createSession, validateSession, deleteSession, deleteUserSessions, refreshSession,
  getUserById, getUserByEmail, countUsers, listUsers, updateUserById,
  createRole, updateRole, deleteRole, listRoles, getRoleById,
  getUserRoles, assignUserRole, revokeUserRole,
  hasPermission, getUserPermissions,
  PERMISSIONS, PERMISSION_DEFINITIONS, getPermissionGroups,
  hashPassword, verifyPassword, generateToken, generateId,
} from '@zen/core/users';
```

---

## API

### `register(userData, options?)`

Crée un compte utilisateur avec vérification des contraintes mot de passe. Le premier utilisateur enregistré reçoit le rôle `admin`. Retourne `{ user, verificationToken }`.

```js
const { user, verificationToken } = await register(
  { email: 'alice@example.com', password: 'Secret1', name: 'Alice' },
  {
    onEmailVerification: async (email, token) => {
      await sendVerificationEmail({ to: email, token });
    },
  }
);
```

| Paramètre | Type | Description |
|-----------|------|-------------|
| `email` | `string` | Adresse email (max 254 caractères) |
| `password` | `string` | Mot de passe (8-128 caractères, au moins 1 majuscule, 1 minuscule, 1 chiffre) |
| `name` | `string` | Nom affiché (max 100 caractères) |
| `onEmailVerification` | `async (email, token) => void` | Callback pour envoyer le token de vérification |

---

### `login(credentials, sessionOptions?)`

Vérifie les identifiants et crée une session. Retourne `{ user, session }`. Lève une erreur si les identifiants sont incorrects.

```js
const { user, session } = await login(
  { email: 'alice@example.com', password: 'Secret1' },
  { ipAddress: req.ip, userAgent: req.headers['user-agent'] }
);
```

---

### `requestPasswordReset(email)`

Génère un token de réinitialisation (expire dans 1 heure). Retourne `{ success: true, token }` même si l'email est inconnu, pour éviter l'énumération.

```js
const { token } = await requestPasswordReset('alice@example.com');
```

---

### `resetPassword(data, options?)`

Valide le token et met à jour le mot de passe. Retourne `{ success: true }`.

```js
await resetPassword(
  { email: 'alice@example.com', token, newPassword: 'NewSecret1' },
  { onPasswordChanged: async (email) => { /* envoyer confirmation */ } }
);
```

---

### `verifyUserEmail(userId)`

Marque l'email de l'utilisateur comme vérifié.

```js
await verifyUserEmail(user.id);
```

---

### `updateUser(userId, data)`

Met à jour les champs autorisés du profil : `name`, `image`, `language`.

```js
await updateUser(user.id, { name: 'Alice Martin' });
```

---

### `createSession(userId, options?)`

Crée une session valide 30 jours. Retourne l'objet session.

```js
const session = await createSession(user.id, { ipAddress: '127.0.0.1', userAgent: '...' });
```

---

### `validateSession(token)`

Valide un token de session. Renouvelle automatiquement la session si elle expire dans moins de 20 jours. Retourne `{ session, user, sessionRefreshed }` ou `null`.

```js
const result = await validateSession(token);
if (!result) {
  // session expirée ou invalide
}
```

---

### `deleteSession(token)` / `deleteUserSessions(userId)`

Supprime une session ou toutes les sessions d'un utilisateur.

```js
await deleteSession(token);
await deleteUserSessions(user.id);
```

---

### `getUserById(id)` / `getUserByEmail(email)`

Récupère un utilisateur par son id ou son email.

```js
const user = await getUserById('abc123');
const user = await getUserByEmail('alice@example.com');
```

---

### `listUsers(options?)`

Liste les utilisateurs avec pagination et tri. Retourne `{ users, pagination }`.

```js
const { users, pagination } = await listUsers({ page: 1, limit: 20, sortBy: 'created_at', sortOrder: 'desc' });
```

| Paramètre | Défaut | Description |
|-----------|--------|-------------|
| `page` | `1` | Page courante |
| `limit` | `10` | Résultats par page (max 100) |
| `sortBy` | `'created_at'` | Colonne de tri (`id`, `email`, `name`, `role`, `email_verified`, `created_at`) |
| `sortOrder` | `'desc'` | `'asc'` ou `'desc'` |

---

### `updateUserById(id, fields)`

Met à jour les champs autorisés d'un utilisateur : `name`, `role`, `email_verified`, `image`, `language`.

```js
await updateUserById(user.id, { role: 'editor', email_verified: true });
```

---

### Rôles

```js
const roles = await listRoles();
const role = await getRoleById(id);

const role = await createRole({ name: 'Modérateur', description: 'Peut gérer les utilisateurs', color: '#3b82f6' });

await updateRole(roleId, {
  name: 'Modérateur',
  permissionKeys: [PERMISSIONS.USERS_VIEW, PERMISSIONS.USERS_MANAGE],
});

await deleteRole(roleId); // impossible sur les rôles système

const userRoles = await getUserRoles(userId);
await assignUserRole(userId, roleId);
await revokeUserRole(userId, roleId);
```

Les rôles système (`is_system = true`) peuvent être renommés mais leurs permissions ne peuvent pas être modifiées. Ils ne peuvent pas être supprimés.

L'endpoint `DELETE /zen/api/users/:id/roles/:roleId` applique une règle de sécurité supplémentaire : un utilisateur ne peut pas se retirer un rôle qui lui accorde `users.manage` s'il n'en a pas d'autre. Cela évite qu'un administrateur se retrouve dans l'impossibilité de se redonner la permission. Cette vérification est faite au niveau du handler API et ne concerne pas la fonction `revokeUserRole` elle-même.

---

### Permissions

```js
const canManageRoles = await hasPermission(userId, PERMISSIONS.ROLES_MANAGE);
const keys = await getUserPermissions(userId);
```

`PERMISSIONS` contient toutes les clés disponibles. `PERMISSION_DEFINITIONS` expose le label, la description et le groupe de chaque permission. `getPermissionGroups()` retourne les permissions regroupées par `group_name`.

| Groupe | Clés |
|--------|------|
| Administration | `admin.access` |
| Utilisateurs | `users.view`, `users.manage` |
| Rôles | `roles.view`, `roles.manage` |

---

### Changement d'email

```js
import { createEmailChangeToken, verifyEmailChangeToken, applyEmailChange } from '@zen/core/users/emailChange';

const token = await createEmailChangeToken(userId, 'new@example.com');

// Plus tard, lors de la confirmation :
const result = await verifyEmailChangeToken(token);
if (result) {
  await applyEmailChange(result.userId, result.newEmail);
}
```

Le token expire dans 24 heures. `verifyEmailChangeToken` retourne `null` si le token est invalide ou expiré.

---

## Gestion des erreurs

`register`, `login`, `resetPassword` lèvent des erreurs typées (`Error`) avec des messages en français. Les fonctions de requête (`getUserById`, etc.) retournent `null` si l'entrée n'existe pas. Les callbacks `onEmailVerification` et `onPasswordChanged` sont exécutés sans bloquer le flux principal : une erreur dans le callback est loguée mais n'interrompt pas l'opération.

---

## Tables utilisées

| Table | Description |
|-------|-------------|
| `zen_auth_users` | Comptes utilisateurs |
| `zen_auth_accounts` | Identifiants par provider (`credential`) |
| `zen_auth_sessions` | Sessions actives |
| `zen_auth_verifications` | Tokens de vérification email, reset mot de passe, changement email |
| `zen_auth_roles` | Rôles |
| `zen_auth_role_permissions` | Permissions associées aux rôles |
| `zen_auth_user_roles` | Rôles assignés aux utilisateurs |
