@atlashub/smartstack-cli 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/.documentation/agents.html +8 -4
  2. package/.documentation/apex.html +8 -4
  3. package/.documentation/business-analyse.html +833 -406
  4. package/.documentation/commands.html +8 -4
  5. package/.documentation/css/styles.css +153 -15
  6. package/.documentation/efcore.html +8 -4
  7. package/.documentation/gitflow.html +795 -230
  8. package/.documentation/hooks.html +8 -4
  9. package/.documentation/index.html +13 -9
  10. package/.documentation/installation.html +23 -19
  11. package/.documentation/ralph-loop.html +530 -0
  12. package/.documentation/test-web.html +8 -4
  13. package/README.md +52 -10
  14. package/dist/index.js +813 -283
  15. package/dist/index.js.map +1 -1
  16. package/package.json +1 -1
  17. package/templates/agents/efcore/conflicts.md +44 -17
  18. package/templates/agents/efcore/db-status.md +27 -6
  19. package/templates/agents/efcore/scan.md +43 -13
  20. package/templates/commands/ai-prompt.md +315 -315
  21. package/templates/commands/application/create.md +362 -362
  22. package/templates/commands/controller/create.md +216 -216
  23. package/templates/commands/controller.md +59 -0
  24. package/templates/commands/create/agent.md +138 -0
  25. package/templates/commands/create/command.md +166 -0
  26. package/templates/commands/create/hook.md +234 -0
  27. package/templates/commands/create/plugin.md +329 -0
  28. package/templates/commands/create/project.md +507 -0
  29. package/templates/commands/create/skill.md +199 -0
  30. package/templates/commands/create.md +220 -0
  31. package/templates/commands/documentation/module.md +202 -202
  32. package/templates/commands/efcore/_env-check.md +153 -153
  33. package/templates/commands/efcore/conflicts.md +109 -192
  34. package/templates/commands/efcore/db-status.md +101 -89
  35. package/templates/commands/efcore/migration.md +23 -11
  36. package/templates/commands/efcore/scan.md +115 -119
  37. package/templates/commands/efcore.md +54 -6
  38. package/templates/commands/feature-full.md +267 -267
  39. package/templates/commands/gitflow/11-finish.md +145 -11
  40. package/templates/commands/gitflow/13-sync.md +216 -216
  41. package/templates/commands/gitflow/14-rebase.md +251 -251
  42. package/templates/commands/gitflow/2-status.md +120 -10
  43. package/templates/commands/gitflow/3-commit.md +150 -0
  44. package/templates/commands/gitflow/7-pull-request.md +134 -5
  45. package/templates/commands/gitflow/9-merge.md +142 -1
  46. package/templates/commands/implement.md +663 -663
  47. package/templates/commands/init.md +562 -0
  48. package/templates/commands/mcp-integration.md +330 -0
  49. package/templates/commands/notification.md +129 -129
  50. package/templates/commands/validate.md +233 -0
  51. package/templates/commands/workflow.md +193 -193
  52. package/templates/skills/ai-prompt/SKILL.md +778 -778
  53. package/templates/skills/application/SKILL.md +563 -563
  54. package/templates/skills/application/templates-backend.md +450 -450
  55. package/templates/skills/application/templates-frontend.md +531 -531
  56. package/templates/skills/application/templates-i18n.md +520 -520
  57. package/templates/skills/application/templates-seed.md +647 -647
  58. package/templates/skills/controller/SKILL.md +240 -240
  59. package/templates/skills/controller/postman-templates.md +614 -614
  60. package/templates/skills/controller/templates.md +1468 -1468
  61. package/templates/skills/documentation/SKILL.md +133 -133
  62. package/templates/skills/documentation/templates.md +476 -476
  63. package/templates/skills/feature-full/SKILL.md +838 -838
  64. package/templates/skills/notification/SKILL.md +555 -555
  65. package/templates/skills/ui-components/SKILL.md +870 -870
  66. package/templates/skills/workflow/SKILL.md +582 -582
@@ -1,240 +1,240 @@
1
- ---
2
- name: controller
3
- description: |
4
- Génère automatiquement des controllers API pour SmartStack.
5
- Utiliser ce skill quand:
6
- - L'utilisateur demande de créer un controller, endpoint, ou API
7
- - L'utilisateur mentionne "CRUD", "REST API", "endpoint"
8
- - L'utilisateur veut ajouter des actions à un module existant
9
- - Après création d'une entité Domain pour exposer via API
10
- Types: CRUD standard, Auth/Login, Custom actions
11
- ---
12
-
13
- ## STRATÉGIE MODÈLES (Qualité Maximale)
14
-
15
- | Phase | Modèle | Coût estimé |
16
- |-------|--------|-------------|
17
- | Génération complète | **Sonnet** | ~$0.19 |
18
- | Validation sécurité | **Opus** | ~$0.10 |
19
- | **Total** | | **~$0.29** |
20
-
21
- > **Note:** Si vous utilisez Opus pour tout, le skill fonctionne parfaitement
22
- > mais coûte ~$0.94/controller. Sonnet offre le meilleur rapport qualité/coût
23
- > pour la génération, Opus pour l'audit sécurité final.
24
-
25
- ---
26
-
27
- # Skill Controller SmartStack
28
-
29
- > **Synergie Skill/Commande:**
30
- > - **Skill** (`.claude/skills/controller/`) → Invocation automatique par Claude
31
- > - **Commande** (`/controller:create`) → Invocation manuelle par l'utilisateur
32
- > - Templates partagés dans `.claude/skills/controller/templates.md`
33
-
34
- ## QUAND CE SKILL S'ACTIVE
35
-
36
- Claude invoque automatiquement ce skill quand il détecte :
37
-
38
- | Déclencheur | Exemple |
39
- |-------------|---------|
40
- | Demande explicite | "Crée un controller pour les tickets" |
41
- | Mention d'API | "Il faut exposer les SLA via REST" |
42
- | Après entité Domain | "L'entité est prête, génère l'API" |
43
- | Mots-clés | "CRUD", "endpoint", "controller", "API REST" |
44
-
45
- ---
46
-
47
- ## WORKFLOW AUTOMATIQUE
48
-
49
- ### ÉTAPE 1: DÉTECTION DU TYPE
50
-
51
- | Indice | → Type |
52
- |--------|--------|
53
- | Authentification, login, session | `auth` |
54
- | Module avec CRUD complet | `crud` |
55
- | Actions spécifiques seulement | `custom` |
56
-
57
- ### ÉTAPE 2: EXTRACTION DES PARAMÈTRES
58
-
59
- | Paramètre | Source | Exemple |
60
- |-----------|--------|---------|
61
- | `$AREA` | Contexte navigation | `Admin`, `Support`, `Business`, `User` |
62
- | `$MODULE` | Nom du module | `Tickets`, `Sla`, `Users` |
63
- | `$ENTITY` | Entité Domain | `Ticket`, `SlaDefinition`, `User` |
64
- | `$PERMISSION_PATH` | Hiérarchie | `platform.support.tickets` |
65
-
66
- ### ÉTAPE 3: EXÉCUTION
67
-
68
- Suivre le workflow de la commande `/controller:create`
69
-
70
- ### ÉTAPE 4: SYNCHRONISATION BASE DE DONNÉES (OBLIGATOIRE)
71
-
72
- > **CRITIQUE:** Un controller avec `[RequirePermission]` retournera **403 Forbidden** pour TOUS les utilisateurs si la permission n'existe pas dans la base de données.
73
-
74
- #### 4.1 Fichiers à synchroniser
75
-
76
- | Fichier | Rôle | Action |
77
- |---------|------|--------|
78
- | `Permissions.cs` | Constantes code | Ajouter la classe de permissions |
79
- | `PermissionConfiguration.cs` | Seed EF Core | Ajouter les entrées HasData |
80
-
81
- #### 4.2 Workflow obligatoire
82
-
83
- ```
84
- ┌──────────────────────────────────────────────────────────────────────────────┐
85
- │ WORKFLOW SYNCHRONISATION PERMISSIONS │
86
- ├──────────────────────────────────────────────────────────────────────────────┤
87
- │ │
88
- │ 1. GÉNÉRER CONTROLLER │
89
- │ └─→ [RequirePermission(Permissions.{Module}.View)] │
90
- │ │
91
- │ 2. AJOUTER À Permissions.cs (Application layer) │
92
- │ └─→ public static class {Module} { ... } │
93
- │ │
94
- │ 3. AJOUTER À PermissionConfiguration.cs (Infrastructure layer) │
95
- │ └─→ HasData(new { Path = "...", ModuleId = ..., ... }) │
96
- │ │
97
- │ 4. CRÉER MIGRATION EF CORE │
98
- │ └─→ /efcore:migration Add{Module}Permissions │
99
- │ │
100
- │ 5. VALIDER COHÉRENCE │
101
- │ └─→ Vérifier que TOUS les paths dans Permissions.cs │
102
- │ existent dans PermissionConfiguration.cs │
103
- │ │
104
- └──────────────────────────────────────────────────────────────────────────────┘
105
- ```
106
-
107
- #### 4.3 Template PermissionConfiguration.cs
108
-
109
- Voir le template complet dans [templates.md](templates.md#template-permissionconfiguration-seed)
110
-
111
- #### 4.4 Checklist de validation
112
-
113
- ```
114
- □ Permissions.cs contient la classe {Module} avec View/Create/Update/Delete
115
- □ PermissionConfiguration.cs contient les entrées HasData correspondantes
116
- □ Les paths sont identiques entre les deux fichiers
117
- □ Le ModuleId référence un module existant dans ModuleConfiguration.cs
118
- □ Migration créée avec /efcore:migration
119
- □ Migration appliquée avec /efcore:db-deploy
120
- ```
121
-
122
- ---
123
-
124
- ## RÈGLES ABSOLUES - SÉCURITÉ
125
-
126
- ### 1. Logs Critiques (OBLIGATOIRE)
127
-
128
- | Événement | Niveau | Pattern |
129
- |-----------|--------|---------|
130
- | Login échoué | `Critical` | `LogCritical("Login attempt on locked account...")` |
131
- | Permission refusée | `Critical` | Auto via `SecurityAuditMiddleware` |
132
- | Compte verrouillé | `Critical` | `LogCritical("Account locked...")` |
133
- | Password change | `Warning` | `LogWarning("Password changed...")` |
134
- | Création/MAJ | `Information` | `LogInformation("User {User} creating...")` |
135
- | Suppression | `Warning` | `LogWarning("User {User} deleting...")` |
136
-
137
- ### 2. Protection Comptes Système (OBLIGATOIRE)
138
-
139
- ```csharp
140
- // TOUJOURS vérifier avant modification d'entité User-related
141
- if (entity.UserType == UserType.System || entity.UserType == UserType.LocalAdmin)
142
- return BadRequest(new { message = "Cannot modify system accounts" });
143
- ```
144
-
145
- ### 3. Permissions (OBLIGATOIRE)
146
-
147
- ```csharp
148
- // TOUJOURS utiliser les constantes Permissions.*
149
- [RequirePermission(Permissions.Support.Tickets.View)] // ✅ Correct
150
- [RequirePermission("platform.support.tickets.read")] // ❌ Éviter strings
151
- ```
152
-
153
- ### 4. Cache Invalidation (SI rôles/permissions)
154
-
155
- ```csharp
156
- // Après modification de rôle ou permission
157
- await _permissionService.InvalidateUserPermissionsCacheAsync(userId, ct);
158
- ```
159
-
160
- ---
161
-
162
- ## RÉFÉRENCE RAPIDE
163
-
164
- ### Services à Injecter
165
-
166
- | Service | Usage | Obligatoire |
167
- |---------|-------|-------------|
168
- | `IApplicationDbContext` | Accès DB | ✅ Toujours |
169
- | `ICurrentUserService` | User courant | ✅ Toujours |
170
- | `ILogger<T>` | Logging | ✅ Toujours |
171
- | `IPermissionService` | Cache permissions | Si roles/permissions |
172
- | `IPasswordService` | Hash passwords | Si auth |
173
- | `IJwtService` | Tokens JWT | Si auth |
174
- | `IUserSessionService` | Sessions | Si auth |
175
- | `INotificationService` | Notifications | Si notifications |
176
-
177
- ### ProducesResponseType (OBLIGATOIRE)
178
-
179
- ```csharp
180
- [ProducesResponseType(typeof(ItemDto), StatusCodes.Status200OK)]
181
- [ProducesResponseType(StatusCodes.Status401Unauthorized)] // Si [Authorize]
182
- [ProducesResponseType(StatusCodes.Status403Forbidden)] // Si [RequirePermission]
183
- [ProducesResponseType(StatusCodes.Status404NotFound)] // Si GET by ID
184
- [ProducesResponseType(StatusCodes.Status400BadRequest)] // Si validation
185
- [ProducesResponseType(StatusCodes.Status409Conflict)] // Si unique constraint
186
- ```
187
-
188
- ---
189
-
190
- ## USER PATH TRACKING
191
-
192
- > **IMPORTANT:** Le tracking du chemin utilisateur est géré par **infrastructure**, pas par les controllers.
193
-
194
- ### Middleware Existant
195
-
196
- `ApplicationAccessTrackingMiddleware` track automatiquement :
197
- - ✅ UserId, ApplicationId, ModuleId
198
- - ✅ IP Address, User Agent, Device Type
199
- - ✅ AccessedAt (timestamp)
200
-
201
- ### Enrichissement Recommandé (Séparé)
202
-
203
- Pour tracker le **temps passé** sur chaque module :
204
-
205
- ```csharp
206
- // Dans ApplicationAccess entity - AJOUTER :
207
- public DateTime? LeftAt { get; private set; }
208
- public TimeSpan? Duration => LeftAt.HasValue ? LeftAt - AccessedAt : null;
209
-
210
- // Dans middleware - AJOUTER :
211
- // 1. Au début de requête: créer/identifier session
212
- // 2. À la fin de requête: calculer durée ou marquer "navigation away"
213
- ```
214
-
215
- → Ceci est un **enhancement infrastructure**, pas un controller concern.
216
-
217
- ---
218
-
219
- ## TESTS POSTMAN
220
-
221
- Chaque controller doit avoir des tests couvrant :
222
-
223
- | Test | User | Status Attendu |
224
- |------|------|----------------|
225
- | GET list | SuperAdmin | 200 |
226
- | GET list | NoPerm | 403 |
227
- | GET list | Anonymous | 401 |
228
- | POST create | ReadOnly | 403 |
229
- | POST create | WithPerm | 201 |
230
- | DELETE | ReadOnly | 403 |
231
-
232
- → Templates dans `postman-templates.md`
233
-
234
- ---
235
-
236
- ## FICHIERS ASSOCIÉS
237
-
238
- - **Templates Controller:** [templates.md](templates.md)
239
- - **Templates Postman:** [postman-templates.md](postman-templates.md)
240
- - **Commande complète:** `.claude/commands/controller-create.md`
1
+ ---
2
+ name: controller
3
+ description: |
4
+ Génère automatiquement des controllers API pour SmartStack.
5
+ Utiliser ce skill quand:
6
+ - L'utilisateur demande de créer un controller, endpoint, ou API
7
+ - L'utilisateur mentionne "CRUD", "REST API", "endpoint"
8
+ - L'utilisateur veut ajouter des actions à un module existant
9
+ - Après création d'une entité Domain pour exposer via API
10
+ Types: CRUD standard, Auth/Login, Custom actions
11
+ ---
12
+
13
+ ## STRATÉGIE MODÈLES (Qualité Maximale)
14
+
15
+ | Phase | Modèle | Coût estimé |
16
+ |-------|--------|-------------|
17
+ | Génération complète | **Sonnet** | ~$0.19 |
18
+ | Validation sécurité | **Opus** | ~$0.10 |
19
+ | **Total** | | **~$0.29** |
20
+
21
+ > **Note:** Si vous utilisez Opus pour tout, le skill fonctionne parfaitement
22
+ > mais coûte ~$0.94/controller. Sonnet offre le meilleur rapport qualité/coût
23
+ > pour la génération, Opus pour l'audit sécurité final.
24
+
25
+ ---
26
+
27
+ # Skill Controller SmartStack
28
+
29
+ > **Synergie Skill/Commande:**
30
+ > - **Skill** (`.claude/skills/controller/`) → Invocation automatique par Claude
31
+ > - **Commande** (`/controller:create`) → Invocation manuelle par l'utilisateur
32
+ > - Templates partagés dans `.claude/skills/controller/templates.md`
33
+
34
+ ## QUAND CE SKILL S'ACTIVE
35
+
36
+ Claude invoque automatiquement ce skill quand il détecte :
37
+
38
+ | Déclencheur | Exemple |
39
+ |-------------|---------|
40
+ | Demande explicite | "Crée un controller pour les tickets" |
41
+ | Mention d'API | "Il faut exposer les SLA via REST" |
42
+ | Après entité Domain | "L'entité est prête, génère l'API" |
43
+ | Mots-clés | "CRUD", "endpoint", "controller", "API REST" |
44
+
45
+ ---
46
+
47
+ ## WORKFLOW AUTOMATIQUE
48
+
49
+ ### ÉTAPE 1: DÉTECTION DU TYPE
50
+
51
+ | Indice | → Type |
52
+ |--------|--------|
53
+ | Authentification, login, session | `auth` |
54
+ | Module avec CRUD complet | `crud` |
55
+ | Actions spécifiques seulement | `custom` |
56
+
57
+ ### ÉTAPE 2: EXTRACTION DES PARAMÈTRES
58
+
59
+ | Paramètre | Source | Exemple |
60
+ |-----------|--------|---------|
61
+ | `$AREA` | Contexte navigation | `Admin`, `Support`, `Business`, `User` |
62
+ | `$MODULE` | Nom du module | `Tickets`, `Sla`, `Users` |
63
+ | `$ENTITY` | Entité Domain | `Ticket`, `SlaDefinition`, `User` |
64
+ | `$PERMISSION_PATH` | Hiérarchie | `platform.support.tickets` |
65
+
66
+ ### ÉTAPE 3: EXÉCUTION
67
+
68
+ Suivre le workflow de la commande `/controller:create`
69
+
70
+ ### ÉTAPE 4: SYNCHRONISATION BASE DE DONNÉES (OBLIGATOIRE)
71
+
72
+ > **CRITIQUE:** Un controller avec `[RequirePermission]` retournera **403 Forbidden** pour TOUS les utilisateurs si la permission n'existe pas dans la base de données.
73
+
74
+ #### 4.1 Fichiers à synchroniser
75
+
76
+ | Fichier | Rôle | Action |
77
+ |---------|------|--------|
78
+ | `Permissions.cs` | Constantes code | Ajouter la classe de permissions |
79
+ | `PermissionConfiguration.cs` | Seed EF Core | Ajouter les entrées HasData |
80
+
81
+ #### 4.2 Workflow obligatoire
82
+
83
+ ```
84
+ ┌──────────────────────────────────────────────────────────────────────────────┐
85
+ │ WORKFLOW SYNCHRONISATION PERMISSIONS │
86
+ ├──────────────────────────────────────────────────────────────────────────────┤
87
+ │ │
88
+ │ 1. GÉNÉRER CONTROLLER │
89
+ │ └─→ [RequirePermission(Permissions.{Module}.View)] │
90
+ │ │
91
+ │ 2. AJOUTER À Permissions.cs (Application layer) │
92
+ │ └─→ public static class {Module} { ... } │
93
+ │ │
94
+ │ 3. AJOUTER À PermissionConfiguration.cs (Infrastructure layer) │
95
+ │ └─→ HasData(new { Path = "...", ModuleId = ..., ... }) │
96
+ │ │
97
+ │ 4. CRÉER MIGRATION EF CORE │
98
+ │ └─→ /efcore:migration Add{Module}Permissions │
99
+ │ │
100
+ │ 5. VALIDER COHÉRENCE │
101
+ │ └─→ Vérifier que TOUS les paths dans Permissions.cs │
102
+ │ existent dans PermissionConfiguration.cs │
103
+ │ │
104
+ └──────────────────────────────────────────────────────────────────────────────┘
105
+ ```
106
+
107
+ #### 4.3 Template PermissionConfiguration.cs
108
+
109
+ Voir le template complet dans [templates.md](templates.md#template-permissionconfiguration-seed)
110
+
111
+ #### 4.4 Checklist de validation
112
+
113
+ ```
114
+ □ Permissions.cs contient la classe {Module} avec View/Create/Update/Delete
115
+ □ PermissionConfiguration.cs contient les entrées HasData correspondantes
116
+ □ Les paths sont identiques entre les deux fichiers
117
+ □ Le ModuleId référence un module existant dans ModuleConfiguration.cs
118
+ □ Migration créée avec /efcore:migration
119
+ □ Migration appliquée avec /efcore:db-deploy
120
+ ```
121
+
122
+ ---
123
+
124
+ ## RÈGLES ABSOLUES - SÉCURITÉ
125
+
126
+ ### 1. Logs Critiques (OBLIGATOIRE)
127
+
128
+ | Événement | Niveau | Pattern |
129
+ |-----------|--------|---------|
130
+ | Login échoué | `Critical` | `LogCritical("Login attempt on locked account...")` |
131
+ | Permission refusée | `Critical` | Auto via `SecurityAuditMiddleware` |
132
+ | Compte verrouillé | `Critical` | `LogCritical("Account locked...")` |
133
+ | Password change | `Warning` | `LogWarning("Password changed...")` |
134
+ | Création/MAJ | `Information` | `LogInformation("User {User} creating...")` |
135
+ | Suppression | `Warning` | `LogWarning("User {User} deleting...")` |
136
+
137
+ ### 2. Protection Comptes Système (OBLIGATOIRE)
138
+
139
+ ```csharp
140
+ // TOUJOURS vérifier avant modification d'entité User-related
141
+ if (entity.UserType == UserType.System || entity.UserType == UserType.LocalAdmin)
142
+ return BadRequest(new { message = "Cannot modify system accounts" });
143
+ ```
144
+
145
+ ### 3. Permissions (OBLIGATOIRE)
146
+
147
+ ```csharp
148
+ // TOUJOURS utiliser les constantes Permissions.*
149
+ [RequirePermission(Permissions.Support.Tickets.View)] // ✅ Correct
150
+ [RequirePermission("platform.support.tickets.read")] // ❌ Éviter strings
151
+ ```
152
+
153
+ ### 4. Cache Invalidation (SI rôles/permissions)
154
+
155
+ ```csharp
156
+ // Après modification de rôle ou permission
157
+ await _permissionService.InvalidateUserPermissionsCacheAsync(userId, ct);
158
+ ```
159
+
160
+ ---
161
+
162
+ ## RÉFÉRENCE RAPIDE
163
+
164
+ ### Services à Injecter
165
+
166
+ | Service | Usage | Obligatoire |
167
+ |---------|-------|-------------|
168
+ | `IApplicationDbContext` | Accès DB | ✅ Toujours |
169
+ | `ICurrentUserService` | User courant | ✅ Toujours |
170
+ | `ILogger<T>` | Logging | ✅ Toujours |
171
+ | `IPermissionService` | Cache permissions | Si roles/permissions |
172
+ | `IPasswordService` | Hash passwords | Si auth |
173
+ | `IJwtService` | Tokens JWT | Si auth |
174
+ | `IUserSessionService` | Sessions | Si auth |
175
+ | `INotificationService` | Notifications | Si notifications |
176
+
177
+ ### ProducesResponseType (OBLIGATOIRE)
178
+
179
+ ```csharp
180
+ [ProducesResponseType(typeof(ItemDto), StatusCodes.Status200OK)]
181
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)] // Si [Authorize]
182
+ [ProducesResponseType(StatusCodes.Status403Forbidden)] // Si [RequirePermission]
183
+ [ProducesResponseType(StatusCodes.Status404NotFound)] // Si GET by ID
184
+ [ProducesResponseType(StatusCodes.Status400BadRequest)] // Si validation
185
+ [ProducesResponseType(StatusCodes.Status409Conflict)] // Si unique constraint
186
+ ```
187
+
188
+ ---
189
+
190
+ ## USER PATH TRACKING
191
+
192
+ > **IMPORTANT:** Le tracking du chemin utilisateur est géré par **infrastructure**, pas par les controllers.
193
+
194
+ ### Middleware Existant
195
+
196
+ `ApplicationAccessTrackingMiddleware` track automatiquement :
197
+ - ✅ UserId, ApplicationId, ModuleId
198
+ - ✅ IP Address, User Agent, Device Type
199
+ - ✅ AccessedAt (timestamp)
200
+
201
+ ### Enrichissement Recommandé (Séparé)
202
+
203
+ Pour tracker le **temps passé** sur chaque module :
204
+
205
+ ```csharp
206
+ // Dans ApplicationAccess entity - AJOUTER :
207
+ public DateTime? LeftAt { get; private set; }
208
+ public TimeSpan? Duration => LeftAt.HasValue ? LeftAt - AccessedAt : null;
209
+
210
+ // Dans middleware - AJOUTER :
211
+ // 1. Au début de requête: créer/identifier session
212
+ // 2. À la fin de requête: calculer durée ou marquer "navigation away"
213
+ ```
214
+
215
+ → Ceci est un **enhancement infrastructure**, pas un controller concern.
216
+
217
+ ---
218
+
219
+ ## TESTS POSTMAN
220
+
221
+ Chaque controller doit avoir des tests couvrant :
222
+
223
+ | Test | User | Status Attendu |
224
+ |------|------|----------------|
225
+ | GET list | SuperAdmin | 200 |
226
+ | GET list | NoPerm | 403 |
227
+ | GET list | Anonymous | 401 |
228
+ | POST create | ReadOnly | 403 |
229
+ | POST create | WithPerm | 201 |
230
+ | DELETE | ReadOnly | 403 |
231
+
232
+ → Templates dans `postman-templates.md`
233
+
234
+ ---
235
+
236
+ ## FICHIERS ASSOCIÉS
237
+
238
+ - **Templates Controller:** [templates.md](templates.md)
239
+ - **Templates Postman:** [postman-templates.md](postman-templates.md)
240
+ - **Commande complète:** `.claude/commands/controller-create.md`