---
name: controller
description: |
  Génère automatiquement des controllers API pour SmartStack.
  Utiliser ce skill quand:
  - L'utilisateur demande de créer un controller, endpoint, ou API
  - L'utilisateur mentionne "CRUD", "REST API", "endpoint"
  - L'utilisateur veut ajouter des actions à un module existant
  - Après création d'une entité Domain pour exposer via API
  Types: CRUD standard, Auth/Login, Custom actions
---

## STRATÉGIE MODÈLES (Qualité Maximale)

| Phase | Modèle | Coût estimé |
|-------|--------|-------------|
| Génération complète | **Sonnet** | ~$0.19 |
| Validation sécurité | **Opus** | ~$0.10 |
| **Total** | | **~$0.29** |

> **Note:** Si vous utilisez Opus pour tout, le skill fonctionne parfaitement
> mais coûte ~$0.94/controller. Sonnet offre le meilleur rapport qualité/coût
> pour la génération, Opus pour l'audit sécurité final.

---

# Skill Controller SmartStack

> **Synergie Skill/Commande:**
> - **Skill** (`.claude/skills/controller/`) → Invocation automatique par Claude
> - **Commande** (`/controller:create`) → Invocation manuelle par l'utilisateur
> - Templates partagés dans `.claude/skills/controller/templates.md`

## QUAND CE SKILL S'ACTIVE

Claude invoque automatiquement ce skill quand il détecte :

| Déclencheur | Exemple |
|-------------|---------|
| Demande explicite | "Crée un controller pour les tickets" |
| Mention d'API | "Il faut exposer les SLA via REST" |
| Après entité Domain | "L'entité est prête, génère l'API" |
| Mots-clés | "CRUD", "endpoint", "controller", "API REST" |

---

## WORKFLOW AUTOMATIQUE

### ÉTAPE 1: DÉTECTION DU TYPE

| Indice | → Type |
|--------|--------|
| Authentification, login, session | `auth` |
| Module avec CRUD complet | `crud` |
| Actions spécifiques seulement | `custom` |

### ÉTAPE 2: EXTRACTION DES PARAMÈTRES

| Paramètre | Source | Exemple |
|-----------|--------|---------|
| `$AREA` | Contexte navigation | `Admin`, `Support`, `Business`, `User` |
| `$MODULE` | Nom du module | `Tickets`, `Sla`, `Users` |
| `$ENTITY` | Entité Domain | `Ticket`, `SlaDefinition`, `User` |
| `$PERMISSION_PATH` | Hiérarchie | `platform.support.tickets` |

### ÉTAPE 3: EXÉCUTION

Suivre le workflow de la commande `/controller:create`

### ÉTAPE 4: SYNCHRONISATION BASE DE DONNÉES (OBLIGATOIRE)

> **CRITIQUE:** Un controller avec `[RequirePermission]` retournera **403 Forbidden** pour TOUS les utilisateurs si la permission n'existe pas dans la base de données.

#### 4.1 Fichiers à synchroniser

| Fichier | Rôle | Action |
|---------|------|--------|
| `Permissions.cs` | Constantes code | Ajouter la classe de permissions |
| `PermissionConfiguration.cs` | Seed EF Core | Ajouter les entrées HasData |

#### 4.2 Workflow obligatoire

```
┌──────────────────────────────────────────────────────────────────────────────┐
│                     WORKFLOW SYNCHRONISATION PERMISSIONS                     │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  1. GÉNÉRER CONTROLLER                                                       │
│     └─→ [RequirePermission(Permissions.{Module}.View)]                       │
│                                                                              │
│  2. AJOUTER À Permissions.cs (Application layer)                             │
│     └─→ public static class {Module} { ... }                                 │
│                                                                              │
│  3. AJOUTER À PermissionConfiguration.cs (Infrastructure layer)              │
│     └─→ HasData(new { Path = "...", ModuleId = ..., ... })                   │
│                                                                              │
│  4. CRÉER MIGRATION EF CORE                                                  │
│     └─→ /efcore:migration Add{Module}Permissions                             │
│                                                                              │
│  5. VALIDER COHÉRENCE                                                        │
│     └─→ Vérifier que TOUS les paths dans Permissions.cs                      │
│         existent dans PermissionConfiguration.cs                             │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
```

#### 4.3 Template PermissionConfiguration.cs

Voir le template complet dans [templates.md](templates.md#template-permissionconfiguration-seed)

#### 4.4 Checklist de validation

```
□ Permissions.cs contient la classe {Module} avec View/Create/Update/Delete
□ PermissionConfiguration.cs contient les entrées HasData correspondantes
□ Les paths sont identiques entre les deux fichiers
□ Le ModuleId référence un module existant dans ModuleConfiguration.cs
□ Migration créée avec /efcore:migration
□ Migration appliquée avec /efcore:db-deploy
```

---

## RÈGLES ABSOLUES - SÉCURITÉ

### 1. Logs Critiques (OBLIGATOIRE)

| Événement | Niveau | Pattern |
|-----------|--------|---------|
| Login échoué | `Critical` | `LogCritical("Login attempt on locked account...")` |
| Permission refusée | `Critical` | Auto via `SecurityAuditMiddleware` |
| Compte verrouillé | `Critical` | `LogCritical("Account locked...")` |
| Password change | `Warning` | `LogWarning("Password changed...")` |
| Création/MAJ | `Information` | `LogInformation("User {User} creating...")` |
| Suppression | `Warning` | `LogWarning("User {User} deleting...")` |

### 2. Protection Comptes Système (OBLIGATOIRE)

```csharp
// TOUJOURS vérifier avant modification d'entité User-related
if (entity.UserType == UserType.System || entity.UserType == UserType.LocalAdmin)
    return BadRequest(new { message = "Cannot modify system accounts" });
```

### 3. Permissions (OBLIGATOIRE)

```csharp
// TOUJOURS utiliser les constantes Permissions.*
[RequirePermission(Permissions.Support.Tickets.View)]  // ✅ Correct
[RequirePermission("platform.support.tickets.read")]   // ❌ Éviter strings
```

### 4. Cache Invalidation (SI rôles/permissions)

```csharp
// Après modification de rôle ou permission
await _permissionService.InvalidateUserPermissionsCacheAsync(userId, ct);
```

---

## RÉFÉRENCE RAPIDE

### Services à Injecter

| Service | Usage | Obligatoire |
|---------|-------|-------------|
| `IApplicationDbContext` | Accès DB | ✅ Toujours |
| `ICurrentUserService` | User courant | ✅ Toujours |
| `ILogger<T>` | Logging | ✅ Toujours |
| `IPermissionService` | Cache permissions | Si roles/permissions |
| `IPasswordService` | Hash passwords | Si auth |
| `IJwtService` | Tokens JWT | Si auth |
| `IUserSessionService` | Sessions | Si auth |
| `INotificationService` | Notifications | Si notifications |

### ProducesResponseType (OBLIGATOIRE)

```csharp
[ProducesResponseType(typeof(ItemDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]  // Si [Authorize]
[ProducesResponseType(StatusCodes.Status403Forbidden)]     // Si [RequirePermission]
[ProducesResponseType(StatusCodes.Status404NotFound)]      // Si GET by ID
[ProducesResponseType(StatusCodes.Status400BadRequest)]    // Si validation
[ProducesResponseType(StatusCodes.Status409Conflict)]      // Si unique constraint
```

---

## USER PATH TRACKING

> **IMPORTANT:** Le tracking du chemin utilisateur est géré par **infrastructure**, pas par les controllers.

### Middleware Existant

`ApplicationAccessTrackingMiddleware` track automatiquement :
- ✅ UserId, ApplicationId, ModuleId
- ✅ IP Address, User Agent, Device Type
- ✅ AccessedAt (timestamp)

### Enrichissement Recommandé (Séparé)

Pour tracker le **temps passé** sur chaque module :

```csharp
// Dans ApplicationAccess entity - AJOUTER :
public DateTime? LeftAt { get; private set; }
public TimeSpan? Duration => LeftAt.HasValue ? LeftAt - AccessedAt : null;

// Dans middleware - AJOUTER :
// 1. Au début de requête: créer/identifier session
// 2. À la fin de requête: calculer durée ou marquer "navigation away"
```

→ Ceci est un **enhancement infrastructure**, pas un controller concern.

---

## TESTS POSTMAN

Chaque controller doit avoir des tests couvrant :

| Test | User | Status Attendu |
|------|------|----------------|
| GET list | SuperAdmin | 200 |
| GET list | NoPerm | 403 |
| GET list | Anonymous | 401 |
| POST create | ReadOnly | 403 |
| POST create | WithPerm | 201 |
| DELETE | ReadOnly | 403 |

→ Templates dans `postman-templates.md`

---

## FICHIERS ASSOCIÉS

- **Templates Controller:** [templates.md](templates.md)
- **Templates Postman:** [postman-templates.md](postman-templates.md)
- **Commande complète:** `.claude/commands/controller-create.md`
