@atlashub/smartstack-cli 1.36.0 → 2.0.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.
- package/config/mcp-defaults.json +62 -0
- package/dist/index.js +57 -4
- package/dist/index.js.map +1 -1
- package/dist/mcp-entry.mjs +16984 -0
- package/dist/mcp-entry.mjs.map +1 -0
- package/package.json +14 -5
- package/templates/agents/gitflow/start.md +5 -4
- package/templates/agents/mcp-healthcheck.md +15 -13
- package/templates/mcp-scaffolding/component.tsx.hbs +298 -0
- package/templates/mcp-scaffolding/controller.cs.hbs +184 -0
- package/templates/mcp-scaffolding/entity-extension.cs.hbs +231 -0
- package/templates/mcp-scaffolding/frontend/api-client.ts.hbs +116 -0
- package/templates/mcp-scaffolding/frontend/nav-routes.ts.hbs +133 -0
- package/templates/mcp-scaffolding/frontend/routes.tsx.hbs +134 -0
- package/templates/mcp-scaffolding/migrations/seed-roles.cs.hbs +261 -0
- package/templates/mcp-scaffolding/service-extension.cs.hbs +53 -0
- package/templates/mcp-scaffolding/tests/controller.test.cs.hbs +413 -0
- package/templates/mcp-scaffolding/tests/entity.test.cs.hbs +239 -0
- package/templates/mcp-scaffolding/tests/repository.test.cs.hbs +441 -0
- package/templates/mcp-scaffolding/tests/security.test.cs.hbs +442 -0
- package/templates/mcp-scaffolding/tests/service.test.cs.hbs +390 -0
- package/templates/mcp-scaffolding/tests/validator.test.cs.hbs +428 -0
- package/templates/ralph/README.md +3 -3
- package/templates/ralph/ralph.config.yaml +2 -2
- package/templates/skills/admin/SKILL.md +42 -0
- package/templates/skills/application/steps/step-01-navigation.md +226 -43
- package/templates/skills/application/steps/step-03-roles.md +160 -38
- package/templates/skills/application/steps/step-04-backend.md +109 -2
- package/templates/skills/application/templates-seed.md +200 -1
- package/templates/skills/business-analyse/_shared.md +24 -1
- package/templates/skills/business-analyse/questionnaire/01-context.md +4 -4
- package/templates/skills/business-analyse/questionnaire/02-stakeholders.md +3 -3
- package/templates/skills/business-analyse/questionnaire/03-scope.md +4 -4
- package/templates/skills/business-analyse/questionnaire/04-data.md +7 -7
- package/templates/skills/business-analyse/questionnaire/05-integrations.md +1 -1
- package/templates/skills/business-analyse/questionnaire/06-security.md +3 -3
- package/templates/skills/business-analyse/questionnaire/07-ui.md +1 -1
- package/templates/skills/business-analyse/questionnaire/08-performance.md +3 -3
- package/templates/skills/business-analyse/questionnaire/09-constraints.md +4 -4
- package/templates/skills/business-analyse/questionnaire/10-documentation.md +2 -2
- package/templates/skills/business-analyse/questionnaire/11-data-lifecycle.md +2 -2
- package/templates/skills/business-analyse/questionnaire/12-migration.md +1 -1
- package/templates/skills/business-analyse/questionnaire/13-cross-module.md +2 -2
- package/templates/skills/business-analyse/steps/step-01-discover.md +50 -25
- package/templates/skills/business-analyse/steps/step-05-handoff.md +133 -34
- package/templates/skills/cc-agent/SKILL.md +129 -0
- package/templates/skills/cc-agent/references/agent-frontmatter.md +213 -0
- package/templates/skills/cc-agent/references/permission-modes.md +102 -0
- package/templates/skills/cc-agent/references/tools-reference.md +144 -0
- package/templates/skills/cc-agent/steps/step-00-init.md +134 -0
- package/templates/skills/cc-agent/steps/step-01-design.md +186 -0
- package/templates/skills/cc-agent/steps/step-02-generate.md +204 -0
- package/templates/skills/cc-agent/steps/step-03-validate.md +130 -0
- package/templates/skills/cc-agent/templates/agent-categorized.md +67 -0
- package/templates/skills/cc-agent/templates/agent-standalone.md +56 -0
- package/templates/skills/cc-agent/templates/agent-with-skills.md +94 -0
- package/templates/skills/cc-audit/SKILL.md +108 -0
- package/templates/skills/cc-audit/references/agent-checklist.md +91 -0
- package/templates/skills/cc-audit/references/hook-checklist.md +110 -0
- package/templates/skills/cc-audit/references/skill-checklist.md +70 -0
- package/templates/skills/cc-audit/steps/step-00-init.md +98 -0
- package/templates/skills/cc-audit/steps/step-01-scan.md +142 -0
- package/templates/skills/cc-audit/steps/step-02-analyze.md +158 -0
- package/templates/skills/cc-audit/steps/step-03-report.md +142 -0
- package/templates/skills/cc-skill/SKILL.md +134 -0
- package/templates/skills/cc-skill/references/best-practices.md +167 -0
- package/templates/skills/cc-skill/references/frontmatter-reference.md +182 -0
- package/templates/skills/cc-skill/references/skill-patterns.md +199 -0
- package/templates/skills/cc-skill/steps/step-00-init.md +119 -0
- package/templates/skills/cc-skill/steps/step-01-design.md +199 -0
- package/templates/skills/cc-skill/steps/step-02-generate.md +145 -0
- package/templates/skills/cc-skill/steps/step-03-steps.md +151 -0
- package/templates/skills/cc-skill/steps/step-04-validate.md +124 -0
- package/templates/skills/cc-skill/templates/skill-forked.md +85 -0
- package/templates/skills/cc-skill/templates/skill-progressive.md +102 -0
- package/templates/skills/cc-skill/templates/skill-simple.md +75 -0
- package/templates/skills/cc-skill/templates/step-template.md +82 -0
- package/templates/skills/check-version/SKILL.md +6 -0
- package/templates/skills/debug/SKILL.md +4 -0
- package/templates/skills/documentation/SKILL.md +1 -0
- package/templates/skills/efcore/SKILL.md +5 -0
- package/templates/skills/efcore/steps/db/step-deploy.md +26 -5
- package/templates/skills/efcore/steps/shared/step-00-init.md +21 -7
- package/templates/skills/explore/SKILL.md +28 -32
- package/templates/skills/feature-full/SKILL.md +1 -0
- package/templates/skills/gitflow/SKILL.md +8 -0
- package/templates/skills/gitflow/steps/step-start.md +45 -10
- package/templates/skills/mcp/SKILL.md +38 -18
- package/templates/skills/quick-search/SKILL.md +8 -1
- package/templates/skills/ralph-loop/SKILL.md +1 -1
- package/templates/skills/ralph-loop/steps/step-00-init.md +8 -68
- package/templates/skills/ralph-loop/steps/step-04-check.md +1 -1
- package/templates/skills/refactor/SKILL.md +1 -0
- package/templates/skills/review-code/SKILL.md +7 -1
- package/templates/skills/ui-components/SKILL.md +31 -438
- package/templates/skills/ui-components/accessibility.md +170 -0
- package/templates/skills/ui-components/patterns/data-table.md +39 -0
- package/templates/skills/ui-components/patterns/entity-card.md +77 -0
- package/templates/skills/ui-components/patterns/grid-layout.md +91 -0
- package/templates/skills/ui-components/patterns/kanban.md +43 -0
- package/templates/skills/ui-components/style-guide.md +86 -0
- package/templates/skills/utils/SKILL.md +1 -0
- package/templates/skills/validate/SKILL.md +1 -0
|
@@ -124,7 +124,110 @@ The tool generates (paths organized by navRoute hierarchy `{context}.{applicatio
|
|
|
124
124
|
3. Run: `dotnet ef migrations add core_vX.X.X_XXX_Add{EntityName}`
|
|
125
125
|
```
|
|
126
126
|
|
|
127
|
-
### 6.
|
|
127
|
+
### 6. Entity Seeding (Optional)
|
|
128
|
+
|
|
129
|
+
> Ask the user if they want to seed initial data for the entity.
|
|
130
|
+
> This creates runtime seed data (applied at startup via DevDataSeeder), following the same
|
|
131
|
+
> architecture as core (SeedData provider pattern).
|
|
132
|
+
|
|
133
|
+
```yaml
|
|
134
|
+
questions:
|
|
135
|
+
- header: "Seed Data"
|
|
136
|
+
question: "Would you like to generate initial seed data for {EntityName}?"
|
|
137
|
+
options:
|
|
138
|
+
- label: "Yes - Generate SeedData provider"
|
|
139
|
+
description: "Creates {EntityName}SeedData.cs + registers in DevDataSeeder (same pattern as core)"
|
|
140
|
+
- label: "No - Skip seeding"
|
|
141
|
+
description: "Entity starts empty (can add seed data later)"
|
|
142
|
+
multiSelect: false
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
#### If User Selects YES:
|
|
146
|
+
|
|
147
|
+
**Reference:** See `templates-seed.md` section "TEMPLATE: ENTITY SEED DATA (SeedData Provider)"
|
|
148
|
+
|
|
149
|
+
**Generate the following files:**
|
|
150
|
+
|
|
151
|
+
1. **`Infrastructure/Persistence/Seeding/Data/{Domain}/{EntityName}SeedData.cs`**
|
|
152
|
+
|
|
153
|
+
Follow the SmartStack.app pattern (same architecture as core):
|
|
154
|
+
- Static class with `internal static IEnumerable<{EntityName}SeedItem> GetAll{EntityName}s()`
|
|
155
|
+
- Use deterministic GUIDs (NEVER `Guid.NewGuid()`)
|
|
156
|
+
- Include 3-5 sample entities with varied, realistic data
|
|
157
|
+
- Internal record class `{EntityName}SeedItem` with all entity properties
|
|
158
|
+
- For multi-tenant entities: organize by tenant using `GetTenant1{EntityName}s()` helper methods
|
|
159
|
+
- Reference existing tenant/user IDs from `TenantSeedData`/`UserSeedData` for foreign keys
|
|
160
|
+
|
|
161
|
+
```csharp
|
|
162
|
+
// Infrastructure/Persistence/Seeding/Data/{Domain}/{EntityName}SeedData.cs
|
|
163
|
+
|
|
164
|
+
public static class {EntityName}SeedData
|
|
165
|
+
{
|
|
166
|
+
public static readonly Guid Sample1Id = Guid.Parse("...");
|
|
167
|
+
public static readonly Guid Sample2Id = Guid.Parse("...");
|
|
168
|
+
public static readonly Guid Sample3Id = Guid.Parse("...");
|
|
169
|
+
|
|
170
|
+
internal static IEnumerable<{EntityName}SeedItem> GetAll{EntityName}s()
|
|
171
|
+
{
|
|
172
|
+
return new[]
|
|
173
|
+
{
|
|
174
|
+
new {EntityName}SeedItem { Id = Sample1Id, /* ... */ },
|
|
175
|
+
new {EntityName}SeedItem { Id = Sample2Id, /* ... */ },
|
|
176
|
+
new {EntityName}SeedItem { Id = Sample3Id, /* ... */ }
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
internal class {EntityName}SeedItem
|
|
182
|
+
{
|
|
183
|
+
public Guid Id { get; init; }
|
|
184
|
+
// ... all required entity properties
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
2. **Update `Infrastructure/Persistence/Seeding/DevDataSeeder.cs`**
|
|
189
|
+
- Add `using` for the new SeedData namespace
|
|
190
|
+
- Add `await Seed{EntityName}sAsync(cancellationToken);` in `SeedAsync()` method
|
|
191
|
+
- Add private seeding method:
|
|
192
|
+
|
|
193
|
+
```csharp
|
|
194
|
+
private async Task Seed{EntityName}sAsync(CancellationToken cancellationToken)
|
|
195
|
+
{
|
|
196
|
+
_logger.LogInformation("Seeding demo {EntityName}s...");
|
|
197
|
+
|
|
198
|
+
var existingCount = await _context.{EntityName}s.CountAsync(cancellationToken);
|
|
199
|
+
if (existingCount > 0)
|
|
200
|
+
{
|
|
201
|
+
_logger.LogWarning("{EntityName}s already seeded ({Count} exist), skipping.", existingCount);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
var createdCount = 0;
|
|
206
|
+
foreach (var seedItem in {EntityName}SeedData.GetAll{EntityName}s())
|
|
207
|
+
{
|
|
208
|
+
var entity = {EntityName}.Create(/* map seedItem properties */);
|
|
209
|
+
typeof({EntityName}).GetProperty("Id")?.SetValue(entity, seedItem.Id);
|
|
210
|
+
_context.{EntityName}s.Add(entity);
|
|
211
|
+
createdCount++;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (createdCount > 0)
|
|
215
|
+
await _context.SaveChangesAsync(cancellationToken);
|
|
216
|
+
|
|
217
|
+
_logger.LogInformation("Created {Count} demo {EntityName}s.", createdCount);
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
#### If User Selects NO:
|
|
222
|
+
|
|
223
|
+
Skip this section and proceed to storing entity info.
|
|
224
|
+
|
|
225
|
+
```markdown
|
|
226
|
+
> Skipping entity seed data. You can generate it later using the SeedData provider pattern
|
|
227
|
+
> documented in templates-seed.md.
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### 7. Store Entity Info
|
|
128
231
|
|
|
129
232
|
Store entity information for frontend generation:
|
|
130
233
|
|
|
@@ -132,6 +235,7 @@ Store entity information for frontend generation:
|
|
|
132
235
|
{entity_name} = "{EntityName}"
|
|
133
236
|
{entity_code} = "{code}"
|
|
134
237
|
{api_route} = "/api/{code}"
|
|
238
|
+
{has_seed_data} = true/false // Whether SeedData provider was generated
|
|
135
239
|
```
|
|
136
240
|
|
|
137
241
|
---
|
|
@@ -168,6 +272,7 @@ This ensures:
|
|
|
168
272
|
If MCP returns successfully:
|
|
169
273
|
- Display all generated files
|
|
170
274
|
- Show DbSet and DI registration instructions
|
|
275
|
+
- Ask about entity seeding (section 6)
|
|
171
276
|
- Store entity info for frontend
|
|
172
277
|
- Proceed to step-05-frontend.md
|
|
173
278
|
|
|
@@ -186,6 +291,7 @@ If MCP call fails:
|
|
|
186
291
|
- Entity, Service, Controller generated
|
|
187
292
|
- DTOs generated
|
|
188
293
|
- NavRoute attribute included
|
|
294
|
+
- Entity seeding offered to user (SeedData.cs + DevDataSeeder if accepted)
|
|
189
295
|
- Entity info stored for frontend
|
|
190
296
|
- Proceeded to step-05-frontend.md
|
|
191
297
|
|
|
@@ -199,4 +305,5 @@ If MCP call fails:
|
|
|
199
305
|
|
|
200
306
|
## NEXT STEP
|
|
201
307
|
|
|
202
|
-
After
|
|
308
|
+
After backend code is generated and entity seeding is handled,
|
|
309
|
+
proceed to `./step-05-frontend.md`
|
|
@@ -605,12 +605,209 @@ $ORDER = 1
|
|
|
605
605
|
|
|
606
606
|
---
|
|
607
607
|
|
|
608
|
+
## TEMPLATE: ENTITY SEED DATA (SeedData Provider)
|
|
609
|
+
|
|
610
|
+
> **Usage:** Runtime seed data for domain entities (Products, Orders, Tickets, etc.)
|
|
611
|
+
> **When:** User wants initial data for development/testing
|
|
612
|
+
> **Mechanism:** Loaded at startup by DevDataSeeder, NOT via EF Core HasData/migrations
|
|
613
|
+
> **Architecture:** Identical in core AND extensions
|
|
614
|
+
|
|
615
|
+
### Two Seeding Mechanisms
|
|
616
|
+
|
|
617
|
+
| Mechanism | When to Use | Applied Via |
|
|
618
|
+
|-----------|-------------|-------------|
|
|
619
|
+
| **HasData()** in Configuration.cs | System entities (Navigation, Permissions, Roles) | EF Core migrations |
|
|
620
|
+
| **SeedData.cs + DevDataSeeder** | Domain entities (Tickets, Products, Orders) | Application startup |
|
|
621
|
+
|
|
622
|
+
**Rule:** Navigation, Permission, and RolePermission seeds use HasData().
|
|
623
|
+
Domain entity seeds use the SeedData provider pattern below.
|
|
624
|
+
|
|
625
|
+
### SeedData Class Pattern
|
|
626
|
+
|
|
627
|
+
```csharp
|
|
628
|
+
// Infrastructure/Persistence/Seeding/Data/{Domain}/{EntityName}SeedData.cs
|
|
629
|
+
|
|
630
|
+
using SmartStack.Domain.{Context}.{Application}.{Module};
|
|
631
|
+
|
|
632
|
+
namespace SmartStack.Infrastructure.Persistence.Seeding.Data.{Domain};
|
|
633
|
+
|
|
634
|
+
/// <summary>
|
|
635
|
+
/// Demo {EntityName} data for development and testing.
|
|
636
|
+
/// </summary>
|
|
637
|
+
public static class {EntityName}SeedData
|
|
638
|
+
{
|
|
639
|
+
// ============================================================
|
|
640
|
+
// DETERMINISTIC IDs - for referencing in other seed data
|
|
641
|
+
// ============================================================
|
|
642
|
+
|
|
643
|
+
public static readonly Guid Sample1Id = Guid.Parse("$SEED_GUID_1");
|
|
644
|
+
public static readonly Guid Sample2Id = Guid.Parse("$SEED_GUID_2");
|
|
645
|
+
public static readonly Guid Sample3Id = Guid.Parse("$SEED_GUID_3");
|
|
646
|
+
|
|
647
|
+
/// <summary>
|
|
648
|
+
/// Returns all demo {EntityName} entities.
|
|
649
|
+
/// </summary>
|
|
650
|
+
internal static IEnumerable<{EntityName}SeedItem> GetAll{EntityName}s()
|
|
651
|
+
{
|
|
652
|
+
return new[]
|
|
653
|
+
{
|
|
654
|
+
new {EntityName}SeedItem
|
|
655
|
+
{
|
|
656
|
+
Id = Sample1Id,
|
|
657
|
+
// ... entity properties with realistic sample data
|
|
658
|
+
CreatedByUserId = UserSeedData.SystemUserId
|
|
659
|
+
},
|
|
660
|
+
new {EntityName}SeedItem
|
|
661
|
+
{
|
|
662
|
+
Id = Sample2Id,
|
|
663
|
+
// ... varied data
|
|
664
|
+
CreatedByUserId = UserSeedData.SystemUserId
|
|
665
|
+
},
|
|
666
|
+
new {EntityName}SeedItem
|
|
667
|
+
{
|
|
668
|
+
Id = Sample3Id,
|
|
669
|
+
// ... varied data
|
|
670
|
+
CreatedByUserId = UserSeedData.SystemUserId
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/// <summary>
|
|
677
|
+
/// Seed item DTO for {EntityName} (avoids domain factory methods during seeding).
|
|
678
|
+
/// </summary>
|
|
679
|
+
internal class {EntityName}SeedItem
|
|
680
|
+
{
|
|
681
|
+
public Guid Id { get; init; }
|
|
682
|
+
// ... all required properties matching the domain entity
|
|
683
|
+
public Guid CreatedByUserId { get; init; }
|
|
684
|
+
}
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
### Multi-Tenant Entity Seed Pattern
|
|
688
|
+
|
|
689
|
+
For entities belonging to a tenant, organize by tenant:
|
|
690
|
+
|
|
691
|
+
```csharp
|
|
692
|
+
internal static IEnumerable<{EntityName}SeedItem> GetAll{EntityName}s()
|
|
693
|
+
{
|
|
694
|
+
var items = new List<{EntityName}SeedItem>();
|
|
695
|
+
|
|
696
|
+
items.AddRange(GetTenant1{EntityName}s());
|
|
697
|
+
items.AddRange(GetTenant2{EntityName}s());
|
|
698
|
+
|
|
699
|
+
return items;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
private static IEnumerable<{EntityName}SeedItem> GetTenant1{EntityName}s()
|
|
703
|
+
{
|
|
704
|
+
var tenantId = TenantSeedData.AcmeCorporationId;
|
|
705
|
+
var userId = TenantMembershipSeedData.AcmeOwnerId;
|
|
706
|
+
|
|
707
|
+
return new[]
|
|
708
|
+
{
|
|
709
|
+
new {EntityName}SeedItem
|
|
710
|
+
{
|
|
711
|
+
Id = Guid.Parse("$GUID"),
|
|
712
|
+
TenantId = tenantId,
|
|
713
|
+
CreatedByUserId = userId,
|
|
714
|
+
// ... properties
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
### DevDataSeeder Registration Pattern
|
|
721
|
+
|
|
722
|
+
```csharp
|
|
723
|
+
// In Infrastructure/Persistence/Seeding/DevDataSeeder.cs
|
|
724
|
+
|
|
725
|
+
// 1. Add using statement
|
|
726
|
+
using SmartStack.Infrastructure.Persistence.Seeding.Data.{Domain};
|
|
727
|
+
|
|
728
|
+
// 2. Add call in SeedAsync() method (after existing seed calls)
|
|
729
|
+
public async Task SeedAsync(CancellationToken cancellationToken = default)
|
|
730
|
+
{
|
|
731
|
+
// ... existing seed calls ...
|
|
732
|
+
|
|
733
|
+
await Seed{EntityName}sAsync(cancellationToken); // <-- ADD THIS
|
|
734
|
+
|
|
735
|
+
// ... summary logging ...
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// 3. Add private seeding method
|
|
739
|
+
private async Task Seed{EntityName}sAsync(CancellationToken cancellationToken)
|
|
740
|
+
{
|
|
741
|
+
_logger.LogInformation("Seeding demo {EntityName}s...");
|
|
742
|
+
|
|
743
|
+
var existingCount = await _context.{EntityName}s.CountAsync(cancellationToken);
|
|
744
|
+
if (existingCount > 0)
|
|
745
|
+
{
|
|
746
|
+
_logger.LogWarning("{EntityName}s already seeded ({Count} exist), skipping.", existingCount);
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
var createdCount = 0;
|
|
751
|
+
|
|
752
|
+
foreach (var seedItem in {EntityName}SeedData.GetAll{EntityName}s())
|
|
753
|
+
{
|
|
754
|
+
var entity = {EntityName}.Create(
|
|
755
|
+
// Map seedItem properties to factory method parameters
|
|
756
|
+
);
|
|
757
|
+
|
|
758
|
+
// Set deterministic ID (factory generates random GUID)
|
|
759
|
+
typeof({EntityName}).GetProperty("Id")?.SetValue(entity, seedItem.Id);
|
|
760
|
+
|
|
761
|
+
_context.{EntityName}s.Add(entity);
|
|
762
|
+
createdCount++;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
if (createdCount > 0)
|
|
766
|
+
{
|
|
767
|
+
await _context.SaveChangesAsync(cancellationToken);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
_logger.LogInformation("Created {Count} demo {EntityName}s.", createdCount);
|
|
771
|
+
}
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
### Seed Data GUID Generation
|
|
775
|
+
|
|
776
|
+
```csharp
|
|
777
|
+
// Option 1: Hardcoded descriptive GUIDs (preferred for small sets)
|
|
778
|
+
public static readonly Guid ProductAlphaId = Guid.Parse("aa000001-0000-0000-0000-000000000001");
|
|
779
|
+
public static readonly Guid ProductBetaId = Guid.Parse("aa000001-0000-0000-0000-000000000002");
|
|
780
|
+
|
|
781
|
+
// Option 2: SHA256-based for larger sets
|
|
782
|
+
private static Guid GenerateEntityGuid(string uniqueKey)
|
|
783
|
+
{
|
|
784
|
+
using var sha256 = System.Security.Cryptography.SHA256.Create();
|
|
785
|
+
var hash = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes($"{EntityName}-{uniqueKey}"));
|
|
786
|
+
return new Guid(hash.Take(16).ToArray());
|
|
787
|
+
}
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
### Best Practices
|
|
791
|
+
|
|
792
|
+
| Practice | Description |
|
|
793
|
+
|----------|-------------|
|
|
794
|
+
| Deterministic IDs | NEVER use `Guid.NewGuid()` - seeds must be idempotent |
|
|
795
|
+
| Idempotent | Always check `if exists` before creating |
|
|
796
|
+
| Use factory methods | Call `Entity.Create(...)` not `new Entity()` |
|
|
797
|
+
| Set ID via reflection | Factory methods generate random IDs; override after creation |
|
|
798
|
+
| Realistic data | Use plausible names, descriptions, amounts |
|
|
799
|
+
| Cover all states | Include entities in different statuses (active, closed, etc.) |
|
|
800
|
+
| Reference existing seeds | Use IDs from TenantSeedData, UserSeedData for foreign keys |
|
|
801
|
+
| SaveChanges per batch | Call SaveChanges after each entity group |
|
|
802
|
+
|
|
803
|
+
---
|
|
804
|
+
|
|
608
805
|
## SEED CHECKLIST
|
|
609
806
|
|
|
610
807
|
| Check | Status |
|
|
611
808
|
|-------|--------|
|
|
612
809
|
| ☐ Deterministic GUID (not NewGuid) | |
|
|
613
|
-
| ☐ 4 languages for each entity | |
|
|
810
|
+
| ☐ 4 languages for each navigation entity | |
|
|
614
811
|
| ☐ Index translations continue existing sequence | |
|
|
615
812
|
| ☐ Route aligned with permission path | |
|
|
616
813
|
| ☐ DisplayOrder consistent | |
|
|
@@ -619,6 +816,8 @@ $ORDER = 1
|
|
|
619
816
|
| ☐ Resource permissions if sub-resources (Level 5) | |
|
|
620
817
|
| ☐ Bulk Operations permissions created | |
|
|
621
818
|
| ☐ RolePermissions assigned | |
|
|
819
|
+
| ☐ Entity SeedData.cs created (if user opted in) | |
|
|
820
|
+
| ☐ DevDataSeeder.cs updated (if user opted in) | |
|
|
622
821
|
|
|
623
822
|
---
|
|
624
823
|
|
|
@@ -214,6 +214,26 @@ generate_feature_id():
|
|
|
214
214
|
|
|
215
215
|
### AskUserQuestion Format
|
|
216
216
|
|
|
217
|
+
> **⚠️ FORMATTING CRITICAL: `AskUserQuestion` does NOT support markdown or line breaks.**
|
|
218
|
+
> Le champ `question` est rendu en texte brut (plain text). Il n'y a pas de retour à la ligne,
|
|
219
|
+
> pas de gras, pas de puces. Une question simple reste lisible meme longue. Mais du contenu
|
|
220
|
+
> structuré (listes, résumés multi-points, tableaux) devient un mur de texte illisible.
|
|
221
|
+
|
|
222
|
+
| Field | Rule |
|
|
223
|
+
|-------|------|
|
|
224
|
+
| `question` | **1 question ou 1 phrase.** Jamais de liste, résumé multi-points ou contenu structuré. |
|
|
225
|
+
| `header` | 1-2 mots (max 12 chars) |
|
|
226
|
+
| `label` (option) | Court et clair (~20 chars) |
|
|
227
|
+
| `description` (option) | 1 phrase explicative (~60 chars) |
|
|
228
|
+
|
|
229
|
+
> **Pour afficher du contenu structuré** (résumés, listes, tableaux, synthèses) :
|
|
230
|
+
> **TOUJOURS** utiliser du **texte direct** (output text) AVANT l'appel `AskUserQuestion`.
|
|
231
|
+
> Le texte direct supporte le markdown et sera correctement formaté avec titres, puces, gras, etc.
|
|
232
|
+
>
|
|
233
|
+
> **Exemple — Validation de synthèse :**
|
|
234
|
+
> 1. Afficher le résumé structuré en markdown (texte direct)
|
|
235
|
+
> 2. Puis poser une question courte : "Cette synthèse est-elle correcte ?"
|
|
236
|
+
|
|
217
237
|
```
|
|
218
238
|
AskUserQuestion({
|
|
219
239
|
questions: [
|
|
@@ -469,7 +489,7 @@ Le champ `language` dans `.business-analyse/config.json` définit la langue :
|
|
|
469
489
|
| Relances et follow-ups (Elicitation Guide) | **OUI** — traduire les probes à la volée |
|
|
470
490
|
| Documents générés (discovery, BRD, FRD, handoff) | **OUI** — rédigés dans `{language}` |
|
|
471
491
|
| Référence technique interne (patterns, architecture) | NON — reste en langue du fichier |
|
|
472
|
-
| Noms de code (entités, permissions, paths) | NON — toujours en anglais (convention
|
|
492
|
+
| Noms de code (entités, permissions, paths) | NON — toujours en anglais (convention plateforme) |
|
|
473
493
|
|
|
474
494
|
### Règle
|
|
475
495
|
|
|
@@ -480,6 +500,9 @@ Le champ `language` dans `.business-analyse/config.json` définit la langue :
|
|
|
480
500
|
→ Si {language} ≠ "fr", les traduire à la volée
|
|
481
501
|
4. Les documents générés sont rédigés dans {language}
|
|
482
502
|
5. Le code, les noms d'entités et les paths restent TOUJOURS en anglais
|
|
503
|
+
6. Ne JAMAIS utiliser "SmartStack" dans les communications utilisateur
|
|
504
|
+
→ Utiliser "la plateforme", "l'application" ou "le système" à la place
|
|
505
|
+
→ SmartStack est le nom interne du framework, le projet client a son propre nom
|
|
483
506
|
```
|
|
484
507
|
|
|
485
508
|
---
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
|---|----------|-------------|
|
|
21
21
|
| Q1.5 | What ROI do you expect? (time, money, efficiency) | Quantitative |
|
|
22
22
|
| Q1.6 | What savings or gains will this module bring? | Estimation |
|
|
23
|
-
| Q1.7 | What
|
|
24
|
-
| Q1.8 | What is the
|
|
23
|
+
| Q1.7 | What triggered this need? (urgency, regulation, roadmap) | Trigger type |
|
|
24
|
+
| Q1.8 | What is the expected delivery timeline? | Timeline |
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
| Q1.3 (TO-BE) | Vague ("ça ira mieux") | "Concrètement, quel geste ou tâche sera différent ? Combien de clics/minutes en moins ?" |
|
|
37
37
|
| Q1.4 (KPIs) | No measurable metric | "Comment saurez-vous dans 3 mois que cette fonctionnalité a réussi ? Quel chiffre regarderez-vous ?" |
|
|
38
38
|
| Q1.5 (ROI) | "I don't know" | "Combien de temps passez-vous sur ce processus aujourd'hui par semaine ? À combien de personnes ?" |
|
|
39
|
-
| Q1.7 (
|
|
39
|
+
| Q1.7 (trigger) | Vague ("c'est utile") | "Quel événement ou quelle situation a déclenché ce besoin maintenant ? Obligation, inefficacité, opportunité ?" |
|
|
40
40
|
|
|
41
41
|
### Anti-patterns to Detect
|
|
42
42
|
|
|
@@ -45,4 +45,4 @@
|
|
|
45
45
|
| "Il faudrait un bouton/écran/champ..." | **Solution disguised as need** | Apply Solution → Problem Reframing |
|
|
46
46
|
| "C'est évident", "tout le monde sait" | **Implicit assumption** | "Pouvez-vous le formuler explicitement pour que je puisse le documenter ?" |
|
|
47
47
|
| KPIs are feelings ("ça sera mieux") | **Non-measurable success** | "Quel chiffre regarderez-vous pour savoir si c'est réussi ?" |
|
|
48
|
-
| Q1.7 = "
|
|
48
|
+
| Q1.7 = "Opportunité" sans urgence | **Déclencheur à clarifier** | "Quel gain concret attendez-vous ? Comment mesurerez-vous l'amélioration ?" |
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
|
|
28
28
|
## Role -> Permission Mapping
|
|
29
29
|
|
|
30
|
-
> **⚠️ RBAC RULE: Roles are
|
|
30
|
+
> **⚠️ RBAC RULE: Roles are platform permissions, NOT entity attributes.**
|
|
31
31
|
>
|
|
32
32
|
> When stakeholders mention "roles" (admin, manager, user...), these MUST be mapped
|
|
33
|
-
> to
|
|
33
|
+
> to the platform's RBAC permission system (`business.{app}.{module}.{action}`).
|
|
34
34
|
>
|
|
35
35
|
> **NEVER** model a role as:
|
|
36
36
|
> - A property/column on a User entity (e.g. `User.Role`, `User.RoleType`)
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
>
|
|
40
40
|
> **ALWAYS** map roles to permission sets in the matrix below:
|
|
41
41
|
|
|
42
|
-
| Discovered Role |
|
|
42
|
+
| Discovered Role | Platform Permission |
|
|
43
43
|
|-----------------|----------------------|
|
|
44
44
|
| Admin | `*.admin` |
|
|
45
45
|
| Manager | `*.read,create,update` |
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
| Q3.1 | List ESSENTIAL features (Must-Have) | List |
|
|
13
13
|
| Q3.2 | List DESIRED features (Should-Have) | List |
|
|
14
14
|
| Q3.3 | List OPTIONAL features (Could-Have) | List |
|
|
15
|
-
| Q3.4 |
|
|
15
|
+
| Q3.4 | Any known constraints limiting v1 scope? | List of constraints |
|
|
16
16
|
|
|
17
17
|
## 3.2 Business Process
|
|
18
18
|
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
| Must | Without this feature, the module has no value |
|
|
33
33
|
| Should | Brings significant value but can wait for v2 |
|
|
34
34
|
| Could | Nice-to-have, can be implemented if time available |
|
|
35
|
-
| Won't |
|
|
35
|
+
| Won't | Deferred — will be considered for future versions |
|
|
36
36
|
|
|
37
37
|
## Elicitation Guide
|
|
38
38
|
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
| Q3.1 (Must-Have) | > 10 items listed | "Si vous ne pouviez en garder que 3 pour la v1, lesquels ? Les autres sont peut-être Should-Have." |
|
|
44
44
|
| Q3.1 (Must-Have) | Mélange CRUD + complexe | "Le CRUD de base (liste, création, modification, suppression) est-il un Must, ou certaines actions sont Could ?" |
|
|
45
45
|
| Q3.2 (Should-Have) | Vide | "Y a-t-il des fonctionnalités utiles mais qui peuvent attendre une v2 ? Export, filtres avancés, notifications ?" |
|
|
46
|
-
| Q3.4 (
|
|
46
|
+
| Q3.4 (limites) | Vide | "Y a-t-il des contraintes connues qui pourraient limiter le périmètre ? (budget, délai, dépendance)" |
|
|
47
47
|
| Q3.5 (main flow) | < 3 étapes | "Détaillez : l'utilisateur arrive sur l'écran → que voit-il ? → que clique-t-il ? → que se passe-t-il ?" |
|
|
48
48
|
| Q3.7 (alt flows) | "Il n'y en a pas" | "Que se passe-t-il si l'utilisateur annule ? S'il n'a pas la permission ? Si les données sont invalides ?" |
|
|
49
49
|
| Q3.8 (errors) | Liste vide | "Que se passe-t-il si le réseau coupe ? Si un champ obligatoire manque ? Si un doublon existe ?" |
|
|
@@ -53,6 +53,6 @@
|
|
|
53
53
|
| Signal | Anti-pattern | Action |
|
|
54
54
|
|--------|-------------|--------|
|
|
55
55
|
| Tout est Must-Have | **Scope non priorisé** | Appliquer le test : "Sans cette fonctionnalité, le module a-t-il ZÉRO valeur ?" |
|
|
56
|
-
| Q3.4
|
|
56
|
+
| Q3.4 pas de limite identifiée | **Scope à valider** | Le scope sera naturellement borné par les Must-Have/Should-Have. Vérifier que les Must-Have sont réalistes. |
|
|
57
57
|
| Flow linéaire sans alternative | **Happy path uniquement** | "Que se passe-t-il au step X si la condition Y n'est pas remplie ?" |
|
|
58
58
|
| Mélange fonctionnel/technique | **Solution dans le scope** | Séparer : "gérer les commandes" (fonctionnel) vs "utiliser Redis" (technique) |
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
28
|
-
##
|
|
28
|
+
## Technical Mapping
|
|
29
29
|
|
|
30
|
-
| Business Concept |
|
|
30
|
+
| Business Concept | Platform |
|
|
31
31
|
|-----------------|------------|
|
|
32
32
|
| Main entity | Domain Entity |
|
|
33
33
|
| Required attribute | `[Required]` |
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
| 1:N relationship | Navigation property |
|
|
36
36
|
| Sensitive data | Encryption + audit |
|
|
37
37
|
|
|
38
|
-
> **⚠️ RBAC EXCLUSION: The following concepts are handled by
|
|
38
|
+
> **⚠️ RBAC EXCLUSION: The following concepts are handled by the platform's RBAC system
|
|
39
39
|
> and MUST NOT be modeled as entity attributes or separate entities:**
|
|
40
40
|
>
|
|
41
41
|
> | Concept | ❌ Wrong (entity attribute) | ✅ Correct (RBAC) |
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
| Question | If answer is vague/insufficient | Probe |
|
|
55
55
|
|----------|-------------------------------|-------|
|
|
56
56
|
| Q4.1 (entities) | Single entity listed | "Cette entité a-t-elle des sous-éléments ? (lignes de commande, pièces jointes, historique)" |
|
|
57
|
-
| Q4.1 (entities) | Mentions "User" as entity | "L'utilisateur est géré par
|
|
57
|
+
| Q4.1 (entities) | Mentions "User" as entity | "L'utilisateur est géré par la plateforme (Identity). Décrivez plutôt l'entité MÉTIER (Client, Employee, Contact...)" |
|
|
58
58
|
| Q4.2 (attributes) | Liste de champs techniques (ID, CreatedDate) | "Les champs techniques (Id, TenantId, audit) sont auto-gérés. Quels sont les attributs MÉTIER ?" |
|
|
59
59
|
| Q4.3 (relationships) | "1:N" without detail | "Un {Parent} peut avoir combien de {Children} max ? Un {Child} peut-il exister sans {Parent} ?" |
|
|
60
60
|
| Q4.4 (volume) | "Beaucoup" | "Ordre de grandeur : dizaines, centaines, milliers, millions ? Croissance par mois ?" |
|
|
@@ -65,14 +65,14 @@
|
|
|
65
65
|
|
|
66
66
|
| Signal | Anti-pattern | Action |
|
|
67
67
|
|--------|-------------|--------|
|
|
68
|
-
| Entity "User" avec attributs métier | **Confusion User/Identity** |
|
|
68
|
+
| Entity "User" avec attributs métier | **Confusion User/Identity** | La plateforme gère les Users via Identity. L'entité métier = Client, Employee, Contact |
|
|
69
69
|
| Attributs Id, TenantId, CreatedBy listés | **Champs techniques comme métier** | Ces champs sont auto-générés par `AuditableEntity`. Ne pas les lister. |
|
|
70
70
|
| Pas de soft delete mentionné | **Suppression non clarifiée** | "Les données supprimées sont-elles effacées définitivement ou archivées ?" → `SoftDeletableEntity` |
|
|
71
71
|
| Aucune contrainte d'unicité | **Unicité non vérifiée** | "Deux entités peuvent-elles avoir le même nom/code/email ?" |
|
|
72
72
|
|
|
73
|
-
###
|
|
73
|
+
### Entity Patterns
|
|
74
74
|
|
|
75
|
-
| Besoin métier | Base class
|
|
75
|
+
| Besoin métier | Base class plateforme | Inclut automatiquement |
|
|
76
76
|
|---------------|----------------------|----------------------|
|
|
77
77
|
| Entité simple | `Entity` | Id, TenantId |
|
|
78
78
|
| Avec audit | `AuditableEntity` | + CreatedBy, CreatedDate, ModifiedBy, ModifiedDate |
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
28
|
-
##
|
|
28
|
+
## Platform Permission
|
|
29
29
|
|
|
30
30
|
**Format:** `business.{application}.{module}.{action}`
|
|
31
31
|
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
| Import | `.import` |
|
|
40
40
|
| Admin | `.admin` |
|
|
41
41
|
|
|
42
|
-
> **⚠️ RBAC ARCHITECTURE:
|
|
42
|
+
> **⚠️ RBAC ARCHITECTURE: La plateforme gère les rôles et permissions via son système RBAC intégré (HasData).**
|
|
43
43
|
>
|
|
44
44
|
> - Les rôles identifiés en Q6.1-Q6.4 sont des **ensembles de permissions**, pas des données métier
|
|
45
45
|
> - L'accès est contrôlé par des permissions attribuées aux rôles, pas par des propriétés d'entité
|
|
@@ -63,6 +63,6 @@
|
|
|
63
63
|
| Signal | Anti-pattern | Action |
|
|
64
64
|
|--------|-------------|--------|
|
|
65
65
|
| "Admin = accès total sans restriction" | **Super-admin sans granularité** | Même l'admin devrait avoir des permissions explicites, pas un bypass global |
|
|
66
|
-
| Aucune mention de multi-tenant | **Isolation oubliée** |
|
|
66
|
+
| Aucune mention de multi-tenant | **Isolation oubliée** | La plateforme est multi-tenant : chaque requête est filtrée par TenantId automatiquement |
|
|
67
67
|
| Pas d'audit trail | **Traçabilité absente** | `AuditableEntity` fournit CreatedBy/ModifiedBy. Suffisant ou besoin d'un audit log détaillé ? |
|
|
68
68
|
| Permissions uniquement CRUD | **Actions métier non couvertes** | Y a-t-il des actions spécifiques ? (valider, approuver, archiver, publier) → permissions custom |
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
28
|
-
##
|
|
28
|
+
## Platform Thresholds
|
|
29
29
|
|
|
30
30
|
| Metric | Acceptable Threshold |
|
|
31
31
|
|--------|---------------------|
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
| Q8.1 (response time) | "Rapide" | "< 1 seconde ? < 200ms ? Différence acceptable entre liste et détail ?" |
|
|
44
44
|
| Q8.2 (concurrent users) | "Pas beaucoup" | "Combien d'utilisateurs se connectent en même temps le matin ? Aux heures de pointe ?" |
|
|
45
45
|
| Q8.3 (peaks) | "Non" | "Pas de clôture mensuelle ? Pas de période de saisie massive ? Pas d'import batch ?" |
|
|
46
|
-
| Q8.4 (SLA) | "100% dispo" | "100% n'existe pas. 99.9% = ~8h d'indisponibilité/an. 99.5% est le standard
|
|
46
|
+
| Q8.4 (SLA) | "100% dispo" | "100% n'existe pas. 99.9% = ~8h d'indisponibilité/an. 99.5% est le standard de la plateforme." |
|
|
47
47
|
| Q8.6 (tests) | "Tests normaux" | "Tests unitaires ? Intégration ? E2E ? Tests de charge ? Tests de sécurité (OWASP) ?" |
|
|
48
48
|
| Q8.8 (acceptance) | Vide | "Quels critères pour que le PO valide la livraison ? Performance, fonctionnel, UX ?" |
|
|
49
49
|
|
|
@@ -51,6 +51,6 @@
|
|
|
51
51
|
|
|
52
52
|
| Signal | Anti-pattern | Action |
|
|
53
53
|
|--------|-------------|--------|
|
|
54
|
-
| SLA irréaliste (100%, < 10ms) | **Exigences impossibles** | Rappeler les seuils
|
|
54
|
+
| SLA irréaliste (100%, < 10ms) | **Exigences impossibles** | Rappeler les seuils de la plateforme et le coût de chaque 9 supplémentaire |
|
|
55
55
|
| Aucune mention de volume de données | **Scalabilité non planifiée** | "Avec 1M de lignes dans 2 ans, la recherche sera-t-elle toujours performante ?" |
|
|
56
56
|
| Pas de tests mentionnés | **Qualité non vérifiable** | Au minimum : tests unitaires services + tests intégration API |
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
28
|
-
##
|
|
28
|
+
## Platform Constraints
|
|
29
29
|
|
|
30
30
|
| Constraint | Impact | Non-négociable |
|
|
31
31
|
|-----------|--------|----------------|
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
|
|
44
44
|
| Question | If answer is vague/insufficient | Probe |
|
|
45
45
|
|----------|-------------------------------|-------|
|
|
46
|
-
| Q9.1 (tech stack) | Propose une technologie hors
|
|
46
|
+
| Q9.1 (tech stack) | Propose une technologie hors plateforme | "La plateforme impose .NET 8 + React 19. Cette contrainte est-elle compatible avec votre besoin ?" |
|
|
47
47
|
| Q9.2 (infrastructure) | "Cloud" sans précision | "Azure, AWS, on-premise ? Contraintes de localisation des données (pays) ?" |
|
|
48
48
|
| Q9.5 (budget) | "Pas de budget défini" | "Y a-t-il un nombre de jours maximum ? Une enveloppe à ne pas dépasser ?" |
|
|
49
49
|
| Q9.6 (deadline) | "Le plus vite possible" | "Y a-t-il une date métier impérative ? (réglementaire, événement, fin de contrat)" |
|
|
@@ -53,6 +53,6 @@
|
|
|
53
53
|
|
|
54
54
|
| Signal | Anti-pattern | Action |
|
|
55
55
|
|--------|-------------|--------|
|
|
56
|
-
| Technologie imposée hors stack | **Incompatibilité
|
|
56
|
+
| Technologie imposée hors stack | **Incompatibilité plateforme** | Clarifier : est-ce une intégration (OK) ou un remplacement de composant (risqué) ? |
|
|
57
57
|
| Pas de deadline | **Priorité floue** | "Sans deadline, comment prioriser par rapport aux autres demandes ?" |
|
|
58
|
-
| "Pas de contrainte" | **Contraintes implicites oubliées** | Multi-tenant, RGPD, audit, i18n sont des contraintes
|
|
58
|
+
| "Pas de contrainte" | **Contraintes implicites oubliées** | Multi-tenant, RGPD, audit, i18n sont des contraintes de la plateforme obligatoires |
|
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
28
|
-
##
|
|
28
|
+
## Documentation
|
|
29
29
|
|
|
30
30
|
| Type | Generated by | Format |
|
|
31
31
|
|------|-------------|--------|
|
|
32
|
-
| FRD Documentation | `/business-analyse:6-doc-html` | React page intégrée dans
|
|
32
|
+
| FRD Documentation | `/business-analyse:6-doc-html` | React page intégrée dans l'application web |
|
|
33
33
|
| Swagger API | Automatic (Swashbuckle) | OpenAPI 3.0 |
|
|
34
34
|
| User guide | Manual or AI | Markdown / PDF |
|
|
35
35
|
| Release notes | `/gitflow:11-finish` | Changelog automatique |
|