# Système de Permissions du Chat Server

## Vue d'ensemble

Le système de permissions du chat server Veza fournit un contrôle d'accès granulaire pour les conversations, avec support des rôles (admin, moderator, member) et vérifications centralisées.

## Architecture

### Module `security/permission.rs`

Le module `PermissionService` centralise toutes les vérifications de permissions :

```rust
pub struct PermissionService {
    pool: PgPool,
}
```

### Fonctions principales

#### `user_in_conversation(user_id, conversation_id) -> Result<bool>`

Vérifie si un utilisateur est membre d'une conversation.

**Retourne** : `true` si membre, `false` sinon.

#### `user_role_in_conversation(user_id, conversation_id) -> Result<Role>`

Récupère le rôle d'un utilisateur dans une conversation spécifique.

**Retourne** : Le rôle (`Admin`, `Moderator`, `User`, `SuperAdmin`) ou une erreur si non membre.

#### `user_global_role(user_id) -> Result<Role>`

Récupère le rôle global d'un utilisateur depuis la table `users`.

**Retourne** : Le rôle global, ou `User` par défaut.

#### `can_send_message(user_id, conversation_id) -> Result<()>`

Vérifie si un utilisateur peut envoyer un message dans une conversation.

**Règles** :
- Les membres peuvent envoyer des messages
- Les admins globaux peuvent envoyer des messages même sans être membres
- Les non-membres (non-admin) sont refusés

#### `can_read_conversation(user_id, conversation_id) -> Result<()>`

Vérifie si un utilisateur peut lire une conversation.

**Règles** :
- Les membres peuvent lire
- Les admins globaux peuvent lire même sans être membres
- Les non-membres (non-admin) sont refusés

#### `can_mark_read(user_id, conversation_id) -> Result<()>`

Vérifie si un utilisateur peut marquer un message comme lu.

**Règles** : Identiques à `can_read_conversation`.

#### `can_join_conversation(user_id, conversation_id) -> Result<()>`

Vérifie si un utilisateur peut rejoindre une conversation.

**Règles** :
- Les conversations publiques peuvent être rejointes par tous
- Les conversations privées nécessitent d'être membre ou admin global

## Rôles et Permissions

### Rôles disponibles

| Rôle | Description |
|------|-------------|
| `User` | Utilisateur standard |
| `Moderator` | Modérateur avec permissions étendues |
| `Admin` | Administrateur avec tous les pouvoirs |
| `SuperAdmin` | Super administrateur |

### Matrice des permissions

| Action | User | Moderator | Admin | SuperAdmin |
|--------|------|-----------|-------|------------|
| Envoyer message (membre) | ✅ | ✅ | ✅ | ✅ |
| Envoyer message (non-membre) | ❌ | ❌ | ✅ | ✅ |
| Lire conversation (membre) | ✅ | ✅ | ✅ | ✅ |
| Lire conversation (non-membre) | ❌ | ❌ | ✅ | ✅ |
| Marquer comme lu | ✅ | ✅ | ✅ | ✅ |
| Rejoindre conversation publique | ✅ | ✅ | ✅ | ✅ |
| Rejoindre conversation privée | ❌* | ❌* | ✅ | ✅ |

\* Nécessite d'être membre de la conversation

## Intégration dans les Handlers

### WebSocket Handler (`websocket/handler.rs`)

Tous les handlers WebSocket vérifient les permissions avant d'exécuter les actions :

#### `SendMessage`

```rust
// Vérifier les permissions avant d'envoyer le message
state
    .permission_service
    .can_send_message(sender_uuid, conversation_id)
    .await?;
```

#### `JoinConversation`

```rust
// Vérifier les permissions avant de rejoindre
state
    .permission_service
    .can_join_conversation(user_uuid, conversation_id)
    .await?;
```

#### `MarkAsRead`

```rust
// Vérifier les permissions pour marquer comme lu
state
    .permission_service
    .can_mark_read(user_uuid, conversation_id)
    .await?;
```

### Message Handler (`message_handler.rs`)

Les handlers de messages vérifient également les permissions :

#### `handle_room_message`

Vérifie `can_send_message` avant d'envoyer un message dans un salon.

#### `handle_direct_message`

Vérifie `can_send_message` avant d'envoyer un message direct.

#### `handle_room_history`

Vérifie `can_read_conversation` via `can_read_room_history`.

#### `handle_dm_history`

Vérifie `can_read_conversation` via `can_read_dm_conversation`.

## Schéma de Base de Données

### Table `conversation_members`

```sql
CREATE TABLE conversation_members (
    conversation_id UUID REFERENCES conversations(id) ON DELETE CASCADE,
    user_id UUID REFERENCES users(id) ON DELETE CASCADE,
    role VARCHAR(50) NOT NULL DEFAULT 'user',
    joined_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    PRIMARY KEY (conversation_id, user_id)
);
```

**Colonne `role`** : Peut être `'user'`, `'moderator'`, `'admin'`, ou `'superadmin'`.

### Table `users`

```sql
CREATE TABLE users (
    id UUID PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    role VARCHAR(20) DEFAULT 'user',  -- Rôle global
    ...
);
```

**Colonne `role`** : Rôle global de l'utilisateur dans le système.

## Gestion des Erreurs

### Types d'erreurs

#### `PermissionError::NotMember`

L'utilisateur n'est pas membre de la conversation.

**Code HTTP** : 403 Forbidden

#### `PermissionError::InsufficientPermissions`

L'utilisateur n'a pas les permissions suffisantes pour l'action.

**Code HTTP** : 403 Forbidden

#### `PermissionError::InvalidRole`

Le rôle spécifié est invalide.

**Code HTTP** : 500 Internal Server Error

### Logging

Toutes les violations de permissions sont loggées avec `tracing::warn!` :

```rust
warn!(
    user_id = %user_id,
    conversation_id = %conversation_id,
    error = %e,
    "Permission refusée pour l'envoi de message"
);
```

## Messages WebSocket d'Erreur

Lorsqu'une permission est refusée, le client reçoit un message d'erreur :

```json
{
  "type": "error",
  "message": "Permission refusée: Utilisateur non membre de la conversation",
  "code": "permission_denied"
}
```

## JWT Manager

Le `JwtManager` a été mis à jour pour récupérer les informations utilisateur depuis la base de données lors du refresh token :

```rust
// Récupérer username et role depuis la DB
let user_info: Option<(String, Option<String>)> = sqlx::query_as(
    r#"
    SELECT username, role FROM users
    WHERE id = $1
    "#,
)
.bind(user_uuid)
.fetch_optional(pool)
.await?;
```

**Fallback** : Si l'utilisateur n'est pas trouvé ou si le pool DB n'est pas disponible, utilise `"user"` / `"user"` par défaut (avec warning).

## Tests

Les tests sont disponibles dans `tests/test_permissions.rs` :

- `test_can_send_message_non_member` : Vérifie qu'un non-membre ne peut pas envoyer
- `test_can_send_message_member` : Vérifie qu'un membre peut envoyer
- `test_can_send_message_admin_global` : Vérifie qu'un admin global peut envoyer sans être membre
- `test_can_read_conversation_non_member` : Vérifie qu'un non-membre ne peut pas lire
- `test_can_read_conversation_member` : Vérifie qu'un membre peut lire
- `test_user_in_conversation` : Vérifie la fonction `user_in_conversation`
- `test_user_role_in_conversation` : Vérifie la fonction `user_role_in_conversation`
- `test_integration_send_message_with_permissions` : Test d'intégration complet

**Note** : Les tests nécessitent une base de données de test et sont marqués avec `#[ignore]`.

## Exemples d'utilisation

### Vérifier les permissions avant d'envoyer un message

```rust
use chat_server::security::permission::PermissionService;

let permission_service = PermissionService::new(pool);

// Vérifier avant d'envoyer
permission_service
    .can_send_message(user_id, conversation_id)
    .await?;

// Envoyer le message...
```

### Vérifier les permissions avant de lire

```rust
// Vérifier avant de lire
permission_service
    .can_read_conversation(user_id, conversation_id)
    .await?;

// Récupérer les messages...
```

### Récupérer le rôle d'un utilisateur

```rust
// Rôle dans une conversation spécifique
let role = permission_service
    .user_role_in_conversation(user_id, conversation_id)
    .await?;

// Rôle global
let global_role = permission_service
    .user_global_role(user_id)
    .await?;
```

## Sécurité

### Bonnes pratiques

1. **Toujours vérifier les permissions** avant d'exécuter une action
2. **Logger les violations** pour audit et monitoring
3. **Ne jamais faire confiance au client** : toutes les vérifications sont côté serveur
4. **Utiliser le service centralisé** : ne pas dupliquer la logique de vérification
5. **Gérer les erreurs gracieusement** : envoyer des messages d'erreur clairs au client

### Points d'attention

- Les admins globaux peuvent contourner certaines restrictions (par design)
- Les conversations privées nécessitent une vérification explicite d'appartenance
- Le rôle dans `conversation_members` peut différer du rôle global dans `users`

## Évolution future

- Support de permissions custom par conversation
- Permissions granulaires (edit, delete, pin, etc.)
- Système de rôles hiérarchiques
- Permissions temporaires (time-based)
- Audit trail des changements de permissions

