@atlashub/smartstack-cli 2.5.3 → 2.6.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 (44) hide show
  1. package/.documentation/business-analyse.html +4 -4
  2. package/.documentation/commands.html +2 -2
  3. package/.documentation/index.html +2 -2
  4. package/.documentation/js/app.js +2 -2
  5. package/dist/index.js +163 -56
  6. package/dist/index.js.map +1 -1
  7. package/package.json +1 -1
  8. package/templates/mcp-scaffolding/component.tsx.hbs +14 -14
  9. package/templates/mcp-scaffolding/controller.cs.hbs +6 -5
  10. package/templates/skills/_resources/docs-manifest-schema.md +3 -3
  11. package/templates/skills/_resources/mcp-validate-documentation-spec.md +6 -6
  12. package/templates/skills/apex/steps/step-04b-doc-sync.md +4 -4
  13. package/templates/skills/apex/steps/step-05-examine.md +1 -1
  14. package/templates/skills/apex/templates/04b-doc-sync.md +1 -1
  15. package/templates/skills/application/SKILL.md +33 -16
  16. package/templates/skills/application/steps/step-00-init.md +86 -3
  17. package/templates/skills/application/steps/step-01-navigation.md +34 -0
  18. package/templates/skills/application/steps/step-02-permissions.md +37 -0
  19. package/templates/skills/application/steps/step-03-roles.md +23 -2
  20. package/templates/skills/application/steps/step-03b-provider.md +251 -0
  21. package/templates/skills/application/steps/step-04-backend.md +75 -0
  22. package/templates/skills/application/steps/step-05-frontend.md +149 -10
  23. package/templates/skills/application/steps/step-06-migration.md +27 -15
  24. package/templates/skills/application/steps/step-07-tests.md +404 -0
  25. package/templates/skills/application/steps/step-08-documentation.md +137 -0
  26. package/templates/skills/application/templates-frontend.md +133 -26
  27. package/templates/skills/application/templates-seed.md +116 -0
  28. package/templates/skills/business-analyse/SKILL.md +1 -1
  29. package/templates/skills/business-analyse/questionnaire/07-ui.md +15 -0
  30. package/templates/skills/business-analyse/questionnaire/10-documentation.md +2 -2
  31. package/templates/skills/business-analyse/schemas/feature-schema.json +96 -7
  32. package/templates/skills/business-analyse/steps/step-03-specify.md +134 -5
  33. package/templates/skills/business-analyse/steps/step-05-handoff.md +61 -8
  34. package/templates/skills/business-analyse/templates/tpl-frd.md +1 -1
  35. package/templates/skills/business-analyse/templates-frd.md +8 -8
  36. package/templates/skills/business-analyse/templates-react.md +26 -26
  37. package/templates/skills/documentation/SKILL.md +6 -6
  38. package/templates/skills/documentation/data-schema.md +70 -44
  39. package/templates/skills/documentation/templates.md +6 -6
  40. package/templates/skills/ralph-loop/SKILL.md +1 -2
  41. package/templates/skills/ralph-loop/steps/step-01-task.md +1 -1
  42. package/templates/skills/ui-components/SKILL.md +33 -2
  43. package/templates/skills/ui-components/patterns/dashboard-chart.md +327 -0
  44. package/templates/skills/ui-components/style-guide.md +27 -0
@@ -64,12 +64,12 @@ export function $MODULE_PASCALPage() {
64
64
  import { useState, useEffect } from 'react';
65
65
  import { useNavigate } from 'react-router-dom';
66
66
  import { useTranslation } from 'react-i18next';
67
- import { Plus, Search, MoreVertical, Pencil, Trash2, Check } from 'lucide-react';
67
+ import { Plus, Search, MoreVertical, Pencil, Trash2, Check, AlertCircle } from 'lucide-react';
68
68
  import { api } from '@/services/api/apiClient';
69
69
  import { use$MODULE_PASCALPreferences } from '@/hooks/use$MODULE_PASCALPreferences';
70
70
  import { Pagination } from '@/components/common/Pagination';
71
71
  import { ColumnSelector } from '@/components/common/ColumnSelector';
72
- import { ViewModeToggle } from '@/components/common/ViewModeToggle';
72
+ import { ViewToggle } from '@/components/ui/DataView';
73
73
  import { EntityCard } from '@/components/ui/EntityCard'; // ⚠️ MANDATORY for Grid view
74
74
 
75
75
  interface $ENTITY_PASCALDto {
@@ -217,7 +217,7 @@ export function $MODULE_PASCALListView({
217
217
  visibleColumns={visibleColumns}
218
218
  onChange={setVisibleColumns}
219
219
  />
220
- <ViewModeToggle value={viewMode} onChange={setViewMode} />
220
+ <ViewToggle value={viewMode} onChange={setViewMode} />
221
221
  </div>
222
222
  </div>
223
223
 
@@ -227,8 +227,19 @@ export function $MODULE_PASCALListView({
227
227
  <div className="animate-spin h-8 w-8 border-4 border-[var(--color-accent-500)] border-t-transparent rounded-full" />
228
228
  </div>
229
229
  ) : error ? (
230
- <div className="p-4 bg-[var(--error-bg)] border border-[var(--error-border)] text-[var(--error-text)]" style={{ borderRadius: 'var(--radius-card)' }}>
231
- {error}
230
+ <div className="p-4 bg-[var(--error-bg)] border border-[var(--error-border)] rounded-[var(--radius-card)] flex items-center gap-3">
231
+ <AlertCircle className="w-5 h-5 text-[var(--error-dot)] flex-shrink-0" />
232
+ <span className="text-[var(--error-text)]">{error}</span>
233
+ <button onClick={() => fetchData()} className="ml-auto text-sm text-[var(--error-text)] hover:underline">
234
+ {t('common:actions.retry')}
235
+ </button>
236
+ </div>
237
+ ) : data?.items.length === 0 ? (
238
+ <div className="text-center py-16">
239
+ <div className="w-16 h-16 mx-auto rounded-full bg-[var(--bg-secondary)] flex items-center justify-center mb-4">
240
+ <Search className="w-8 h-8 text-[var(--text-tertiary)]" />
241
+ </div>
242
+ <p className="text-[var(--text-secondary)]">{t('$module:list.empty')}</p>
232
243
  </div>
233
244
  ) : viewMode === 'list' ? (
234
245
  <div className="bg-[var(--bg-card)] border border-[var(--item-color-border)] overflow-hidden" style={{ borderRadius: 'var(--radius-card)' }}>
@@ -276,8 +287,8 @@ export function $MODULE_PASCALListView({
276
287
  <span
277
288
  className={`inline-flex items-center px-2 py-1 text-xs font-medium ${
278
289
  item.isActive
279
- ? 'bg-green-100 text-green-800'
280
- : 'bg-gray-100 text-gray-800'
290
+ ? 'bg-[var(--success-bg)] text-[var(--success-text)]'
291
+ : 'bg-[var(--bg-tertiary)] text-[var(--text-secondary)]'
281
292
  }`}
282
293
  style={{ borderRadius: 'var(--radius-badge)' }}
283
294
  >
@@ -477,17 +488,29 @@ export const $moduleApi = {
477
488
 
478
489
  ## TEMPLATE: ROUTES (App.tsx)
479
490
 
480
- ### ⚠️ CRITICAL RULE: NESTED ROUTES MANDATORY
491
+ ### ⚠️ CRITICAL RULE 1: ROUTES MUST BE INSIDE LAYOUT WRAPPER
481
492
 
482
- React Router v7 **requires** nested routes for multi-module applications.
493
+ SmartStack layouts (`AdminLayout`, `BusinessLayout`, `UserLayout`) provide the application shell: **header with AvatarMenu**, sidebar, navigation. They render child pages via React Router's `<Outlet />`.
483
494
 
484
- **❌ FORBIDDEN - Flat routes (cause redirects to Home)**
495
+ **If routes are placed OUTSIDE the layout wrapper, the shell (header, sidebar, AvatarMenu) will NOT render. The page appears "naked" without any navigation.**
496
+
497
+ **Step-by-step insertion:**
498
+
499
+ 1. Open `App.tsx`
500
+ 2. Find the existing layout route for the target context:
501
+ - `platform` → `<Route path="/platform" element={<AdminLayout />}>`
502
+ - `business` → `<Route path="/business" element={<BusinessLayout />}>`
503
+ - `personal` → `<Route path="/personal/myspace" element={<UserLayout />}>`
504
+ 3. Add the new routes **INSIDE** that `<Route>` block
505
+ 4. If a tenant-prefixed block exists (`/t/:slug/...`), add the routes there too
506
+
507
+ **❌ FORBIDDEN - Flat routes OUTSIDE layout (AvatarMenu disappears!)**
485
508
  ```tsx
486
- <Route path="$APPLICATION" element={<Navigate to="/$CONTEXT/$APPLICATION/$DEFAULT_MODULE" replace />} />
487
- <Route path="$APPLICATION/$MODULE" element={<$MODULE_PASCALPage />} />
509
+ // These routes bypass the layout system entirely = NO header, NO sidebar, NO AvatarMenu
510
+ <Route path="/$CONTEXT/$APPLICATION/$MODULE" element={<$MODULE_PASCALPage />} />
488
511
  ```
489
512
 
490
- **✅ MANDATORY - Nested routes with index**
513
+ **✅ MANDATORY - Routes INSIDE the existing layout wrapper**
491
514
  ```tsx
492
515
  // Add to App.tsx
493
516
 
@@ -495,13 +518,44 @@ import { $MODULE_PASCALPage } from '@/pages/$CONTEXT/$APPLICATION/$MODULE/$MODUL
495
518
  import { $MODULE_PASCALDetailPage } from '@/pages/$CONTEXT/$APPLICATION/$MODULE/$MODULE_PASCALDetailPage';
496
519
  import { Create$MODULE_PASCALPage } from '@/pages/$CONTEXT/$APPLICATION/$MODULE/Create$MODULE_PASCALPage';
497
520
 
498
- // In routes - NESTED STRUCTURE
521
+ // Find the EXISTING layout route and add routes INSIDE it:
522
+ <Route path="/$CONTEXT" element={<$CONTEXT_Layout />}>
523
+ {/* ... existing routes stay here ... */}
524
+
525
+ {/* NEW: $APPLICATION routes - added as children of the layout */}
526
+ <Route path="$APPLICATION">
527
+ <Route index element={<Navigate to="$DEFAULT_MODULE" replace />} />
528
+ <Route path="$MODULE" element={<$MODULE_PASCALPage />} />
529
+ <Route path="$MODULE/new" element={<Create$MODULE_PASCALPage />} />
530
+ <Route path="$MODULE/:id" element={<$MODULE_PASCALDetailPage />} />
531
+ <Route path="$MODULE/:id/edit" element={<Create$MODULE_PASCALPage />} />
532
+ </Route>
533
+ </Route>
534
+ ```
535
+
536
+ ### Context-to-Layout mapping
537
+
538
+ | Context | Layout Component | Layout Route Path |
539
+ |---------|------------------|-------------------|
540
+ | `platform` | `AdminLayout` | `/platform` |
541
+ | `business` | `BusinessLayout` | `/business` |
542
+ | `personal` | `UserLayout` | `/personal/myspace` |
543
+
544
+ ### ⚠️ CRITICAL RULE 2: NESTED ROUTES MANDATORY
545
+
546
+ React Router v7 **requires** nested routes for multi-module applications.
547
+
548
+ **❌ FORBIDDEN - Flat routes (cause redirects to Home)**
549
+ ```tsx
550
+ <Route path="$APPLICATION" element={<Navigate to="/$CONTEXT/$APPLICATION/$DEFAULT_MODULE" replace />} />
551
+ <Route path="$APPLICATION/$MODULE" element={<$MODULE_PASCALPage />} />
552
+ ```
553
+
554
+ **✅ MANDATORY - Nested routes with index**
555
+ ```tsx
499
556
  <Route path="$APPLICATION">
500
557
  <Route index element={<Navigate to="$DEFAULT_MODULE" replace />} />
501
558
  <Route path="$MODULE" element={<$MODULE_PASCALPage />} />
502
- <Route path="$MODULE/new" element={<Create$MODULE_PASCALPage />} />
503
- <Route path="$MODULE/:id" element={<$MODULE_PASCALDetailPage />} />
504
- <Route path="$MODULE/:id/edit" element={<Create$MODULE_PASCALPage />} />
505
559
  </Route>
506
560
  ```
507
561
 
@@ -509,6 +563,8 @@ import { Create$MODULE_PASCALPage } from '@/pages/$CONTEXT/$APPLICATION/$MODULE/
509
563
 
510
564
  | Aspect | Flat routes | Nested routes |
511
565
  |--------|------------|----------------|
566
+ | Shell rendered | ❌ No (bypasses layout) | ✅ Yes (Outlet pattern) |
567
+ | AvatarMenu visible | ❌ No | ✅ Yes |
512
568
  | Matching | Ambiguous between siblings | Hierarchical clear |
513
569
  | Navigate | Must be absolute | Can be relative |
514
570
  | Outlet | Not supported | Supported |
@@ -516,16 +572,67 @@ import { Create$MODULE_PASCALPage } from '@/pages/$CONTEXT/$APPLICATION/$MODULE/
516
572
 
517
573
  ---
518
574
 
575
+ ## ⛔ FORBIDDEN PATTERNS
576
+
577
+ These patterns are **strictly prohibited** in generated frontend code:
578
+
579
+ | FORBIDDEN | REQUIRED |
580
+ |-----------|----------|
581
+ | `import axios from 'axios'` | `import { api } from '@/services/api/apiClient'` |
582
+ | `bg-blue-600`, `text-gray-900`, `bg-green-100` | `bg-[var(--color-accent-600)]`, `text-[var(--text-primary)]`, `bg-[var(--success-bg)]` |
583
+ | Any hardcoded Tailwind color (`bg-{color}-{shade}`) | CSS variables from style-guide.md |
584
+ | `rounded-lg`, `rounded-md` | `rounded-[var(--radius-card)]`, `rounded-[var(--radius-button)]` |
585
+ | Custom `<div>` cards for entity lists | `<EntityCard>` component (MANDATORY) |
586
+ | Flat routes outside Layout wrapper | Nested routes inside `<BusinessLayout>` / `<AdminLayout>` |
587
+ | Only 2 languages (fr/en) | All 4 languages (fr/en/it/de) |
588
+ | `[Authorize]` without permissions | `[RequirePermission("navRoute.action")]` per endpoint |
589
+ | Missing error state | Error state with retry button (AlertCircle + underline) |
590
+ | Missing empty state | Empty state with icon + message |
591
+ | `new Date().toLocaleDateString()` without locale | Date formatting via i18n or Intl |
592
+
593
+ ---
594
+
519
595
  ## FRONTEND CHECKLIST
520
596
 
597
+ ### Structure
598
+ | Check | Status |
599
+ |-------|--------|
600
+ | ☐ Main page created (`$MODULE_PASCALPage.tsx`) | |
601
+ | ☐ ListView component created (`$MODULE_PASCALListView.tsx`) | |
602
+ | ☐ Preferences hook created (`use$MODULE_PASCALPreferences.ts`) | |
603
+ | ☐ API service created (uses `apiClient`, NOT raw axios) | |
604
+ | ☐ Routes added inside Layout wrapper in App.tsx | |
605
+ | ☐ Route path follows `/{context}/{application}/{module}` | |
606
+
607
+ ### Theme Compliance
608
+ | Check | Status |
609
+ |-------|--------|
610
+ | ☐ Zero hardcoded Tailwind colors (grep: `bg-blue-`, `text-gray-`, etc.) | |
611
+ | ☐ All colors use CSS variables (`var(--*)`) | |
612
+ | ☐ Border radius uses `var(--radius-*)` | |
613
+ | ☐ Buttons follow style-guide.md variants | |
614
+
615
+ ### UI Components
616
+ | Check | Status |
617
+ |-------|--------|
618
+ | ☐ Grid view uses `EntityCard` (not custom divs) | |
619
+ | ☐ `ViewToggle` for list/grid switch | |
620
+ | ☐ Loading state (spinner) | |
621
+ | ☐ Error state (AlertCircle + retry button) | |
622
+ | ☐ Empty state (icon + message) | |
623
+ | ☐ Pagination component | |
624
+
625
+ ### i18n
626
+ | Check | Status |
627
+ |-------|--------|
628
+ | ☐ French (fr) file created | |
629
+ | ☐ English (en) file created | |
630
+ | ☐ Italian (it) file created | |
631
+ | ☐ German (de) file created | |
632
+ | ☐ All 4 files have identical keys | |
633
+
634
+ ### Build
521
635
  | Check | Status |
522
636
  |-------|--------|
523
- | ☐ Main page created | |
524
- | ☐ ListView component created | |
525
- | ☐ Preferences hook created | |
526
- | ☐ API service created | |
527
- | ☐ Routes added to App.tsx | |
528
- | ☐ Uses apiClient (no direct calls) | |
529
- | ☐ No Infrastructure imports | |
530
- | ☐ npm run build successful | |
531
- | ☐ npm run lint successful | |
637
+ | ☐ `npm run build` successful | |
638
+ | ☐ `npm run lint` successful | |
@@ -802,6 +802,120 @@ private static Guid GenerateEntityGuid(string uniqueKey)
802
802
 
803
803
  ---
804
804
 
805
+ ## TEMPLATE: CLIENT SEED DATA PROVIDER
806
+
807
+ > **Usage:** Client projects (projectType: "client") to seed data into the Core schema
808
+ > **Mechanism:** Runtime seeding via IClientSeedDataProvider (no Core migrations required)
809
+ > **When:** Generated automatically at step 03b if the project is of type client
810
+
811
+ ### Difference with HasData()
812
+
813
+ | Aspect | HasData() (core) | IClientSeedDataProvider (client) |
814
+ |--------|-----------------|----------------------------------|
815
+ | When | EF Core migration | Application startup |
816
+ | Where | In Core migrations | Runtime via CoreDbContext |
817
+ | Who | SmartStack.app | Client project |
818
+ | Idempotent | Yes (single migration) | Yes (check existence) |
819
+ | Core migration | Yes | No |
820
+ | Entities created with | Anonymous objects | Factory methods (mandatory) |
821
+
822
+ ### Implementation Pattern
823
+
824
+ The provider is generated in:
825
+ `Infrastructure/Persistence/Seeding/{AppPascalName}SeedDataProvider.cs`
826
+
827
+ It consumes the SeedData files generated in steps 01-03:
828
+ - `{Module}NavigationSeedData.cs` (GUIDs + navigation data)
829
+ - `{Module}NavigationTranslationSeedData.cs` (4-language translations)
830
+ - `{Module}PermissionSeedData.cs` (RBAC permissions)
831
+ - `{Module}RolePermissionSeedData.cs` (role -> permission mappings)
832
+
833
+ ### DI Registration
834
+
835
+ In `Infrastructure/DependencyInjection.cs`:
836
+ ```csharp
837
+ services.AddScoped<IClientSeedDataProvider, {AppPascalName}SeedDataProvider>();
838
+ ```
839
+
840
+ ### Execution Pipeline
841
+
842
+ ```
843
+ InitializeSmartStackAsync()
844
+ 1. MigrateAsync() -> Core schema created
845
+ 2. IDatabaseSeeder.SeedAsync() -> System users, tenant
846
+ 3. IClientSeedDataProvider.Seed*() -> Navigation + Permissions + Roles CLIENT
847
+ 4. IDevDataSeeder.SeedAsync() -> Dev data
848
+ 5. InitializeNavigationRoutingAsync -> Routes loaded (including client routes)
849
+ ```
850
+
851
+ ### Provider Template
852
+
853
+ ```csharp
854
+ using Microsoft.EntityFrameworkCore;
855
+ using SmartStack.Application.Common.Interfaces;
856
+ using SmartStack.Domain.Navigation;
857
+ using SmartStack.Domain.Platform.Administration.Roles;
858
+
859
+ namespace {BaseNamespace}.Infrastructure.Persistence.Seeding;
860
+
861
+ public class {AppPascalName}SeedDataProvider : IClientSeedDataProvider
862
+ {
863
+ public int Order => 100;
864
+
865
+ public async Task SeedNavigationAsync(ICoreDbContext context, CancellationToken ct)
866
+ {
867
+ var exists = await context.NavigationApplications
868
+ .AnyAsync(a => a.Code == "{app_code}", ct);
869
+ if (exists) return;
870
+
871
+ var parentContext = await context.NavigationContexts
872
+ .FirstAsync(c => c.Code == "{context_code}", ct);
873
+
874
+ var app = NavigationApplication.Create(
875
+ parentContext.Id, "{app_code}", "{app_label_en}",
876
+ "{app_desc_en}", "{app_icon}", IconType.Lucide,
877
+ "/{context_code}/{app_code}", {display_order});
878
+ context.NavigationApplications.Add(app);
879
+ await ((DbContext)context).SaveChangesAsync(ct);
880
+
881
+ // Create modules from {Module}NavigationSeedData
882
+ // Create translations from {Module}NavigationTranslationSeedData
883
+ }
884
+
885
+ public async Task SeedPermissionsAsync(ICoreDbContext context, CancellationToken ct)
886
+ {
887
+ var exists = await context.Permissions
888
+ .AnyAsync(p => p.Path == "{full_path}.*", ct);
889
+ if (exists) return;
890
+
891
+ // Create permissions from {Module}PermissionSeedData
892
+ // Use Permission.CreateForModule(...) and Permission.CreateWildcard(...)
893
+ }
894
+
895
+ public async Task SeedRolePermissionsAsync(ICoreDbContext context, CancellationToken ct)
896
+ {
897
+ var exists = await context.RolePermissions
898
+ .AnyAsync(rp => rp.Permission!.Path.StartsWith("{full_path}."), ct);
899
+ if (exists) return;
900
+
901
+ // Create role-permissions from {Module}RolePermissionSeedData
902
+ // Use RolePermission.Create(roleId, permissionId, "system")
903
+ }
904
+ }
905
+ ```
906
+
907
+ ### Critical Rules
908
+
909
+ | Rule | Description |
910
+ |------|-------------|
911
+ | Factory methods | `NavigationModule.Create(...)`, `Permission.CreateForModule(...)` - NEVER `new Entity()` |
912
+ | Idempotence | Each Seed method checks existence before inserting |
913
+ | SaveChanges per group | Navigation -> save -> Permissions -> save -> RolePermissions -> save |
914
+ | Deterministic GUIDs | Use IDs from SeedData classes (not `Guid.NewGuid()`) |
915
+ | FK resolution by Code | Parent modules found by `Code`, not hardcoded GUID |
916
+
917
+ ---
918
+
805
919
  ## SEED CHECKLIST
806
920
 
807
921
  | Check | Status |
@@ -818,6 +932,8 @@ private static Guid GenerateEntityGuid(string uniqueKey)
818
932
  | ☐ RolePermissions assigned | |
819
933
  | ☐ Entity SeedData.cs created (if user opted in) | |
820
934
  | ☐ DevDataSeeder.cs updated (if user opted in) | |
935
+ | ☐ IClientSeedDataProvider generated (client projects only) | |
936
+ | ☐ Provider registered in DI (client projects only) | |
821
937
 
822
938
  ---
823
939
 
@@ -240,7 +240,7 @@ Load ONLY relevant categories based on feature type:
240
240
  | Template | File | Used in step |
241
241
  | -------- | ----------------------------------- | ------------ |
242
242
  | schema | `schemas/feature-schema.json` | All steps |
243
- | frd | `templates/tpl-frd.md` | 02 |
243
+ | spec | `templates/tpl-frd.md` | 02 |
244
244
  | handoff | `templates/tpl-handoff.md` | 04 |
245
245
  | suggestions | `patterns/suggestion-catalog.md` | 01 |
246
246
 
@@ -23,6 +23,15 @@
23
23
  | Q7.7 | Key information per screen? | Per screen |
24
24
  | Q7.8 | Possible actions per screen? | Per screen |
25
25
 
26
+ ## 7.3 Dashboards & Analytics
27
+
28
+ | # | Question | Answer Type |
29
+ |---|----------|-------------|
30
+ | Q7.9 | Dashboards ou tableaux de bord requis ? | List (noms + descriptions) |
31
+ | Q7.10 | KPIs à afficher par dashboard ? | Per dashboard: nom, métrique, format (number/currency/percent), seuils |
32
+ | Q7.11 | Types de graphiques souhaités ? | Per KPI: bar, line, pie, area, scatter, kpi-card |
33
+ | Q7.12 | Filtres temporels ? | Période par défaut + plages disponibles (jour/semaine/mois/trimestre/année) |
34
+
26
35
  ---
27
36
 
28
37
  ## UI Components
@@ -38,6 +47,9 @@
38
47
  | Detail view | DetailPanel | Side panel ou page dédiée |
39
48
  | Status/Workflow | StatusBadge + Timeline | Affichage état + historique transitions |
40
49
  | Tooltips/Infobulles | Tooltip | Info contextuelle sur champs/actions |
50
+ | KPI Card | StatCard | Valeur numérique + tendance + icône |
51
+ | Chart (Bar/Line/Pie) | RechartsChart | Graphique interactif via Recharts |
52
+ | Dashboard layout | DashboardGrid | Grille responsive de KPI + charts |
41
53
 
42
54
  ## Elicitation Guide
43
55
 
@@ -50,6 +62,8 @@
50
62
  | Q7.5 (screens) | Pas de mention dashboard | "L'utilisateur a-t-il besoin d'un tableau de bord avec des KPIs avant de plonger dans les données ?" |
51
63
  | Q7.7 (key info) | "Toutes les colonnes" | "Sur mobile/petit écran, quelles 3-4 colonnes sont indispensables ? Le reste = détail secondaire" |
52
64
  | Q7.8 (actions) | "CRUD classique" | "Actions métier spécifiques ? (valider, dupliquer, archiver, changer statut, assigner)" |
65
+ | Q7.9 (dashboards) | "Juste des chiffres" | "Les tendances/comparaisons ne seraient-elles pas plus lisibles en graphique ? Bar chart pour comparer, line chart pour évoluer ?" |
66
+ | Q7.10 (KPIs) | Pas de seuils définis | "À partir de quel seuil un KPI est-il en alerte ? En critique ? (ex: stock < 10 = warning, < 3 = critique)" |
53
67
 
54
68
  ### Anti-patterns to Detect
55
69
 
@@ -59,3 +73,4 @@
59
73
  | Aucune mention de feedback utilisateur | **UX silencieuse** | "Quels messages de succès/erreur ? Toast, notification, redirect ?" |
60
74
  | "Identique à [autre app]" | **Copier sans adapter** | "Quelles différences de contexte ? L'utilisateur fait-il le même parcours ?" |
61
75
  | Actions sans confirmation | **Actions destructives non protégées** | "La suppression nécessite-t-elle une confirmation ? Un motif ? Une double validation ?" |
76
+ | "Juste des chiffres sur la page" | **Dashboard sans visualisation** | "Les tendances/comparaisons ne seraient-elles pas plus lisibles en graphique ? Bar chart pour comparer, line chart pour évoluer ?" |
@@ -20,7 +20,7 @@
20
20
 
21
21
  | Type | Generated by | Format |
22
22
  |------|-------------|--------|
23
- | FRD Documentation | `/business-analyse:6-doc-html` | React page intégrée dans l'application web |
23
+ | Documentation module | `/documentation` (auto step-08) | React page intégrée via doc-data.ts + DocRenderer |
24
24
  | Swagger API | Automatic (Swashbuckle) | OpenAPI 3.0 |
25
25
  | User guide | Manual or AI | Markdown / PDF |
26
26
  | Release notes | `/gitflow:11-finish` | Changelog automatique |
@@ -40,4 +40,4 @@
40
40
 
41
41
  | Signal | Anti-pattern | Action |
42
42
  |--------|-------------|--------|
43
- | "La doc se fera après" | **Documentation en dette** | Le FRD EST la doc. `/business-analyse:6-doc-html` la génère automatiquement. |
43
+ | "La doc se fera après" | **Documentation en dette** | Le feature.json EST la doc. `/documentation` la génère automatiquement au step-08. |
@@ -214,7 +214,7 @@
214
214
 
215
215
  "analysis": {
216
216
  "type": "object",
217
- "description": "Enriched by step-01-analyse (analysis part, merged from old BRD step)",
217
+ "description": "Enriched by step-01-analyse (analysis part, merged from old business requirements step)",
218
218
  "properties": {
219
219
  "objectives": {
220
220
  "type": "array",
@@ -569,12 +569,18 @@
569
569
  },
570
570
  "uiWireframes": {
571
571
  "type": "array",
572
+ "description": "MANDATORY wireframes for every module section. Each section MUST have at least one wireframe validated by the client. These wireframes are traced through to frontend implementation via linkedWireframes in handoff.filesToCreate.",
572
573
  "items": {
573
574
  "type": "object",
575
+ "required": ["screen", "mockup", "elements", "section"],
574
576
  "properties": {
575
- "screen": { "type": "string" },
577
+ "screen": { "type": "string", "description": "Unique screen identifier: {module}-{section} (e.g., orders-list, orders-detail)" },
576
578
  "description": { "type": "string" },
577
- "elements": { "type": "array", "items": { "type": "string" } },
579
+ "elements": {
580
+ "type": "array",
581
+ "items": { "type": "string" },
582
+ "description": "UI components in this wireframe (DataGrid, FilterBar, Form, etc.). Used for component mapping."
583
+ },
578
584
  "actions": { "type": "array", "items": { "type": "string" } },
579
585
  "permissionsRequired": { "type": "array", "items": { "type": "string" } },
580
586
  "mockupFormat": {
@@ -584,15 +590,77 @@
584
590
  },
585
591
  "mockup": {
586
592
  "type": "string",
587
- "description": "ASCII art or SVG markup of the wireframe"
593
+ "description": "ASCII art or SVG markup of the wireframe. MANDATORY: captures the layout validated by the client."
588
594
  },
589
595
  "section": {
590
596
  "type": "string",
591
- "description": "Navigation section this wireframe belongs to (e.g., list, detail, create)"
597
+ "description": "Navigation section this wireframe belongs to (e.g., list, detail, create, dashboard)"
598
+ },
599
+ "componentMapping": {
600
+ "type": "array",
601
+ "description": "Mapping of wireframe elements to SmartStack React components",
602
+ "items": {
603
+ "type": "object",
604
+ "properties": {
605
+ "wireframeElement": { "type": "string", "description": "Element name from the wireframe (e.g., DataGrid)" },
606
+ "reactComponent": { "type": "string", "description": "SmartStack React component to use (e.g., SmartTable)" }
607
+ }
608
+ }
592
609
  }
593
610
  }
594
611
  }
595
612
  },
613
+ "dashboards": {
614
+ "type": "array",
615
+ "description": "Dashboard specifications with KPIs and chart configurations. Captured during step-03 when a 'dashboard' section is selected.",
616
+ "items": {
617
+ "type": "object",
618
+ "required": ["code", "title", "kpis"],
619
+ "properties": {
620
+ "code": { "type": "string", "description": "Dashboard identifier (kebab-case, e.g., fleet-dashboard)" },
621
+ "title": { "type": "string" },
622
+ "description": { "type": "string" },
623
+ "linkedUCs": { "type": "array", "items": { "type": "string" } },
624
+ "refreshMode": { "type": "string", "enum": ["static", "polling", "signalr"], "default": "static" },
625
+ "defaultPeriod": { "type": "string", "enum": ["day", "week", "month", "quarter", "year"], "default": "month" },
626
+ "filters": {
627
+ "type": "array",
628
+ "items": {
629
+ "type": "object",
630
+ "properties": {
631
+ "field": { "type": "string" },
632
+ "type": { "type": "string", "enum": ["dateRange", "select", "multiselect", "search"] },
633
+ "label": { "type": "string" }
634
+ }
635
+ }
636
+ },
637
+ "kpis": {
638
+ "type": "array",
639
+ "items": {
640
+ "type": "object",
641
+ "required": ["code", "label", "metric", "visualization"],
642
+ "properties": {
643
+ "code": { "type": "string" },
644
+ "label": { "type": "string" },
645
+ "metric": { "type": "string", "description": "Description of calculation (e.g. COUNT(vehicles WHERE status=active))" },
646
+ "format": { "type": "string", "enum": ["number", "currency", "percent", "duration"], "default": "number" },
647
+ "visualization": { "type": "string", "enum": ["kpi-card", "bar", "line", "pie", "area", "donut", "stacked-bar"] },
648
+ "dataSource": { "type": "string", "description": "Entity or endpoint providing data" },
649
+ "dimensions": { "type": "array", "items": { "type": "string" }, "description": "Grouping dimensions (e.g. status, month)" },
650
+ "thresholds": {
651
+ "type": "object",
652
+ "properties": {
653
+ "warning": { "type": "number" },
654
+ "critical": { "type": "number" }
655
+ }
656
+ }
657
+ }
658
+ }
659
+ },
660
+ "permissionsRequired": { "type": "array", "items": { "type": "string" } }
661
+ }
662
+ }
663
+ },
596
664
  "messages": {
597
665
  "type": "array",
598
666
  "description": "Business messages (success, error, warning, info) with i18n keys. MANDATORY: ≥4 messages.",
@@ -862,6 +930,17 @@
862
930
  }
863
931
  },
864
932
 
933
+ "documentation": {
934
+ "type": "object",
935
+ "description": "Documentation requirements captured during BA (questionnaire 10). Consumed by /application step-08 to auto-generate in-app documentation.",
936
+ "properties": {
937
+ "userDocRequired": { "type": "boolean", "default": true, "description": "Whether in-app user documentation page should be generated" },
938
+ "techDocRequired": { "type": "boolean", "default": false, "description": "Whether technical documentation (ERD, API) should be generated" },
939
+ "generatedAt": { "type": ["string", "null"], "format": "date-time", "description": "Timestamp when documentation was last generated" },
940
+ "status": { "type": "string", "enum": ["pending", "generated", "skipped"], "default": "pending" }
941
+ }
942
+ },
943
+
865
944
  "suggestions": {
866
945
  "type": "array",
867
946
  "description": "Proactive AI suggestions for complementary modules/sections",
@@ -917,14 +996,24 @@
917
996
  "required": ["path", "type"],
918
997
  "properties": {
919
998
  "path": { "type": "string", "description": "Relative file path" },
920
- "type": { "type": "string", "description": "File type (Entity, Service, DTO, Repository, Migration, HasData, Constants, ApiController, Page, Component, ApiClient, ReduxSlice, UnitTests, IntegrationTests, Enum)" },
999
+ "type": { "type": "string", "description": "File type (Entity, Service, DTO, Repository, Migration, HasData, Constants, ApiController, Page, DashboardPage, Component, ApiClient, ReduxSlice, UnitTests, IntegrationTests, Enum)" },
921
1000
  "linkedFRs": { "type": "array", "items": { "type": "string" }, "description": "Linked functional requirement IDs (FR-XXX)" },
922
1001
  "linkedUCs": { "type": "array", "items": { "type": "string" }, "description": "Linked use case IDs (UC-XXX)" },
1002
+ "linkedWireframes": {
1003
+ "type": "array",
1004
+ "items": { "type": "string" },
1005
+ "description": "Linked wireframe screen identifiers from specification.uiWireframes[].screen. MANDATORY for Page and DashboardPage types. Ensures BA mockups are traced to implementation."
1006
+ },
1007
+ "wireframeAcceptanceCriteria": {
1008
+ "type": "string",
1009
+ "description": "Acceptance criteria describing how the implementation must match the wireframe layout. MANDATORY for Page and DashboardPage types."
1010
+ },
923
1011
  "category": { "type": "string", "enum": ["core", "business"], "description": "SeedData category: core (navigation/permissions) or business (lookup tables)" },
924
1012
  "source": { "type": "string", "description": "Source path in feature.json for derivation (e.g., specification.seedDataCore.permissions)" },
925
1013
  "description": { "type": "string" },
926
1014
  "pattern": { "type": "string", "description": "Reference pattern from existing codebase" },
927
- "instructions": { "type": "string" }
1015
+ "instructions": { "type": "string" },
1016
+ "dashboardRef": { "type": "string", "description": "Reference to specification.dashboards[].code for DashboardPage type files" }
928
1017
  }
929
1018
  }
930
1019
  }