@atlashub/smartstack-cli 1.5.1 → 1.5.3
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.
- package/.documentation/css/styles.css +2168 -2168
- package/.documentation/js/app.js +794 -794
- package/config/default-config.json +86 -86
- package/config/settings.json +53 -53
- package/config/settings.local.example.json +16 -16
- package/dist/index.js +0 -0
- package/dist/index.js.map +1 -1
- package/package.json +88 -88
- package/templates/agents/action.md +36 -36
- package/templates/agents/efcore/conflicts.md +84 -84
- package/templates/agents/efcore/db-deploy.md +51 -51
- package/templates/agents/efcore/db-reset.md +59 -59
- package/templates/agents/efcore/db-seed.md +56 -56
- package/templates/agents/efcore/db-status.md +64 -64
- package/templates/agents/efcore/migration.md +85 -85
- package/templates/agents/efcore/rebase-snapshot.md +62 -62
- package/templates/agents/efcore/scan.md +90 -90
- package/templates/agents/efcore/squash.md +67 -67
- package/templates/agents/explore-codebase.md +65 -65
- package/templates/agents/explore-docs.md +97 -97
- package/templates/agents/fix-grammar.md +49 -49
- package/templates/agents/gitflow/abort.md +45 -45
- package/templates/agents/gitflow/cleanup.md +85 -85
- package/templates/agents/gitflow/commit.md +40 -40
- package/templates/agents/gitflow/exec.md +48 -48
- package/templates/agents/gitflow/finish.md +92 -92
- package/templates/agents/gitflow/init.md +139 -139
- package/templates/agents/gitflow/merge.md +62 -62
- package/templates/agents/gitflow/plan.md +42 -42
- package/templates/agents/gitflow/pr.md +78 -78
- package/templates/agents/gitflow/review.md +49 -49
- package/templates/agents/gitflow/start.md +61 -61
- package/templates/agents/gitflow/status.md +32 -32
- package/templates/agents/snipper.md +36 -36
- package/templates/agents/websearch.md +46 -46
- package/templates/commands/_resources/formatting-guide.md +124 -124
- package/templates/commands/ai-prompt.md +315 -315
- package/templates/commands/apex/1-analyze.md +100 -100
- package/templates/commands/apex/2-plan.md +145 -145
- package/templates/commands/apex/3-execute.md +171 -171
- package/templates/commands/apex/4-examine.md +116 -116
- package/templates/commands/apex/5-tasks.md +209 -209
- package/templates/commands/apex.md +76 -76
- package/templates/commands/application/create.md +362 -362
- package/templates/commands/application/templates-backend.md +463 -463
- package/templates/commands/application/templates-frontend.md +517 -517
- package/templates/commands/application/templates-i18n.md +478 -478
- package/templates/commands/application/templates-seed.md +362 -362
- package/templates/commands/application.md +303 -303
- package/templates/commands/business-analyse/0-orchestrate.md +640 -640
- package/templates/commands/business-analyse/1-init.md +269 -269
- package/templates/commands/business-analyse/2-discover.md +520 -520
- package/templates/commands/business-analyse/3-analyse.md +408 -408
- package/templates/commands/business-analyse/4-specify.md +598 -598
- package/templates/commands/business-analyse/5-validate.md +326 -326
- package/templates/commands/business-analyse/6-handoff.md +746 -746
- package/templates/commands/business-analyse/7-doc-html.md +602 -602
- package/templates/commands/business-analyse/bug.md +325 -325
- package/templates/commands/business-analyse/change-request.md +368 -368
- package/templates/commands/business-analyse/hotfix.md +200 -200
- package/templates/commands/business-analyse.md +640 -640
- package/templates/commands/controller/create.md +216 -216
- package/templates/commands/controller/postman-templates.md +528 -528
- package/templates/commands/controller/templates.md +600 -600
- package/templates/commands/controller.md +337 -337
- package/templates/commands/create/agent.md +138 -138
- package/templates/commands/create/command.md +166 -166
- package/templates/commands/create/hook.md +234 -234
- package/templates/commands/create/plugin.md +329 -329
- package/templates/commands/create/project.md +507 -507
- package/templates/commands/create/skill.md +199 -199
- package/templates/commands/create.md +220 -220
- package/templates/commands/debug.md +95 -95
- package/templates/commands/documentation/module.md +202 -202
- package/templates/commands/documentation/templates.md +432 -432
- package/templates/commands/documentation.md +190 -190
- package/templates/commands/efcore/_env-check.md +153 -153
- package/templates/commands/efcore/conflicts.md +186 -186
- package/templates/commands/efcore/db-deploy.md +193 -193
- package/templates/commands/efcore/db-reset.md +426 -426
- package/templates/commands/efcore/db-seed.md +326 -326
- package/templates/commands/efcore/db-status.md +226 -226
- package/templates/commands/efcore/migration.md +400 -400
- package/templates/commands/efcore/rebase-snapshot.md +264 -264
- package/templates/commands/efcore/scan.md +198 -198
- package/templates/commands/efcore/squash.md +298 -298
- package/templates/commands/efcore.md +224 -224
- package/templates/commands/epct.md +69 -69
- package/templates/commands/explain.md +186 -186
- package/templates/commands/explore.md +45 -45
- package/templates/commands/feature-full.md +267 -267
- package/templates/commands/gitflow/1-init.md +1038 -1038
- package/templates/commands/gitflow/10-start.md +768 -768
- package/templates/commands/gitflow/11-finish.md +457 -457
- package/templates/commands/gitflow/12-cleanup.md +276 -276
- package/templates/commands/gitflow/13-sync.md +216 -216
- package/templates/commands/gitflow/14-rebase.md +251 -251
- package/templates/commands/gitflow/2-status.md +277 -277
- package/templates/commands/gitflow/3-commit.md +344 -344
- package/templates/commands/gitflow/4-plan.md +145 -145
- package/templates/commands/gitflow/5-exec.md +147 -147
- package/templates/commands/gitflow/6-abort.md +344 -344
- package/templates/commands/gitflow/7-pull-request.md +453 -355
- package/templates/commands/gitflow/8-review.md +240 -176
- package/templates/commands/gitflow/9-merge.md +451 -365
- package/templates/commands/gitflow.md +128 -128
- package/templates/commands/implement.md +663 -663
- package/templates/commands/init.md +567 -567
- package/templates/commands/mcp-integration.md +330 -330
- package/templates/commands/notification.md +129 -129
- package/templates/commands/oneshot.md +57 -57
- package/templates/commands/quick-search.md +72 -72
- package/templates/commands/ralph-loop/cancel-ralph.md +18 -18
- package/templates/commands/ralph-loop/help.md +126 -126
- package/templates/commands/ralph-loop/ralph-loop.md +18 -18
- package/templates/commands/review.md +106 -106
- package/templates/commands/utils/test-web-config.md +160 -160
- package/templates/commands/utils/test-web.md +151 -151
- package/templates/commands/validate.md +233 -233
- package/templates/commands/workflow.md +193 -193
- package/templates/gitflow/config.json +138 -138
- package/templates/hooks/ef-migration-check.md +139 -139
- package/templates/hooks/hooks.json +25 -25
- package/templates/hooks/stop-hook.sh +177 -177
- package/templates/skills/ai-prompt/SKILL.md +778 -778
- package/templates/skills/application/SKILL.md +563 -563
- package/templates/skills/application/templates-backend.md +450 -450
- package/templates/skills/application/templates-frontend.md +531 -531
- package/templates/skills/application/templates-i18n.md +520 -520
- package/templates/skills/application/templates-seed.md +647 -647
- package/templates/skills/business-analyse/SKILL.md +191 -191
- package/templates/skills/business-analyse/questionnaire.md +283 -283
- package/templates/skills/business-analyse/templates-frd.md +477 -477
- package/templates/skills/business-analyse/templates-react.md +580 -580
- package/templates/skills/controller/SKILL.md +240 -240
- package/templates/skills/controller/postman-templates.md +614 -614
- package/templates/skills/controller/templates.md +1468 -1468
- package/templates/skills/documentation/SKILL.md +133 -133
- package/templates/skills/documentation/templates.md +476 -476
- package/templates/skills/feature-full/SKILL.md +838 -838
- package/templates/skills/notification/SKILL.md +555 -555
- package/templates/skills/ui-components/SKILL.md +870 -870
- package/templates/skills/workflow/SKILL.md +582 -582
- package/templates/test-web/api-health.json +38 -38
- package/templates/test-web/minimal.json +19 -19
- package/templates/test-web/npm-package.json +46 -46
- package/templates/test-web/seo-check.json +54 -54
|
@@ -1,463 +1,463 @@
|
|
|
1
|
-
# Templates Backend - Application Skill
|
|
2
|
-
|
|
3
|
-
> Ces templates génèrent le code C# pour les nouvelles applications/modules.
|
|
4
|
-
> **RAPPEL:** Seules les applications dans le context `business` sont autorisées.
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## TEMPLATE: PERMISSIONS CLASS
|
|
9
|
-
|
|
10
|
-
```csharp
|
|
11
|
-
// Ajouter dans src/SmartStack.Application/Common/Authorization/Permissions.cs
|
|
12
|
-
|
|
13
|
-
// IMPORTANT: Les permissions client sont TOUJOURS sous "business.*"
|
|
14
|
-
public static class Business
|
|
15
|
-
{
|
|
16
|
-
public const string Access = "business";
|
|
17
|
-
|
|
18
|
-
public static class $APP_PASCAL
|
|
19
|
-
{
|
|
20
|
-
public const string Access = "business.$app";
|
|
21
|
-
|
|
22
|
-
public static class $MODULE_PASCAL
|
|
23
|
-
{
|
|
24
|
-
public const string View = "business.$app.$module.read";
|
|
25
|
-
public const string Create = "business.$app.$module.create";
|
|
26
|
-
public const string Update = "business.$app.$module.update";
|
|
27
|
-
public const string Delete = "business.$app.$module.delete";
|
|
28
|
-
public const string Assign = "business.$app.$module.assign";
|
|
29
|
-
public const string Execute = "business.$app.$module.execute";
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### Exemple pour Business > CRM > Leads
|
|
36
|
-
|
|
37
|
-
```csharp
|
|
38
|
-
public static class Business
|
|
39
|
-
{
|
|
40
|
-
public const string Access = "business";
|
|
41
|
-
|
|
42
|
-
public static class Crm
|
|
43
|
-
{
|
|
44
|
-
public const string Access = "business.crm";
|
|
45
|
-
|
|
46
|
-
public static class Leads
|
|
47
|
-
{
|
|
48
|
-
public const string View = "business.crm.leads.read";
|
|
49
|
-
public const string Create = "business.crm.leads.create";
|
|
50
|
-
public const string Update = "business.crm.leads.update";
|
|
51
|
-
public const string Delete = "business.crm.leads.delete";
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
## TEMPLATE: SERVICE INTERFACE
|
|
60
|
-
|
|
61
|
-
```csharp
|
|
62
|
-
// src/SmartStack.Application/Common/Interfaces/I{Module}Service.cs
|
|
63
|
-
|
|
64
|
-
using SmartStack.Application.$MODULE_PASCAL.Models;
|
|
65
|
-
|
|
66
|
-
namespace SmartStack.Application.Common.Interfaces;
|
|
67
|
-
|
|
68
|
-
public interface I$MODULE_PASCALService
|
|
69
|
-
{
|
|
70
|
-
Task<PagedResult<$ENTITY_PASCALDto>> GetAllAsync(
|
|
71
|
-
$ENTITY_PASCALQueryParameters parameters,
|
|
72
|
-
CancellationToken cancellationToken = default);
|
|
73
|
-
|
|
74
|
-
Task<$ENTITY_PASCALDto?> GetByIdAsync(
|
|
75
|
-
Guid id,
|
|
76
|
-
CancellationToken cancellationToken = default);
|
|
77
|
-
|
|
78
|
-
Task<$ENTITY_PASCALDto> CreateAsync(
|
|
79
|
-
Create$ENTITY_PASCALRequest request,
|
|
80
|
-
CancellationToken cancellationToken = default);
|
|
81
|
-
|
|
82
|
-
Task<$ENTITY_PASCALDto> UpdateAsync(
|
|
83
|
-
Guid id,
|
|
84
|
-
Update$ENTITY_PASCALRequest request,
|
|
85
|
-
CancellationToken cancellationToken = default);
|
|
86
|
-
|
|
87
|
-
Task<bool> DeleteAsync(
|
|
88
|
-
Guid id,
|
|
89
|
-
CancellationToken cancellationToken = default);
|
|
90
|
-
}
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## TEMPLATE: SERVICE IMPLEMENTATION
|
|
96
|
-
|
|
97
|
-
```csharp
|
|
98
|
-
// src/SmartStack.Infrastructure/Services/$MODULE_PASCAL/$MODULE_PASCALService.cs
|
|
99
|
-
|
|
100
|
-
using Microsoft.EntityFrameworkCore;
|
|
101
|
-
using Microsoft.Extensions.Logging;
|
|
102
|
-
using SmartStack.Application.Common.Interfaces;
|
|
103
|
-
using SmartStack.Application.$MODULE_PASCAL.Models;
|
|
104
|
-
using SmartStack.Domain.$MODULE_PASCAL;
|
|
105
|
-
|
|
106
|
-
namespace SmartStack.Infrastructure.Services.$MODULE_PASCAL;
|
|
107
|
-
|
|
108
|
-
public class $MODULE_PASCALService : I$MODULE_PASCALService
|
|
109
|
-
{
|
|
110
|
-
private readonly IApplicationDbContext _context;
|
|
111
|
-
private readonly ICurrentUserService _currentUser;
|
|
112
|
-
private readonly ILogger<$MODULE_PASCALService> _logger;
|
|
113
|
-
|
|
114
|
-
public $MODULE_PASCALService(
|
|
115
|
-
IApplicationDbContext context,
|
|
116
|
-
ICurrentUserService currentUser,
|
|
117
|
-
ILogger<$MODULE_PASCALService> logger)
|
|
118
|
-
{
|
|
119
|
-
_context = context;
|
|
120
|
-
_currentUser = currentUser;
|
|
121
|
-
_logger = logger;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
public async Task<PagedResult<$ENTITY_PASCALDto>> GetAllAsync(
|
|
125
|
-
$ENTITY_PASCALQueryParameters parameters,
|
|
126
|
-
CancellationToken cancellationToken = default)
|
|
127
|
-
{
|
|
128
|
-
var query = _context.$ENTITY_PLURAL
|
|
129
|
-
.AsNoTracking();
|
|
130
|
-
|
|
131
|
-
// Apply filters
|
|
132
|
-
if (!string.IsNullOrWhiteSpace(parameters.SearchTerm))
|
|
133
|
-
{
|
|
134
|
-
query = query.Where(x =>
|
|
135
|
-
x.Name.Contains(parameters.SearchTerm) ||
|
|
136
|
-
x.Description.Contains(parameters.SearchTerm));
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Apply sorting
|
|
140
|
-
query = parameters.SortColumn?.ToLower() switch
|
|
141
|
-
{
|
|
142
|
-
"name" => parameters.SortDirection == "desc"
|
|
143
|
-
? query.OrderByDescending(x => x.Name)
|
|
144
|
-
: query.OrderBy(x => x.Name),
|
|
145
|
-
"createdat" => parameters.SortDirection == "desc"
|
|
146
|
-
? query.OrderByDescending(x => x.CreatedAt)
|
|
147
|
-
: query.OrderBy(x => x.CreatedAt),
|
|
148
|
-
_ => query.OrderByDescending(x => x.CreatedAt)
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
var totalCount = await query.CountAsync(cancellationToken);
|
|
152
|
-
|
|
153
|
-
var items = await query
|
|
154
|
-
.Skip((parameters.Page - 1) * parameters.PageSize)
|
|
155
|
-
.Take(parameters.PageSize)
|
|
156
|
-
.Select(x => new $ENTITY_PASCALDto
|
|
157
|
-
{
|
|
158
|
-
Id = x.Id,
|
|
159
|
-
Name = x.Name,
|
|
160
|
-
Description = x.Description,
|
|
161
|
-
IsActive = x.IsActive,
|
|
162
|
-
CreatedAt = x.CreatedAt,
|
|
163
|
-
UpdatedAt = x.UpdatedAt
|
|
164
|
-
})
|
|
165
|
-
.ToListAsync(cancellationToken);
|
|
166
|
-
|
|
167
|
-
return new PagedResult<$ENTITY_PASCALDto>
|
|
168
|
-
{
|
|
169
|
-
Items = items,
|
|
170
|
-
TotalCount = totalCount,
|
|
171
|
-
Page = parameters.Page,
|
|
172
|
-
PageSize = parameters.PageSize
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
public async Task<$ENTITY_PASCALDto?> GetByIdAsync(
|
|
177
|
-
Guid id,
|
|
178
|
-
CancellationToken cancellationToken = default)
|
|
179
|
-
{
|
|
180
|
-
var entity = await _context.$ENTITY_PLURAL
|
|
181
|
-
.AsNoTracking()
|
|
182
|
-
.FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
|
|
183
|
-
|
|
184
|
-
if (entity == null)
|
|
185
|
-
return null;
|
|
186
|
-
|
|
187
|
-
return new $ENTITY_PASCALDto
|
|
188
|
-
{
|
|
189
|
-
Id = entity.Id,
|
|
190
|
-
Name = entity.Name,
|
|
191
|
-
Description = entity.Description,
|
|
192
|
-
IsActive = entity.IsActive,
|
|
193
|
-
CreatedAt = entity.CreatedAt,
|
|
194
|
-
UpdatedAt = entity.UpdatedAt
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
public async Task<$ENTITY_PASCALDto> CreateAsync(
|
|
199
|
-
Create$ENTITY_PASCALRequest request,
|
|
200
|
-
CancellationToken cancellationToken = default)
|
|
201
|
-
{
|
|
202
|
-
var entity = $ENTITY_PASCAL.Create(
|
|
203
|
-
request.Name,
|
|
204
|
-
request.Description);
|
|
205
|
-
|
|
206
|
-
_context.$ENTITY_PLURAL.Add(entity);
|
|
207
|
-
await _context.SaveChangesAsync(cancellationToken);
|
|
208
|
-
|
|
209
|
-
_logger.LogInformation(
|
|
210
|
-
"User {User} created $ENTITY_PASCAL {Id} ({Name})",
|
|
211
|
-
_currentUser.Email,
|
|
212
|
-
entity.Id,
|
|
213
|
-
entity.Name);
|
|
214
|
-
|
|
215
|
-
return new $ENTITY_PASCALDto
|
|
216
|
-
{
|
|
217
|
-
Id = entity.Id,
|
|
218
|
-
Name = entity.Name,
|
|
219
|
-
Description = entity.Description,
|
|
220
|
-
IsActive = entity.IsActive,
|
|
221
|
-
CreatedAt = entity.CreatedAt
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
public async Task<$ENTITY_PASCALDto> UpdateAsync(
|
|
226
|
-
Guid id,
|
|
227
|
-
Update$ENTITY_PASCALRequest request,
|
|
228
|
-
CancellationToken cancellationToken = default)
|
|
229
|
-
{
|
|
230
|
-
var entity = await _context.$ENTITY_PLURAL
|
|
231
|
-
.FirstOrDefaultAsync(x => x.Id == id, cancellationToken)
|
|
232
|
-
?? throw new NotFoundException("$ENTITY_PASCAL", id);
|
|
233
|
-
|
|
234
|
-
entity.Update(request.Name, request.Description);
|
|
235
|
-
|
|
236
|
-
await _context.SaveChangesAsync(cancellationToken);
|
|
237
|
-
|
|
238
|
-
_logger.LogInformation(
|
|
239
|
-
"User {User} updated $ENTITY_PASCAL {Id} ({Name})",
|
|
240
|
-
_currentUser.Email,
|
|
241
|
-
entity.Id,
|
|
242
|
-
entity.Name);
|
|
243
|
-
|
|
244
|
-
return new $ENTITY_PASCALDto
|
|
245
|
-
{
|
|
246
|
-
Id = entity.Id,
|
|
247
|
-
Name = entity.Name,
|
|
248
|
-
Description = entity.Description,
|
|
249
|
-
IsActive = entity.IsActive,
|
|
250
|
-
CreatedAt = entity.CreatedAt,
|
|
251
|
-
UpdatedAt = entity.UpdatedAt
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
public async Task<bool> DeleteAsync(
|
|
256
|
-
Guid id,
|
|
257
|
-
CancellationToken cancellationToken = default)
|
|
258
|
-
{
|
|
259
|
-
var entity = await _context.$ENTITY_PLURAL
|
|
260
|
-
.FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
|
|
261
|
-
|
|
262
|
-
if (entity == null)
|
|
263
|
-
return false;
|
|
264
|
-
|
|
265
|
-
_context.$ENTITY_PLURAL.Remove(entity);
|
|
266
|
-
await _context.SaveChangesAsync(cancellationToken);
|
|
267
|
-
|
|
268
|
-
_logger.LogWarning(
|
|
269
|
-
"User {User} deleted $ENTITY_PASCAL {Id} ({Name})",
|
|
270
|
-
_currentUser.Email,
|
|
271
|
-
id,
|
|
272
|
-
entity.Name);
|
|
273
|
-
|
|
274
|
-
return true;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
---
|
|
280
|
-
|
|
281
|
-
## TEMPLATE: DTOs
|
|
282
|
-
|
|
283
|
-
```csharp
|
|
284
|
-
// src/SmartStack.Application/$MODULE_PASCAL/Models/$ENTITY_PASCALDto.cs
|
|
285
|
-
|
|
286
|
-
namespace SmartStack.Application.$MODULE_PASCAL.Models;
|
|
287
|
-
|
|
288
|
-
public record $ENTITY_PASCALDto
|
|
289
|
-
{
|
|
290
|
-
public Guid Id { get; init; }
|
|
291
|
-
public string Name { get; init; } = null!;
|
|
292
|
-
public string? Description { get; init; }
|
|
293
|
-
public bool IsActive { get; init; }
|
|
294
|
-
public DateTime CreatedAt { get; init; }
|
|
295
|
-
public DateTime? UpdatedAt { get; init; }
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
public record Create$ENTITY_PASCALRequest
|
|
299
|
-
{
|
|
300
|
-
public string Name { get; init; } = null!;
|
|
301
|
-
public string? Description { get; init; }
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
public record Update$ENTITY_PASCALRequest
|
|
305
|
-
{
|
|
306
|
-
public string Name { get; init; } = null!;
|
|
307
|
-
public string? Description { get; init; }
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
public record $ENTITY_PASCALQueryParameters
|
|
311
|
-
{
|
|
312
|
-
public int Page { get; init; } = 1;
|
|
313
|
-
public int PageSize { get; init; } = 10;
|
|
314
|
-
public string? SearchTerm { get; init; }
|
|
315
|
-
public string? SortColumn { get; init; } = "createdAt";
|
|
316
|
-
public string? SortDirection { get; init; } = "desc";
|
|
317
|
-
}
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
---
|
|
321
|
-
|
|
322
|
-
## TEMPLATE: DOMAIN ENTITY
|
|
323
|
-
|
|
324
|
-
```csharp
|
|
325
|
-
// src/SmartStack.Domain/$MODULE_PASCAL/$ENTITY_PASCAL.cs
|
|
326
|
-
|
|
327
|
-
using SmartStack.Domain.Common;
|
|
328
|
-
|
|
329
|
-
namespace SmartStack.Domain.$MODULE_PASCAL;
|
|
330
|
-
|
|
331
|
-
public class $ENTITY_PASCAL : BaseEntity
|
|
332
|
-
{
|
|
333
|
-
public string Name { get; private set; } = null!;
|
|
334
|
-
public string? Description { get; private set; }
|
|
335
|
-
public bool IsActive { get; private set; }
|
|
336
|
-
|
|
337
|
-
private $ENTITY_PASCAL() { }
|
|
338
|
-
|
|
339
|
-
public static $ENTITY_PASCAL Create(string name, string? description = null)
|
|
340
|
-
{
|
|
341
|
-
if (string.IsNullOrWhiteSpace(name))
|
|
342
|
-
throw new Exceptions.DomainException("Name is required");
|
|
343
|
-
|
|
344
|
-
return new $ENTITY_PASCAL
|
|
345
|
-
{
|
|
346
|
-
Id = Guid.NewGuid(),
|
|
347
|
-
Name = name,
|
|
348
|
-
Description = description,
|
|
349
|
-
IsActive = true,
|
|
350
|
-
CreatedAt = DateTime.UtcNow
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
public void Update(string name, string? description)
|
|
355
|
-
{
|
|
356
|
-
if (string.IsNullOrWhiteSpace(name))
|
|
357
|
-
throw new Exceptions.DomainException("Name is required");
|
|
358
|
-
|
|
359
|
-
Name = name;
|
|
360
|
-
Description = description;
|
|
361
|
-
UpdatedAt = DateTime.UtcNow;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
public void Activate() => IsActive = true;
|
|
365
|
-
public void Deactivate() => IsActive = false;
|
|
366
|
-
}
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
---
|
|
370
|
-
|
|
371
|
-
## TEMPLATE: EF CONFIGURATION
|
|
372
|
-
|
|
373
|
-
```csharp
|
|
374
|
-
// src/SmartStack.Infrastructure/Persistence/Configurations/$MODULE_PASCAL/$ENTITY_PASCALConfiguration.cs
|
|
375
|
-
|
|
376
|
-
using Microsoft.EntityFrameworkCore;
|
|
377
|
-
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
|
378
|
-
using SmartStack.Domain.$MODULE_PASCAL;
|
|
379
|
-
|
|
380
|
-
namespace SmartStack.Infrastructure.Persistence.Configurations.$MODULE_PASCAL;
|
|
381
|
-
|
|
382
|
-
public class $ENTITY_PASCALConfiguration : IEntityTypeConfiguration<$ENTITY_PASCAL>
|
|
383
|
-
{
|
|
384
|
-
public void Configure(EntityTypeBuilder<$ENTITY_PASCAL> builder)
|
|
385
|
-
{
|
|
386
|
-
// Tables métier client dans le schéma "biz" (business)
|
|
387
|
-
builder.ToTable("$ENTITY_PLURAL", "biz");
|
|
388
|
-
|
|
389
|
-
builder.HasKey(x => x.Id);
|
|
390
|
-
|
|
391
|
-
builder.Property(x => x.Name)
|
|
392
|
-
.HasMaxLength(200)
|
|
393
|
-
.IsRequired();
|
|
394
|
-
|
|
395
|
-
builder.Property(x => x.Description)
|
|
396
|
-
.HasMaxLength(1000);
|
|
397
|
-
|
|
398
|
-
builder.HasIndex(x => x.Name)
|
|
399
|
-
.IsUnique();
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
---
|
|
405
|
-
|
|
406
|
-
## TEMPLATE: DBCONTEXT UPDATE
|
|
407
|
-
|
|
408
|
-
```csharp
|
|
409
|
-
// Ajouter dans IApplicationDbContext.cs
|
|
410
|
-
DbSet<$ENTITY_PASCAL> $ENTITY_PLURAL { get; }
|
|
411
|
-
|
|
412
|
-
// Ajouter dans ApplicationDbContext.cs
|
|
413
|
-
public DbSet<$ENTITY_PASCAL> $ENTITY_PLURAL => Set<$ENTITY_PASCAL>();
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
---
|
|
417
|
-
|
|
418
|
-
## TEMPLATE: DI REGISTRATION
|
|
419
|
-
|
|
420
|
-
```csharp
|
|
421
|
-
// Ajouter dans src/SmartStack.Infrastructure/DependencyInjection.cs
|
|
422
|
-
|
|
423
|
-
services.AddScoped<I$MODULE_PASCALService, $MODULE_PASCALService>();
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
---
|
|
427
|
-
|
|
428
|
-
## CHAÎNAGE AVEC /controller:create
|
|
429
|
-
|
|
430
|
-
Après génération des templates backend, le skill appelle automatiquement :
|
|
431
|
-
|
|
432
|
-
```
|
|
433
|
-
/controller:create Business $MODULE $ENTITY
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
Exemple :
|
|
437
|
-
```
|
|
438
|
-
/controller:create Business Leads Lead
|
|
439
|
-
```
|
|
440
|
-
|
|
441
|
-
Cela génère :
|
|
442
|
-
- Controller avec CRUD complet
|
|
443
|
-
- Endpoints REST
|
|
444
|
-
- ProducesResponseType
|
|
445
|
-
- Logging approprié
|
|
446
|
-
- Tests Postman
|
|
447
|
-
|
|
448
|
-
---
|
|
449
|
-
|
|
450
|
-
## CHECKLIST BACKEND
|
|
451
|
-
|
|
452
|
-
| Vérification | Status |
|
|
453
|
-
|--------------|--------|
|
|
454
|
-
| ☐ Permissions.cs mis à jour (sous Business.*) | |
|
|
455
|
-
| ☐ Service interface créée | |
|
|
456
|
-
| ☐ Service implementation créée | |
|
|
457
|
-
| ☐ DTOs créés | |
|
|
458
|
-
| ☐ Domain entity créée | |
|
|
459
|
-
| ☐ EF Configuration créée (schéma "biz") | |
|
|
460
|
-
| ☐ DbContext mis à jour | |
|
|
461
|
-
| ☐ DI registration ajoutée | |
|
|
462
|
-
| ☐ /controller:create exécuté | |
|
|
463
|
-
| ☐ dotnet build réussi | |
|
|
1
|
+
# Templates Backend - Application Skill
|
|
2
|
+
|
|
3
|
+
> Ces templates génèrent le code C# pour les nouvelles applications/modules.
|
|
4
|
+
> **RAPPEL:** Seules les applications dans le context `business` sont autorisées.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## TEMPLATE: PERMISSIONS CLASS
|
|
9
|
+
|
|
10
|
+
```csharp
|
|
11
|
+
// Ajouter dans src/SmartStack.Application/Common/Authorization/Permissions.cs
|
|
12
|
+
|
|
13
|
+
// IMPORTANT: Les permissions client sont TOUJOURS sous "business.*"
|
|
14
|
+
public static class Business
|
|
15
|
+
{
|
|
16
|
+
public const string Access = "business";
|
|
17
|
+
|
|
18
|
+
public static class $APP_PASCAL
|
|
19
|
+
{
|
|
20
|
+
public const string Access = "business.$app";
|
|
21
|
+
|
|
22
|
+
public static class $MODULE_PASCAL
|
|
23
|
+
{
|
|
24
|
+
public const string View = "business.$app.$module.read";
|
|
25
|
+
public const string Create = "business.$app.$module.create";
|
|
26
|
+
public const string Update = "business.$app.$module.update";
|
|
27
|
+
public const string Delete = "business.$app.$module.delete";
|
|
28
|
+
public const string Assign = "business.$app.$module.assign";
|
|
29
|
+
public const string Execute = "business.$app.$module.execute";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Exemple pour Business > CRM > Leads
|
|
36
|
+
|
|
37
|
+
```csharp
|
|
38
|
+
public static class Business
|
|
39
|
+
{
|
|
40
|
+
public const string Access = "business";
|
|
41
|
+
|
|
42
|
+
public static class Crm
|
|
43
|
+
{
|
|
44
|
+
public const string Access = "business.crm";
|
|
45
|
+
|
|
46
|
+
public static class Leads
|
|
47
|
+
{
|
|
48
|
+
public const string View = "business.crm.leads.read";
|
|
49
|
+
public const string Create = "business.crm.leads.create";
|
|
50
|
+
public const string Update = "business.crm.leads.update";
|
|
51
|
+
public const string Delete = "business.crm.leads.delete";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## TEMPLATE: SERVICE INTERFACE
|
|
60
|
+
|
|
61
|
+
```csharp
|
|
62
|
+
// src/SmartStack.Application/Common/Interfaces/I{Module}Service.cs
|
|
63
|
+
|
|
64
|
+
using SmartStack.Application.$MODULE_PASCAL.Models;
|
|
65
|
+
|
|
66
|
+
namespace SmartStack.Application.Common.Interfaces;
|
|
67
|
+
|
|
68
|
+
public interface I$MODULE_PASCALService
|
|
69
|
+
{
|
|
70
|
+
Task<PagedResult<$ENTITY_PASCALDto>> GetAllAsync(
|
|
71
|
+
$ENTITY_PASCALQueryParameters parameters,
|
|
72
|
+
CancellationToken cancellationToken = default);
|
|
73
|
+
|
|
74
|
+
Task<$ENTITY_PASCALDto?> GetByIdAsync(
|
|
75
|
+
Guid id,
|
|
76
|
+
CancellationToken cancellationToken = default);
|
|
77
|
+
|
|
78
|
+
Task<$ENTITY_PASCALDto> CreateAsync(
|
|
79
|
+
Create$ENTITY_PASCALRequest request,
|
|
80
|
+
CancellationToken cancellationToken = default);
|
|
81
|
+
|
|
82
|
+
Task<$ENTITY_PASCALDto> UpdateAsync(
|
|
83
|
+
Guid id,
|
|
84
|
+
Update$ENTITY_PASCALRequest request,
|
|
85
|
+
CancellationToken cancellationToken = default);
|
|
86
|
+
|
|
87
|
+
Task<bool> DeleteAsync(
|
|
88
|
+
Guid id,
|
|
89
|
+
CancellationToken cancellationToken = default);
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## TEMPLATE: SERVICE IMPLEMENTATION
|
|
96
|
+
|
|
97
|
+
```csharp
|
|
98
|
+
// src/SmartStack.Infrastructure/Services/$MODULE_PASCAL/$MODULE_PASCALService.cs
|
|
99
|
+
|
|
100
|
+
using Microsoft.EntityFrameworkCore;
|
|
101
|
+
using Microsoft.Extensions.Logging;
|
|
102
|
+
using SmartStack.Application.Common.Interfaces;
|
|
103
|
+
using SmartStack.Application.$MODULE_PASCAL.Models;
|
|
104
|
+
using SmartStack.Domain.$MODULE_PASCAL;
|
|
105
|
+
|
|
106
|
+
namespace SmartStack.Infrastructure.Services.$MODULE_PASCAL;
|
|
107
|
+
|
|
108
|
+
public class $MODULE_PASCALService : I$MODULE_PASCALService
|
|
109
|
+
{
|
|
110
|
+
private readonly IApplicationDbContext _context;
|
|
111
|
+
private readonly ICurrentUserService _currentUser;
|
|
112
|
+
private readonly ILogger<$MODULE_PASCALService> _logger;
|
|
113
|
+
|
|
114
|
+
public $MODULE_PASCALService(
|
|
115
|
+
IApplicationDbContext context,
|
|
116
|
+
ICurrentUserService currentUser,
|
|
117
|
+
ILogger<$MODULE_PASCALService> logger)
|
|
118
|
+
{
|
|
119
|
+
_context = context;
|
|
120
|
+
_currentUser = currentUser;
|
|
121
|
+
_logger = logger;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public async Task<PagedResult<$ENTITY_PASCALDto>> GetAllAsync(
|
|
125
|
+
$ENTITY_PASCALQueryParameters parameters,
|
|
126
|
+
CancellationToken cancellationToken = default)
|
|
127
|
+
{
|
|
128
|
+
var query = _context.$ENTITY_PLURAL
|
|
129
|
+
.AsNoTracking();
|
|
130
|
+
|
|
131
|
+
// Apply filters
|
|
132
|
+
if (!string.IsNullOrWhiteSpace(parameters.SearchTerm))
|
|
133
|
+
{
|
|
134
|
+
query = query.Where(x =>
|
|
135
|
+
x.Name.Contains(parameters.SearchTerm) ||
|
|
136
|
+
x.Description.Contains(parameters.SearchTerm));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Apply sorting
|
|
140
|
+
query = parameters.SortColumn?.ToLower() switch
|
|
141
|
+
{
|
|
142
|
+
"name" => parameters.SortDirection == "desc"
|
|
143
|
+
? query.OrderByDescending(x => x.Name)
|
|
144
|
+
: query.OrderBy(x => x.Name),
|
|
145
|
+
"createdat" => parameters.SortDirection == "desc"
|
|
146
|
+
? query.OrderByDescending(x => x.CreatedAt)
|
|
147
|
+
: query.OrderBy(x => x.CreatedAt),
|
|
148
|
+
_ => query.OrderByDescending(x => x.CreatedAt)
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
var totalCount = await query.CountAsync(cancellationToken);
|
|
152
|
+
|
|
153
|
+
var items = await query
|
|
154
|
+
.Skip((parameters.Page - 1) * parameters.PageSize)
|
|
155
|
+
.Take(parameters.PageSize)
|
|
156
|
+
.Select(x => new $ENTITY_PASCALDto
|
|
157
|
+
{
|
|
158
|
+
Id = x.Id,
|
|
159
|
+
Name = x.Name,
|
|
160
|
+
Description = x.Description,
|
|
161
|
+
IsActive = x.IsActive,
|
|
162
|
+
CreatedAt = x.CreatedAt,
|
|
163
|
+
UpdatedAt = x.UpdatedAt
|
|
164
|
+
})
|
|
165
|
+
.ToListAsync(cancellationToken);
|
|
166
|
+
|
|
167
|
+
return new PagedResult<$ENTITY_PASCALDto>
|
|
168
|
+
{
|
|
169
|
+
Items = items,
|
|
170
|
+
TotalCount = totalCount,
|
|
171
|
+
Page = parameters.Page,
|
|
172
|
+
PageSize = parameters.PageSize
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
public async Task<$ENTITY_PASCALDto?> GetByIdAsync(
|
|
177
|
+
Guid id,
|
|
178
|
+
CancellationToken cancellationToken = default)
|
|
179
|
+
{
|
|
180
|
+
var entity = await _context.$ENTITY_PLURAL
|
|
181
|
+
.AsNoTracking()
|
|
182
|
+
.FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
|
|
183
|
+
|
|
184
|
+
if (entity == null)
|
|
185
|
+
return null;
|
|
186
|
+
|
|
187
|
+
return new $ENTITY_PASCALDto
|
|
188
|
+
{
|
|
189
|
+
Id = entity.Id,
|
|
190
|
+
Name = entity.Name,
|
|
191
|
+
Description = entity.Description,
|
|
192
|
+
IsActive = entity.IsActive,
|
|
193
|
+
CreatedAt = entity.CreatedAt,
|
|
194
|
+
UpdatedAt = entity.UpdatedAt
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
public async Task<$ENTITY_PASCALDto> CreateAsync(
|
|
199
|
+
Create$ENTITY_PASCALRequest request,
|
|
200
|
+
CancellationToken cancellationToken = default)
|
|
201
|
+
{
|
|
202
|
+
var entity = $ENTITY_PASCAL.Create(
|
|
203
|
+
request.Name,
|
|
204
|
+
request.Description);
|
|
205
|
+
|
|
206
|
+
_context.$ENTITY_PLURAL.Add(entity);
|
|
207
|
+
await _context.SaveChangesAsync(cancellationToken);
|
|
208
|
+
|
|
209
|
+
_logger.LogInformation(
|
|
210
|
+
"User {User} created $ENTITY_PASCAL {Id} ({Name})",
|
|
211
|
+
_currentUser.Email,
|
|
212
|
+
entity.Id,
|
|
213
|
+
entity.Name);
|
|
214
|
+
|
|
215
|
+
return new $ENTITY_PASCALDto
|
|
216
|
+
{
|
|
217
|
+
Id = entity.Id,
|
|
218
|
+
Name = entity.Name,
|
|
219
|
+
Description = entity.Description,
|
|
220
|
+
IsActive = entity.IsActive,
|
|
221
|
+
CreatedAt = entity.CreatedAt
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
public async Task<$ENTITY_PASCALDto> UpdateAsync(
|
|
226
|
+
Guid id,
|
|
227
|
+
Update$ENTITY_PASCALRequest request,
|
|
228
|
+
CancellationToken cancellationToken = default)
|
|
229
|
+
{
|
|
230
|
+
var entity = await _context.$ENTITY_PLURAL
|
|
231
|
+
.FirstOrDefaultAsync(x => x.Id == id, cancellationToken)
|
|
232
|
+
?? throw new NotFoundException("$ENTITY_PASCAL", id);
|
|
233
|
+
|
|
234
|
+
entity.Update(request.Name, request.Description);
|
|
235
|
+
|
|
236
|
+
await _context.SaveChangesAsync(cancellationToken);
|
|
237
|
+
|
|
238
|
+
_logger.LogInformation(
|
|
239
|
+
"User {User} updated $ENTITY_PASCAL {Id} ({Name})",
|
|
240
|
+
_currentUser.Email,
|
|
241
|
+
entity.Id,
|
|
242
|
+
entity.Name);
|
|
243
|
+
|
|
244
|
+
return new $ENTITY_PASCALDto
|
|
245
|
+
{
|
|
246
|
+
Id = entity.Id,
|
|
247
|
+
Name = entity.Name,
|
|
248
|
+
Description = entity.Description,
|
|
249
|
+
IsActive = entity.IsActive,
|
|
250
|
+
CreatedAt = entity.CreatedAt,
|
|
251
|
+
UpdatedAt = entity.UpdatedAt
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
public async Task<bool> DeleteAsync(
|
|
256
|
+
Guid id,
|
|
257
|
+
CancellationToken cancellationToken = default)
|
|
258
|
+
{
|
|
259
|
+
var entity = await _context.$ENTITY_PLURAL
|
|
260
|
+
.FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
|
|
261
|
+
|
|
262
|
+
if (entity == null)
|
|
263
|
+
return false;
|
|
264
|
+
|
|
265
|
+
_context.$ENTITY_PLURAL.Remove(entity);
|
|
266
|
+
await _context.SaveChangesAsync(cancellationToken);
|
|
267
|
+
|
|
268
|
+
_logger.LogWarning(
|
|
269
|
+
"User {User} deleted $ENTITY_PASCAL {Id} ({Name})",
|
|
270
|
+
_currentUser.Email,
|
|
271
|
+
id,
|
|
272
|
+
entity.Name);
|
|
273
|
+
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## TEMPLATE: DTOs
|
|
282
|
+
|
|
283
|
+
```csharp
|
|
284
|
+
// src/SmartStack.Application/$MODULE_PASCAL/Models/$ENTITY_PASCALDto.cs
|
|
285
|
+
|
|
286
|
+
namespace SmartStack.Application.$MODULE_PASCAL.Models;
|
|
287
|
+
|
|
288
|
+
public record $ENTITY_PASCALDto
|
|
289
|
+
{
|
|
290
|
+
public Guid Id { get; init; }
|
|
291
|
+
public string Name { get; init; } = null!;
|
|
292
|
+
public string? Description { get; init; }
|
|
293
|
+
public bool IsActive { get; init; }
|
|
294
|
+
public DateTime CreatedAt { get; init; }
|
|
295
|
+
public DateTime? UpdatedAt { get; init; }
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
public record Create$ENTITY_PASCALRequest
|
|
299
|
+
{
|
|
300
|
+
public string Name { get; init; } = null!;
|
|
301
|
+
public string? Description { get; init; }
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
public record Update$ENTITY_PASCALRequest
|
|
305
|
+
{
|
|
306
|
+
public string Name { get; init; } = null!;
|
|
307
|
+
public string? Description { get; init; }
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
public record $ENTITY_PASCALQueryParameters
|
|
311
|
+
{
|
|
312
|
+
public int Page { get; init; } = 1;
|
|
313
|
+
public int PageSize { get; init; } = 10;
|
|
314
|
+
public string? SearchTerm { get; init; }
|
|
315
|
+
public string? SortColumn { get; init; } = "createdAt";
|
|
316
|
+
public string? SortDirection { get; init; } = "desc";
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## TEMPLATE: DOMAIN ENTITY
|
|
323
|
+
|
|
324
|
+
```csharp
|
|
325
|
+
// src/SmartStack.Domain/$MODULE_PASCAL/$ENTITY_PASCAL.cs
|
|
326
|
+
|
|
327
|
+
using SmartStack.Domain.Common;
|
|
328
|
+
|
|
329
|
+
namespace SmartStack.Domain.$MODULE_PASCAL;
|
|
330
|
+
|
|
331
|
+
public class $ENTITY_PASCAL : BaseEntity
|
|
332
|
+
{
|
|
333
|
+
public string Name { get; private set; } = null!;
|
|
334
|
+
public string? Description { get; private set; }
|
|
335
|
+
public bool IsActive { get; private set; }
|
|
336
|
+
|
|
337
|
+
private $ENTITY_PASCAL() { }
|
|
338
|
+
|
|
339
|
+
public static $ENTITY_PASCAL Create(string name, string? description = null)
|
|
340
|
+
{
|
|
341
|
+
if (string.IsNullOrWhiteSpace(name))
|
|
342
|
+
throw new Exceptions.DomainException("Name is required");
|
|
343
|
+
|
|
344
|
+
return new $ENTITY_PASCAL
|
|
345
|
+
{
|
|
346
|
+
Id = Guid.NewGuid(),
|
|
347
|
+
Name = name,
|
|
348
|
+
Description = description,
|
|
349
|
+
IsActive = true,
|
|
350
|
+
CreatedAt = DateTime.UtcNow
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
public void Update(string name, string? description)
|
|
355
|
+
{
|
|
356
|
+
if (string.IsNullOrWhiteSpace(name))
|
|
357
|
+
throw new Exceptions.DomainException("Name is required");
|
|
358
|
+
|
|
359
|
+
Name = name;
|
|
360
|
+
Description = description;
|
|
361
|
+
UpdatedAt = DateTime.UtcNow;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
public void Activate() => IsActive = true;
|
|
365
|
+
public void Deactivate() => IsActive = false;
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## TEMPLATE: EF CONFIGURATION
|
|
372
|
+
|
|
373
|
+
```csharp
|
|
374
|
+
// src/SmartStack.Infrastructure/Persistence/Configurations/$MODULE_PASCAL/$ENTITY_PASCALConfiguration.cs
|
|
375
|
+
|
|
376
|
+
using Microsoft.EntityFrameworkCore;
|
|
377
|
+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
|
378
|
+
using SmartStack.Domain.$MODULE_PASCAL;
|
|
379
|
+
|
|
380
|
+
namespace SmartStack.Infrastructure.Persistence.Configurations.$MODULE_PASCAL;
|
|
381
|
+
|
|
382
|
+
public class $ENTITY_PASCALConfiguration : IEntityTypeConfiguration<$ENTITY_PASCAL>
|
|
383
|
+
{
|
|
384
|
+
public void Configure(EntityTypeBuilder<$ENTITY_PASCAL> builder)
|
|
385
|
+
{
|
|
386
|
+
// Tables métier client dans le schéma "biz" (business)
|
|
387
|
+
builder.ToTable("$ENTITY_PLURAL", "biz");
|
|
388
|
+
|
|
389
|
+
builder.HasKey(x => x.Id);
|
|
390
|
+
|
|
391
|
+
builder.Property(x => x.Name)
|
|
392
|
+
.HasMaxLength(200)
|
|
393
|
+
.IsRequired();
|
|
394
|
+
|
|
395
|
+
builder.Property(x => x.Description)
|
|
396
|
+
.HasMaxLength(1000);
|
|
397
|
+
|
|
398
|
+
builder.HasIndex(x => x.Name)
|
|
399
|
+
.IsUnique();
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## TEMPLATE: DBCONTEXT UPDATE
|
|
407
|
+
|
|
408
|
+
```csharp
|
|
409
|
+
// Ajouter dans IApplicationDbContext.cs
|
|
410
|
+
DbSet<$ENTITY_PASCAL> $ENTITY_PLURAL { get; }
|
|
411
|
+
|
|
412
|
+
// Ajouter dans ApplicationDbContext.cs
|
|
413
|
+
public DbSet<$ENTITY_PASCAL> $ENTITY_PLURAL => Set<$ENTITY_PASCAL>();
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
## TEMPLATE: DI REGISTRATION
|
|
419
|
+
|
|
420
|
+
```csharp
|
|
421
|
+
// Ajouter dans src/SmartStack.Infrastructure/DependencyInjection.cs
|
|
422
|
+
|
|
423
|
+
services.AddScoped<I$MODULE_PASCALService, $MODULE_PASCALService>();
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
## CHAÎNAGE AVEC /controller:create
|
|
429
|
+
|
|
430
|
+
Après génération des templates backend, le skill appelle automatiquement :
|
|
431
|
+
|
|
432
|
+
```
|
|
433
|
+
/controller:create Business $MODULE $ENTITY
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Exemple :
|
|
437
|
+
```
|
|
438
|
+
/controller:create Business Leads Lead
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
Cela génère :
|
|
442
|
+
- Controller avec CRUD complet
|
|
443
|
+
- Endpoints REST
|
|
444
|
+
- ProducesResponseType
|
|
445
|
+
- Logging approprié
|
|
446
|
+
- Tests Postman
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## CHECKLIST BACKEND
|
|
451
|
+
|
|
452
|
+
| Vérification | Status |
|
|
453
|
+
|--------------|--------|
|
|
454
|
+
| ☐ Permissions.cs mis à jour (sous Business.*) | |
|
|
455
|
+
| ☐ Service interface créée | |
|
|
456
|
+
| ☐ Service implementation créée | |
|
|
457
|
+
| ☐ DTOs créés | |
|
|
458
|
+
| ☐ Domain entity créée | |
|
|
459
|
+
| ☐ EF Configuration créée (schéma "biz") | |
|
|
460
|
+
| ☐ DbContext mis à jour | |
|
|
461
|
+
| ☐ DI registration ajoutée | |
|
|
462
|
+
| ☐ /controller:create exécuté | |
|
|
463
|
+
| ☐ dotnet build réussi | |
|