@atlashub/smartstack-cli 1.11.0 → 1.13.1

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 (74) hide show
  1. package/.documentation/agents.html +7 -2
  2. package/.documentation/apex.html +7 -2
  3. package/.documentation/business-analyse.html +7 -2
  4. package/.documentation/cli-commands.html +871 -0
  5. package/.documentation/commands.html +7 -2
  6. package/.documentation/efcore.html +7 -2
  7. package/.documentation/gitflow.html +7 -2
  8. package/.documentation/hooks.html +7 -2
  9. package/.documentation/index.html +7 -2
  10. package/.documentation/init.html +7 -2
  11. package/.documentation/installation.html +7 -2
  12. package/.documentation/ralph-loop.html +7 -2
  13. package/.documentation/test-web.html +7 -2
  14. package/dist/index.js +1932 -336
  15. package/dist/index.js.map +1 -1
  16. package/package.json +8 -2
  17. package/templates/agents/efcore/squash.md +67 -31
  18. package/templates/agents/gitflow/finish.md +68 -56
  19. package/templates/commands/business-analyse/0-orchestrate.md +72 -556
  20. package/templates/commands/business-analyse/1-init.md +23 -193
  21. package/templates/commands/business-analyse/2-discover.md +85 -462
  22. package/templates/commands/business-analyse/3-analyse.md +40 -342
  23. package/templates/commands/business-analyse/4-specify.md +72 -537
  24. package/templates/commands/business-analyse/5-validate.md +43 -237
  25. package/templates/commands/business-analyse/6-handoff.md +93 -682
  26. package/templates/commands/business-analyse/7-doc-html.md +45 -544
  27. package/templates/commands/business-analyse/_shared.md +176 -0
  28. package/templates/commands/business-analyse/bug.md +50 -257
  29. package/templates/commands/business-analyse/change-request.md +59 -283
  30. package/templates/commands/business-analyse/hotfix.md +36 -120
  31. package/templates/commands/business-analyse.md +55 -574
  32. package/templates/commands/efcore/_shared.md +206 -0
  33. package/templates/commands/efcore/conflicts.md +39 -201
  34. package/templates/commands/efcore/db-deploy.md +28 -237
  35. package/templates/commands/efcore/db-reset.md +41 -390
  36. package/templates/commands/efcore/db-seed.md +44 -323
  37. package/templates/commands/efcore/db-status.md +31 -210
  38. package/templates/commands/efcore/migration.md +45 -368
  39. package/templates/commands/efcore/rebase-snapshot.md +38 -241
  40. package/templates/commands/efcore/scan.md +35 -204
  41. package/templates/commands/efcore/squash.md +158 -251
  42. package/templates/commands/efcore.md +49 -177
  43. package/templates/commands/gitflow/1-init.md +94 -1318
  44. package/templates/commands/gitflow/10-start.md +86 -990
  45. package/templates/commands/gitflow/11-finish.md +264 -454
  46. package/templates/commands/gitflow/12-cleanup.md +40 -213
  47. package/templates/commands/gitflow/2-status.md +51 -386
  48. package/templates/commands/gitflow/3-commit.md +108 -801
  49. package/templates/commands/gitflow/4-plan.md +42 -13
  50. package/templates/commands/gitflow/5-exec.md +60 -5
  51. package/templates/commands/gitflow/6-abort.md +54 -277
  52. package/templates/commands/gitflow/7-pull-request.md +74 -717
  53. package/templates/commands/gitflow/8-review.md +51 -178
  54. package/templates/commands/gitflow/9-merge.md +74 -404
  55. package/templates/commands/gitflow/_shared.md +196 -0
  56. package/templates/commands/quickstart.md +154 -0
  57. package/templates/commands/ralph-loop/ralph-loop.md +104 -2
  58. package/templates/hooks/hooks.json +13 -0
  59. package/templates/hooks/ralph-mcp-logger.sh +46 -0
  60. package/templates/hooks/ralph-session-end.sh +69 -0
  61. package/templates/ralph/README.md +91 -0
  62. package/templates/ralph/ralph.config.yaml +113 -0
  63. package/templates/scripts/setup-ralph-loop.sh +173 -0
  64. package/templates/skills/_shared.md +117 -0
  65. package/templates/skills/ai-prompt/SKILL.md +87 -654
  66. package/templates/skills/application/SKILL.md +76 -499
  67. package/templates/skills/controller/SKILL.md +38 -165
  68. package/templates/skills/documentation/SKILL.md +2 -1
  69. package/templates/skills/feature-full/SKILL.md +107 -732
  70. package/templates/skills/notification/SKILL.md +85 -474
  71. package/templates/skills/ui-components/SKILL.md +62 -762
  72. package/templates/skills/workflow/SKILL.md +85 -489
  73. package/templates/commands/gitflow/rescue.md +0 -867
  74. package/templates/skills/business-analyse/SKILL.md +0 -191
@@ -12,827 +12,202 @@ description: |
12
12
 
13
13
  # Skill Feature Full SmartStack
14
14
 
15
- > **OneShot Development:** Ce skill orchestre tous les autres skills pour creer
16
- > une feature complete avec la meilleure experience utilisateur possible.
15
+ > **OneShot Development:** Orchestre tous les skills pour une feature complete.
17
16
 
18
- ## QUAND CE SKILL S'ACTIVE
17
+ **Référence:** [_shared.md](../_shared.md) pour architecture, permissions, i18n
19
18
 
20
- Claude invoque automatiquement ce skill quand il detecte :
19
+ ## QUAND CE SKILL S'ACTIVE
21
20
 
22
21
  | Declencheur | Exemple |
23
22
  |-------------|---------|
24
23
  | Feature complete | "Cree un module de gestion des produits" |
25
- | OneShot | "Implemente la feature de A a Z" |
26
24
  | Full-stack | "Cree le backend et le frontend pour..." |
27
- | UX focus | "Je veux une experience utilisateur complete" |
28
25
  | Integration | "Avec notifications et emails automatiques" |
29
26
 
30
- ---
31
-
32
- ## ARCHITECTURE FEATURE COMPLETE
27
+ ## FLOW COMPLET
33
28
 
34
29
  ```
35
- ┌─────────────────────────────────────────────────────────────────────────────┐
36
- FEATURE FULL-STACK COMPLETE │
37
- ├─────────────────────────────────────────────────────────────────────────────┤
38
- │ │
39
- │ ┌───────────────────────────────────────────────────────────────────────┐ │
40
- │ │ DOMAIN LAYER │ │
41
- │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
42
- │ │ │ Entity │ │ Enums │ │ Events │ │ Factory │ │ Specs │ │ │
43
- │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
44
- │ └───────────────────────────────────────────────────────────────────────┘ │
45
- │ │ │
46
- │ ┌───────────────────────────────────────────────────────────────────────┐ │
47
- │ │ APPLICATION LAYER │ │
48
- │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
49
- │ │ │Interface│ │ DTOs │ │Commands │ │Validators│ │ │
50
- │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
51
- │ └───────────────────────────────────────────────────────────────────────┘ │
52
- │ │ │
53
- │ ┌───────────────────────────────────────────────────────────────────────┐ │
54
- │ │ INFRASTRUCTURE LAYER │ │
55
- │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
56
- │ │ │ EF Core │ │ Service │ │ Seed │ │ SignalR │ │ Email │ │ │
57
- │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
58
- │ └───────────────────────────────────────────────────────────────────────┘ │
59
- │ │ │
60
- │ ┌───────────────────────────────────────────────────────────────────────┐ │
61
- │ │ API LAYER │ │
62
- │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
63
- │ │ │Controller│ │Authorize │ │ Swagger │ │Postman │ │ │
64
- │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
65
- │ └───────────────────────────────────────────────────────────────────────┘ │
66
- │ │ │
67
- │ ┌───────────────────────────────────────────────────────────────────────┐ │
68
- │ │ WEB LAYER │ │
69
- │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
70
- │ │ │ Pages │ │ Hooks │ │ i18n │ │ API │ │ Routes │ │ │
71
- │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
72
- │ └───────────────────────────────────────────────────────────────────────┘ │
73
- │ │ │
74
- │ ┌───────────────────────────────────────────────────────────────────────┐ │
75
- │ │ INTEGRATIONS │ │
76
- │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
77
- │ │ │NOTIFICATIONS│ │ WORKFLOWS │ │ AI │ │ │
78
- │ │ │ In-App │ │ Emails │ │ Analysis │ │ │
79
- │ │ │ Real-time │ │ Webhooks │ │ Generation │ │ │
80
- │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
81
- │ └───────────────────────────────────────────────────────────────────────┘ │
82
- │ │
83
- └─────────────────────────────────────────────────────────────────────────────┘
30
+ DOMAIN → APPLICATION → INFRASTRUCTURE → API → WEB
31
+ + NOTIFICATIONS + WORKFLOWS + AI
84
32
  ```
85
33
 
86
- ---
87
-
88
34
  ## WORKFLOW DE CREATION
89
35
 
90
- ### PHASE 1: ANALYSE (5 min)
36
+ ### PHASE 1: ANALYSE
91
37
 
92
38
  ```
93
- 1. IDENTIFIER LE BESOIN
94
- Quel module/fonctionnalite ?
95
- Quelles entites ?
96
- Quelles operations CRUD ?
97
- □ Quelles regles metier ?
98
-
99
- 2. DEFINIR LES INTEGRATIONS
100
- □ Notifications requises ?
101
- → Quand ? Pour qui ? Quel type ?
102
- □ Emails automatiques ?
103
- → Quels triggers ? Quels templates ?
104
- □ Assistance IA ?
105
- → Quel use case ? Quelle validation ?
106
-
107
- 3. DEFINIR L'UX
108
- □ Affichage: Cards, Table, Kanban ?
109
- □ Navigation: Ou dans l'arborescence ?
110
- □ Permissions: Qui peut faire quoi ?
39
+ Module/fonctionnalite ?
40
+ Entites ? Operations CRUD ? Regles metier ?
41
+ Notifications requises ? Emails automatiques ? IA ?
42
+ Affichage: Cards/Table/Kanban ? Permissions ?
111
43
  ```
112
44
 
113
- ### PHASE 2: GENERATION DOMAIN (10 min)
45
+ ### PHASE 2: DOMAIN
114
46
 
115
47
  ```csharp
116
- // 1. ENTITE DOMAIN
117
- // src/SmartStack.Domain/{Area}/{Entity}.cs
118
-
48
+ // {Entity}.cs - Factory Method + Behaviors
119
49
  public class {Entity} : BaseEntity, IAuditableEntity
120
50
  {
121
- // Proprietes
122
51
  public string Name { get; private set; }
123
- public string? Description { get; private set; }
124
52
  public {Entity}Status Status { get; private set; }
125
-
126
- // Relations
127
- public Guid CreatedById { get; private set; }
128
- public User CreatedBy { get; private set; } = null!;
129
-
130
- // Audit
131
- public string? CreatedByName { get; set; }
132
- public string? UpdatedByName { get; set; }
133
-
134
- // Private constructor for EF Core
135
53
  private {Entity}() { }
136
-
137
- // Factory Method
138
- public static {Entity} Create(
139
- string name,
140
- string? description,
141
- Guid createdById)
142
- {
143
- if (string.IsNullOrWhiteSpace(name))
144
- throw new DomainException("{Entity} name is required");
145
-
146
- return new {Entity}
147
- {
148
- Id = Guid.NewGuid(),
149
- Name = name,
150
- Description = description,
151
- Status = {Entity}Status.Active,
152
- CreatedById = createdById,
153
- CreatedAt = DateTime.UtcNow
154
- };
155
- }
156
-
157
- // Behaviors
158
- public void Update(string name, string? description)
159
- {
160
- Name = name ?? throw new DomainException("Name is required");
161
- Description = description;
162
- UpdatedAt = DateTime.UtcNow;
163
- }
164
-
165
- public void Activate() => Status = {Entity}Status.Active;
166
- public void Deactivate() => Status = {Entity}Status.Inactive;
54
+ public static {Entity} Create(string name, Guid createdById) =>
55
+ new { Id = Guid.NewGuid(), Name = name, Status = {Entity}Status.Active, ... };
56
+ public void Update(string name) => Name = name ?? throw new DomainException("Name required");
167
57
  }
168
58
 
169
- // 2. ENUM
170
- // src/SmartStack.Domain/{Area}/Enums/{Entity}Status.cs
171
-
172
- public enum {Entity}Status
173
- {
174
- Active = 0,
175
- Inactive = 1,
176
- Archived = 2
177
- }
59
+ // {Entity}Status.cs
60
+ public enum {Entity}Status { Active = 0, Inactive = 1, Archived = 2 }
178
61
  ```
179
62
 
180
- ### PHASE 3: GENERATION APPLICATION (10 min)
63
+ ### PHASE 3: APPLICATION
181
64
 
182
65
  ```csharp
183
- // 1. INTERFACE SERVICE
184
- // src/SmartStack.Application/Common/Interfaces/I{Entity}Service.cs
185
-
186
- public interface I{Entity}Service
187
- {
188
- Task<PagedResult<{Entity}Dto>> GetAllAsync(
189
- int page, int pageSize, string? search, CancellationToken ct);
190
- Task<{Entity}Dto?> GetByIdAsync(Guid id, CancellationToken ct);
191
- Task<{Entity}Dto> CreateAsync(Create{Entity}Request request, CancellationToken ct);
192
- Task<{Entity}Dto> UpdateAsync(Guid id, Update{Entity}Request request, CancellationToken ct);
193
- Task DeleteAsync(Guid id, CancellationToken ct);
194
- }
195
-
196
- // 2. DTOs
197
- // src/SmartStack.Application/{Area}/DTOs/{Entity}Dto.cs
198
-
199
- public record {Entity}Dto(
200
- Guid Id,
201
- string Name,
202
- string? Description,
203
- string Status,
204
- DateTime CreatedAt,
205
- string? CreatedByName);
66
+ // I{Entity}Service.cs
67
+ Task<PagedResult<{Entity}Dto>> GetAllAsync(...);
68
+ Task<{Entity}Dto> CreateAsync(Create{Entity}Request request, CancellationToken ct);
206
69
 
207
- public record Create{Entity}Request(
208
- string Name,
209
- string? Description);
70
+ // DTOs
71
+ public record {Entity}Dto(Guid Id, string Name, string Status, DateTime CreatedAt);
72
+ public record Create{Entity}Request(string Name, string? Description);
210
73
 
211
- public record Update{Entity}Request(
212
- string Name,
213
- string? Description);
214
-
215
- // 3. PERMISSIONS
216
- // src/SmartStack.Application/Common/Authorization/Permissions.cs
217
-
218
- public static class {Area}
219
- {
220
- public static class {Module}
221
- {
222
- public const string View = "{context}.{area}.{module}.read";
223
- public const string Create = "{context}.{area}.{module}.create";
224
- public const string Update = "{context}.{area}.{module}.update";
225
- public const string Delete = "{context}.{area}.{module}.delete";
226
- }
227
- }
74
+ // Permissions.cs + PermissionConfiguration.cs (2 fichiers!)
75
+ public const string View = "{context}.{area}.{module}.read";
228
76
  ```
229
77
 
230
- ### PHASE 4: GENERATION INFRASTRUCTURE (15 min)
78
+ ### PHASE 4: INFRASTRUCTURE
231
79
 
232
80
  ```csharp
233
- // 1. CONFIGURATION EF CORE
234
- // src/SmartStack.Infrastructure/Persistence/Configurations/{Area}/{Entity}Configuration.cs
235
-
236
- public class {Entity}Configuration : IEntityTypeConfiguration<{Entity}>
237
- {
238
- public void Configure(EntityTypeBuilder<{Entity}> builder)
239
- {
240
- builder.ToTable("{Entity}s", "{schema}");
241
-
242
- builder.HasKey(x => x.Id);
243
-
244
- builder.Property(x => x.Name)
245
- .HasMaxLength(200)
246
- .IsRequired();
247
-
248
- builder.Property(x => x.Description)
249
- .HasMaxLength(2000);
250
-
251
- builder.HasIndex(x => x.Name);
252
- builder.HasIndex(x => x.Status);
253
- builder.HasIndex(x => x.CreatedById);
254
-
255
- // Navigation
256
- builder.HasOne(x => x.CreatedBy)
257
- .WithMany()
258
- .HasForeignKey(x => x.CreatedById)
259
- .OnDelete(DeleteBehavior.Restrict);
260
- }
261
- }
262
-
263
- // 2. SERVICE IMPLEMENTATION
264
- // src/SmartStack.Infrastructure/Services/{Area}/{Entity}Service.cs
265
-
266
- public class {Entity}Service : I{Entity}Service
267
- {
268
- private readonly IApplicationDbContext _context;
269
- private readonly ICurrentUserService _currentUser;
270
- private readonly INotificationService _notificationService;
271
- private readonly ILogger<{Entity}Service> _logger;
272
-
273
- public {Entity}Service(
274
- IApplicationDbContext context,
275
- ICurrentUserService currentUser,
276
- INotificationService notificationService,
277
- ILogger<{Entity}Service> logger)
278
- {
279
- _context = context;
280
- _currentUser = currentUser;
281
- _notificationService = notificationService;
282
- _logger = logger;
283
- }
284
-
285
- public async Task<{Entity}Dto> CreateAsync(
286
- Create{Entity}Request request,
287
- CancellationToken ct)
288
- {
289
- var entity = {Entity}.Create(
290
- request.Name,
291
- request.Description,
292
- _currentUser.Id);
293
-
294
- entity.CreatedByName = _currentUser.DisplayName;
295
-
296
- _context.{Entity}s.Add(entity);
297
- await _context.SaveChangesAsync(ct);
298
-
299
- // NOTIFICATION
300
- await _notificationService.SendNotificationAsync(
301
- _currentUser.Id,
302
- NotificationType.{Entity}Created,
303
- "{Entity} creee",
304
- $"{entity.Name} a ete cree avec succes",
305
- relatedEntityType: nameof({Entity}),
306
- relatedEntityId: entity.Id,
307
- actionUrl: $"/{area}/{module}/{entity.Id}",
308
- cancellationToken: ct);
309
-
310
- _logger.LogInformation(
311
- "User {UserId} created {EntityType} {EntityId}: {EntityName}",
312
- _currentUser.Id, nameof({Entity}), entity.Id, entity.Name);
313
-
314
- return MapToDto(entity);
315
- }
316
-
317
- // ... autres methodes CRUD avec notifications
81
+ // {Entity}Configuration.cs
82
+ builder.ToTable("{Entity}s", "{schema}");
83
+ builder.Property(x => x.Name).HasMaxLength(200).IsRequired();
84
+
85
+ // {Entity}Service.cs avec Notifications
86
+ public async Task<{Entity}Dto> CreateAsync(...) {
87
+ var entity = {Entity}.Create(request.Name, _currentUser.Id);
88
+ _context.{Entity}s.Add(entity);
89
+ await _context.SaveChangesAsync(ct);
90
+ await _notificationService.SendNotificationAsync(_currentUser.Id,
91
+ NotificationType.{Entity}Created, "Cree", $"{entity.Name} cree",
92
+ relatedEntityType: nameof({Entity}), relatedEntityId: entity.Id, ct);
93
+ return MapToDto(entity);
318
94
  }
319
95
 
320
- // 3. DEPENDENCY INJECTION
321
- // Ajouter dans DependencyInjection.cs:
96
+ // DependencyInjection.cs
322
97
  services.AddScoped<I{Entity}Service, {Entity}Service>();
323
98
  ```
324
99
 
325
- ### PHASE 5: GENERATION API (10 min)
100
+ ### PHASE 5: API
326
101
 
327
102
  ```csharp
328
- // src/SmartStack.Api/Controllers/{Area}/{Entity}Controller.cs
329
-
330
- [ApiController]
331
- [Route("api/{area}/{module}")]
332
- [Authorize]
103
+ [ApiController][Route("api/{area}/{module}")][Authorize]
333
104
  public class {Entity}Controller : ControllerBase
334
105
  {
335
- private readonly I{Entity}Service _service;
336
- private readonly ILogger<{Entity}Controller> _logger;
337
-
338
- public {Entity}Controller(
339
- I{Entity}Service service,
340
- ILogger<{Entity}Controller> logger)
341
- {
342
- _service = service;
343
- _logger = logger;
344
- }
345
-
346
- [HttpGet]
347
- [RequirePermission(Permissions.{Area}.{Module}.View)]
348
- [ProducesResponseType(typeof(PagedResult<{Entity}Dto>), StatusCodes.Status200OK)]
349
- public async Task<ActionResult<PagedResult<{Entity}Dto>>> GetAll(
350
- [FromQuery] int page = 1,
351
- [FromQuery] int pageSize = 20,
352
- [FromQuery] string? search = null,
353
- CancellationToken ct = default)
354
- {
355
- var result = await _service.GetAllAsync(page, pageSize, search, ct);
356
- return Ok(result);
357
- }
358
-
359
- [HttpGet("{id:guid}")]
360
- [RequirePermission(Permissions.{Area}.{Module}.View)]
361
- [ProducesResponseType(typeof({Entity}Dto), StatusCodes.Status200OK)]
362
- [ProducesResponseType(StatusCodes.Status404NotFound)]
363
- public async Task<ActionResult<{Entity}Dto>> GetById(Guid id, CancellationToken ct)
364
- {
365
- var result = await _service.GetByIdAsync(id, ct);
366
- return result is null ? NotFound() : Ok(result);
367
- }
368
-
369
- [HttpPost]
370
- [RequirePermission(Permissions.{Area}.{Module}.Create)]
371
- [ProducesResponseType(typeof({Entity}Dto), StatusCodes.Status201Created)]
372
- [ProducesResponseType(StatusCodes.Status400BadRequest)]
373
- public async Task<ActionResult<{Entity}Dto>> Create(
374
- [FromBody] Create{Entity}Request request,
375
- CancellationToken ct)
376
- {
377
- var result = await _service.CreateAsync(request, ct);
378
- return CreatedAtAction(nameof(GetById), new { id = result.Id }, result);
379
- }
380
-
381
- [HttpPut("{id:guid}")]
382
- [RequirePermission(Permissions.{Area}.{Module}.Update)]
383
- [ProducesResponseType(typeof({Entity}Dto), StatusCodes.Status200OK)]
384
- [ProducesResponseType(StatusCodes.Status404NotFound)]
385
- public async Task<ActionResult<{Entity}Dto>> Update(
386
- Guid id,
387
- [FromBody] Update{Entity}Request request,
388
- CancellationToken ct)
389
- {
390
- var result = await _service.UpdateAsync(id, request, ct);
391
- return Ok(result);
392
- }
393
-
394
- [HttpDelete("{id:guid}")]
395
- [RequirePermission(Permissions.{Area}.{Module}.Delete)]
396
- [ProducesResponseType(StatusCodes.Status204NoContent)]
397
- [ProducesResponseType(StatusCodes.Status404NotFound)]
398
- public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
399
- {
400
- await _service.DeleteAsync(id, ct);
401
- return NoContent();
402
- }
106
+ [HttpGet][RequirePermission(Permissions.{Area}.{Module}.View)]
107
+ [ProducesResponseType(typeof(PagedResult<{Entity}Dto>), 200)]
108
+ public async Task<ActionResult<PagedResult<{Entity}Dto>>> GetAll(...);
109
+
110
+ [HttpPost][RequirePermission(Permissions.{Area}.{Module}.Create)]
111
+ [ProducesResponseType(typeof({Entity}Dto), 201)]
112
+ public async Task<ActionResult<{Entity}Dto>> Create([FromBody] request, CancellationToken ct);
403
113
  }
404
114
  ```
405
115
 
406
- ### PHASE 6: GENERATION FRONTEND (20 min)
116
+ ### PHASE 6: FRONTEND
407
117
 
408
118
  ```typescript
409
- // 1. API SERVICE
410
- // web/src/services/api/{module}Api.ts
411
-
412
- import { apiClient } from './apiClient';
413
- import type { PagedResult, {Entity}Dto, Create{Entity}Request, Update{Entity}Request } from '@/types';
414
-
119
+ // {module}Api.ts
415
120
  export const {module}Api = {
416
- getAll: (page = 1, pageSize = 20, search?: string) =>
417
- apiClient.get<PagedResult<{Entity}Dto>>('/{area}/{module}', {
418
- params: { page, pageSize, search }
419
- }),
420
-
421
- getById: (id: string) =>
422
- apiClient.get<{Entity}Dto>(`/{area}/{module}/${id}`),
423
-
424
- create: (data: Create{Entity}Request) =>
425
- apiClient.post<{Entity}Dto>('/{area}/{module}', data),
426
-
427
- update: (id: string, data: Update{Entity}Request) =>
428
- apiClient.put<{Entity}Dto>(`/{area}/{module}/${id}`, data),
429
-
430
- delete: (id: string) =>
431
- apiClient.delete(`/{area}/{module}/${id}`),
121
+ getAll: (page, pageSize, search?) => apiClient.get<PagedResult<{Entity}Dto>>('/{area}/{module}', { params }),
122
+ create: (data) => apiClient.post<{Entity}Dto>('/{area}/{module}', data),
432
123
  };
433
124
 
434
- // 2. HOOK AVEC SIGNALR
435
- // web/src/hooks/use{Module}.ts
436
-
437
- import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
438
- import { {module}Api } from '@/services/api/{module}Api';
439
- import { useSignalR } from '@/hooks/useSignalR';
440
- import { toast } from 'sonner';
441
-
125
+ // use{Module}.ts avec SignalR
442
126
  export function use{Module}() {
443
127
  const queryClient = useQueryClient();
444
-
445
- // Real-time updates
446
- useSignalR({
447
- onNotification: (notification) => {
448
- if (notification.relatedEntityType === '{Entity}') {
449
- queryClient.invalidateQueries(['{module}']);
450
- toast.info(notification.title, {
451
- description: notification.message,
452
- });
453
- }
454
- },
455
- });
456
-
457
- const {module}Query = useQuery({
458
- queryKey: ['{module}'],
459
- queryFn: () => {module}Api.getAll(),
460
- });
461
-
462
- const createMutation = useMutation({
463
- mutationFn: {module}Api.create,
464
- onSuccess: () => {
465
- queryClient.invalidateQueries(['{module}']);
466
- toast.success('{Entity} creee');
467
- },
468
- onError: (error) => {
469
- toast.error('Erreur lors de la creation');
470
- },
471
- });
472
-
473
- const updateMutation = useMutation({
474
- mutationFn: ({ id, data }: { id: string; data: Update{Entity}Request }) =>
475
- {module}Api.update(id, data),
476
- onSuccess: () => {
477
- queryClient.invalidateQueries(['{module}']);
478
- toast.success('{Entity} mise a jour');
479
- },
480
- });
481
-
482
- const deleteMutation = useMutation({
483
- mutationFn: {module}Api.delete,
484
- onSuccess: () => {
485
- queryClient.invalidateQueries(['{module}']);
486
- toast.success('{Entity} supprimee');
487
- },
488
- });
489
-
490
- return {
491
- {module}: {module}Query.data?.items ?? [],
492
- isLoading: {module}Query.isLoading,
493
- error: {module}Query.error,
494
- create: createMutation.mutate,
495
- update: updateMutation.mutate,
496
- delete: deleteMutation.mutate,
497
- isCreating: createMutation.isPending,
498
- isUpdating: updateMutation.isPending,
499
- isDeleting: deleteMutation.isPending,
500
- };
128
+ useSignalR({ onNotification: (n) => {
129
+ if (n.relatedEntityType === '{Entity}') queryClient.invalidateQueries(['{module}']);
130
+ }});
131
+ const createMutation = useMutation({ mutationFn: {module}Api.create, onSuccess: () => ... });
132
+ return { create: createMutation.mutate, ... };
501
133
  }
502
134
 
503
- // 3. PAGE PRINCIPALE
504
- // web/src/pages/{area}/{module}/{Module}Page.tsx
505
-
506
- import { useState } from 'react';
507
- import { Plus, Search } from 'lucide-react';
508
- import { use{Module} } from '@/hooks/use{Module}';
509
- import { EntityCard } from '@/components/ui/EntityCard';
510
- import { {Module}Form } from './components/{Module}Form';
511
- import { useTranslation } from 'react-i18next';
512
-
513
- export function {Module}Page() {
514
- const { t } = useTranslation('{module}');
515
- const { {module}, isLoading, create, delete: remove } = use{Module}();
516
- const [showForm, setShowForm] = useState(false);
517
- const [search, setSearch] = useState('');
518
-
519
- const filtered = {module}.filter(item =>
520
- item.name.toLowerCase().includes(search.toLowerCase())
521
- );
522
-
523
- return (
524
- <div className="space-y-6">
525
- {/* Header */}
526
- <div className="flex items-center justify-between">
527
- <div>
528
- <h1 className="text-2xl font-bold">{t('title')}</h1>
529
- <p className="text-[var(--text-secondary)]">{t('subtitle')}</p>
530
- </div>
531
- <button
532
- onClick={() => setShowForm(true)}
533
- className="inline-flex items-center gap-2 px-4 py-2 bg-[var(--color-accent-600)] text-white rounded-lg"
534
- >
535
- <Plus className="w-4 h-4" />
536
- {t('create')}
537
- </button>
538
- </div>
539
-
540
- {/* Search */}
541
- <div className="relative">
542
- <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-[var(--text-tertiary)]" />
543
- <input
544
- type="text"
545
- placeholder={t('search')}
546
- value={search}
547
- onChange={(e) => setSearch(e.target.value)}
548
- className="w-full pl-10 pr-4 py-2 border rounded-lg"
549
- />
550
- </div>
551
-
552
- {/* Grid */}
553
- {isLoading ? (
554
- <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
555
- {Array.from({ length: 6 }).map((_, i) => (
556
- <div key={i} className="h-48 bg-[var(--bg-secondary)] animate-pulse rounded-lg" />
557
- ))}
558
- </div>
559
- ) : filtered.length === 0 ? (
560
- <div className="text-center py-12">
561
- <p className="text-[var(--text-secondary)]">{t('empty')}</p>
562
- </div>
563
- ) : (
564
- <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
565
- {filtered.map((item) => (
566
- <EntityCard
567
- key={item.id}
568
- avatar={{ letter: item.name[0], color: 'var(--color-accent-500)' }}
569
- title={item.name}
570
- subtitle={item.status}
571
- description={item.description}
572
- actions={[
573
- { label: t('view'), onClick: () => navigate(`/${area}/{module}/${item.id}`), variant: 'primary' },
574
- { label: t('delete'), onClick: () => remove(item.id), variant: 'ghost' },
575
- ]}
576
- />
577
- ))}
578
- </div>
579
- )}
580
-
581
- {/* Form Modal */}
582
- {showForm && (
583
- <{Module}Form
584
- onSubmit={(data) => {
585
- create(data);
586
- setShowForm(false);
587
- }}
588
- onClose={() => setShowForm(false)}
589
- />
590
- )}
591
- </div>
592
- );
593
- }
135
+ // {Module}Page.tsx avec EntityCard
136
+ <EntityCard title={item.name} actions={[{ label: 'Voir', onClick: () => navigate(...) }]} />
594
137
 
595
- // 4. i18n
596
- // web/src/i18n/locales/fr/{module}.json
597
-
598
- {
599
- "title": "{Module}",
600
- "subtitle": "Gerez vos {module}s",
601
- "create": "Creer",
602
- "search": "Rechercher...",
603
- "empty": "Aucun {module} trouve",
604
- "view": "Voir",
605
- "edit": "Modifier",
606
- "delete": "Supprimer",
607
- "form": {
608
- "name": "Nom",
609
- "namePlaceholder": "Entrez le nom",
610
- "description": "Description",
611
- "descriptionPlaceholder": "Entrez une description",
612
- "submit": "Enregistrer",
613
- "cancel": "Annuler"
614
- },
615
- "notifications": {
616
- "created": "{Module} creee avec succes",
617
- "updated": "{Module} mise a jour",
618
- "deleted": "{Module} supprimee"
619
- }
620
- }
621
-
622
- // 5. ROUTES
623
- // App.tsx - Ajouter:
624
- <Route path="{area}">
625
- <Route index element={<Navigate to="{module}" replace />} />
626
- <Route path="{module}">
627
- <Route index element={<{Module}Page />} />
628
- <Route path=":id" element={<{Module}DetailPage />} />
629
- </Route>
630
- </Route>
138
+ // Routes (nested obligatoire)
139
+ <Route path="{area}"><Route path="{module}"><Route index element={<{Module}Page />} /></Route></Route>
631
140
  ```
632
141
 
633
- ### PHASE 7: INTEGRATIONS (15 min)
634
-
635
- #### 7.1 Notifications
142
+ ### PHASE 7: INTEGRATIONS
636
143
 
144
+ #### Notifications
637
145
  ```csharp
638
- // Dans le service, ajouter les notifications appropriees:
639
-
640
- // Creation
641
- await _notificationService.SendNotificationAsync(
642
- _currentUser.Id,
643
- NotificationType.{Entity}Created,
644
- t["notifications.created.title"],
645
- t["notifications.created.message", entity.Name],
646
- relatedEntityType: nameof({Entity}),
647
- relatedEntityId: entity.Id,
648
- actionUrl: $"/{area}/{module}/{entity.Id}");
649
-
650
- // Si assignation
651
- if (entity.AssignedToId.HasValue)
652
- {
653
- await _notificationService.SendNotificationAsync(
654
- entity.AssignedToId.Value,
655
- NotificationType.{Entity}Assigned,
656
- "{Entity} assignee",
657
- $"La {entity.Name} vous a ete assignee",
658
- relatedEntityType: nameof({Entity}),
659
- relatedEntityId: entity.Id,
660
- actionUrl: $"/{area}/{module}/{entity.Id}");
661
- }
146
+ await _notificationService.SendNotificationAsync(userId, NotificationType.{Entity}Created,
147
+ title, message, relatedEntityType: nameof({Entity}), relatedEntityId: entity.Id, actionUrl);
662
148
  ```
663
149
 
664
- #### 7.2 Workflow Email
665
-
150
+ #### Workflow Email
666
151
  ```csharp
667
- // 1. Creer le trigger
668
- // Dans WorkflowTriggerConfiguration.cs:
669
- new
670
- {
671
- Id = Guid.Parse("NEW-TRIGGER-GUID"),
672
- Code = "{entity}.created",
673
- Name = "{Entity} Created",
674
- AvailableVariablesJson = "[{\"Name\":\"entityId\"},{\"Name\":\"entityName\"},{\"Name\":\"creatorEmail\"}]",
675
- IsActive = true,
676
- CreatedAt = seedDate
677
- },
678
-
679
- // 2. Creer le workflow
680
- // Dans WorkflowConfiguration.cs:
681
- new
682
- {
683
- Id = Guid.Parse("NEW-WORKFLOW-GUID"),
684
- Code = "{entity}-created-notification",
685
- Name = "{Entity} Created Notification",
686
- TriggerId = Guid.Parse("TRIGGER-GUID"),
687
- IsActive = true,
688
- IsSystem = true,
689
- Priority = 10,
690
- CreatedAt = seedDate
691
- },
692
-
693
- // 3. Declencher dans le service
694
- await _workflowService.TriggerAsync(
695
- "{entity}.created",
696
- new Dictionary<string, object>
697
- {
698
- ["entityId"] = entity.Id,
699
- ["entityName"] = entity.Name,
700
- ["creatorEmail"] = _currentUser.Email
701
- });
152
+ // 1. WorkflowTriggerConfiguration.cs: new { Code = "{entity}.created", ... }
153
+ // 2. WorkflowConfiguration.cs: new { TriggerId = ..., ... }
154
+ // 3. Service:
155
+ await _workflowService.TriggerAsync("{entity}.created", new Dictionary<string, object>{...});
702
156
  ```
703
157
 
704
- #### 7.3 AI Integration
705
-
158
+ #### AI
706
159
  ```csharp
707
- // Si analyse IA requise:
708
- public async Task<{Entity}AnalysisResult?> AnalyzeAsync(Guid entityId, CancellationToken ct)
709
- {
710
- var entity = await _context.{Entity}s.FindAsync(entityId);
711
- if (entity == null) return null;
712
-
713
- var result = await _aiCompletionService
714
- .ExecutePromptByCodeWithValidationAsync<{Entity}AnalysisResult>(
715
- "{entity}-analyzer",
716
- new Dictionary<string, object>
717
- {
718
- ["entityName"] = entity.Name,
719
- ["entityDescription"] = entity.Description ?? ""
720
- },
721
- cancellationToken: ct);
722
-
723
- if (result.Success && result.IsValid)
724
- {
725
- _logger.LogInformation(
726
- "{Entity} {EntityId} analyzed: {Category}",
727
- entityId, result.Data.Category);
728
- return result.Data;
729
- }
730
-
731
- return null;
732
- }
160
+ var result = await _aiCompletionService.ExecutePromptByCodeWithValidationAsync<{Entity}AnalysisResult>(
161
+ "{entity}-analyzer", new Dictionary<string, object>{ ["name"] = entity.Name }, ct);
733
162
  ```
734
163
 
735
- ---
736
-
737
164
  ## CHECKLIST COMPLETE
738
165
 
739
- ### Domain Layer
740
- ```
741
- □ Entite {Entity}.cs creee
742
- □ Factory Method Create() implemente
743
- □ Behaviors (Update, Activate, etc.)
744
- □ Enum {Entity}Status.cs
745
- □ IAuditableEntity implemente
746
- ```
747
-
748
- ### Application Layer
749
- ```
750
- □ Interface I{Entity}Service.cs
751
- □ DTOs: {Entity}Dto, Create/Update Requests
752
- □ Permissions ajoutees dans Permissions.cs
753
- □ Permissions ajoutees dans PermissionConfiguration.cs
754
- ```
755
-
756
- ### Infrastructure Layer
166
+ ### Backend
757
167
  ```
758
- {Entity}Configuration.cs (EF Core)
759
- {Entity}Service.cs implementation
760
- Injection DI dans DependencyInjection.cs
761
- DbSet<{Entity}> dans ApplicationDbContext
762
- □ Migration EF Core creee
168
+ Domain: Entity + Factory + Behaviors + Enum + IAuditableEntity
169
+ Application: Interface + DTOs + Permissions (2 fichiers!)
170
+ Infrastructure: EF Config + Service + DI + DbSet + Migration
171
+ API: Controller + Authorize + RequirePermission + ProducesResponseType
763
172
  ```
764
173
 
765
- ### API Layer
174
+ ### Frontend
766
175
  ```
767
- □ {Entity}Controller.cs
768
- [Authorize] et [RequirePermission]
769
- [ProducesResponseType] documentes
770
- □ Logging dans les actions
771
- ```
772
-
773
- ### Web Layer
774
- ```
775
- □ {module}Api.ts (service API)
776
- □ use{Module}.ts (hook avec SignalR)
777
- □ {Module}Page.tsx (page principale)
778
- □ {Module}Form.tsx (formulaire)
779
- □ {Module}DetailPage.tsx (detail)
780
- □ i18n: fr/{module}.json + en/{module}.json
781
- □ Routes dans App.tsx
176
+ □ {module}Api.ts + use{Module}.ts (avec SignalR) + {Module}Page.tsx + {Module}Form.tsx
177
+ i18n: fr, en, it, de
178
+ Routes nested dans App.tsx
782
179
  ```
783
180
 
784
181
  ### Integrations
785
182
  ```
786
- □ Notifications:
787
- NotificationType ajoute
788
- SendNotificationAsync dans le service
789
- □ useSignalR dans le hook
790
- □ Workflows (si emails requis):
791
- □ Trigger cree
792
- □ Workflow cree
793
- □ TriggerAsync dans le service
794
- □ AI (si analyse requise):
795
- □ Prompt cree
796
- □ OutputSchema cree
797
- □ ExecutePromptAsync dans le service
183
+ □ Notifications: NotificationType + SendNotificationAsync + useSignalR
184
+ Workflows: Trigger + Workflow + TriggerAsync
185
+ AI: Prompt + OutputSchema + ExecutePromptAsync
798
186
  ```
799
187
 
800
188
  ### Validation
801
189
  ```
802
- □ dotnet build OK
803
- □ npm run build OK
804
- □ npm run lint OK
805
- □ Tests unitaires
806
- □ Test manuel E2E
190
+ □ dotnet build + npm run build + npm run lint OK
807
191
  ```
808
192
 
809
- ---
193
+ ## SKILLS ORCHESTRES
810
194
 
811
- ## SKILLS ASSOCIES
812
-
813
- Ce skill orchestre les skills suivants :
814
-
815
- | Skill | Phase | Action |
816
- |-------|-------|--------|
817
- | `/application` | 2-6 | Creation module full-stack |
818
- | `/controller` | 5 | Generation controller API |
819
- | `/notification` | 7.1 | Integration notifications |
820
- | `/workflow` | 7.2 | Integration workflows/emails |
821
- | `/ai-prompt` | 7.3 | Integration IA |
822
- | `/ui-components` | 6 | Composants UI (EntityCard) |
823
- | `/efcore:migration` | 4 | Migration EF Core |
824
-
825
- ---
195
+ | Skill | Phase |
196
+ |-------|-------|
197
+ | `/application` | 2-6 |
198
+ | `/controller` | 5 |
199
+ | `/notification` | 7.1 |
200
+ | `/workflow` | 7.2 |
201
+ | `/ai-prompt` | 7.3 |
202
+ | `/ui-components` | 6 |
203
+ | `/efcore:migration` | 4 |
826
204
 
827
205
  ## REGLES ABSOLUES
828
206
 
829
- 1. **TOUJOURS** suivre l'architecture en couches
830
- 2. **TOUJOURS** utiliser Factory Methods pour les entites
831
- 3. **TOUJOURS** implementer IAuditableEntity
832
- 4. **TOUJOURS** ajouter les permissions dans les 2 fichiers
833
- 5. **TOUJOURS** utiliser les hooks avec SignalR
834
- 6. **TOUJOURS** internationaliser (4 langues: fr, en, it, de)
835
- 7. **TOUJOURS** logger les operations importantes
836
- 8. **TOUJOURS** documenter l'API avec ProducesResponseType
837
- 9. **JAMAIS** d'acces DB direct depuis le frontend
838
- 10. **JAMAIS** de permissions hardcodees en strings
207
+ | DO | DON'T |
208
+ |----|-------|
209
+ | Architecture en couches | Acces DB direct frontend |
210
+ | Factory Methods entites | Permissions strings hardcodees |
211
+ | Permissions 2 fichiers | Routes plates |
212
+ | Hooks SignalR | Skip i18n 4 langues |
213
+ | ProducesResponseType | Skip logging |