@atlashub/smartstack-cli 4.76.0 → 4.80.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/package.json +1 -1
  2. package/templates/project/claude-md/root.CLAUDE.md.template +1 -1
  3. package/templates/skills/ai-prompt/SKILL.md +64 -0
  4. package/templates/skills/ai-prompt/references/ai-agent-modes.md +89 -0
  5. package/templates/skills/ai-prompt/references/eval-framework.md +129 -0
  6. package/templates/skills/apex/references/checks/frontend-checks.sh +97 -11
  7. package/templates/skills/apex/references/checks/seed-checks.sh +34 -0
  8. package/templates/skills/apex/references/core-seed-data.md +7 -4
  9. package/templates/skills/apex/references/domain-events-pattern.md +45 -0
  10. package/templates/skills/apex/references/entity-hooks-pattern.md +68 -0
  11. package/templates/skills/apex/references/licensing-enforcement.md +52 -0
  12. package/templates/skills/apex/references/smartstack-api.md +112 -1
  13. package/templates/skills/apex-verify/steps/step-01-nav-audit.md +4 -0
  14. package/templates/skills/application/references/contexts-cheatsheet.md +86 -0
  15. package/templates/skills/application/references/extensions-system.md +158 -0
  16. package/templates/skills/application/references/frontend-route-naming.md +7 -5
  17. package/templates/skills/application/references/frontend-verification.md +7 -5
  18. package/templates/skills/application/references/provider-template.md +4 -2
  19. package/templates/skills/application/references/smartstack-provider.md +118 -0
  20. package/templates/skills/application/references/themes-db-driven.md +484 -0
  21. package/templates/skills/application/templates-seed.md +4 -2
  22. package/templates/skills/audit-route/references/routing-pattern.md +3 -1
  23. package/templates/skills/business-analyse/react/components.md +30 -28
  24. package/templates/skills/business-analyse/templates-react.md +15 -15
  25. package/templates/skills/cli-app-sync/SKILL.md +105 -4
  26. package/templates/skills/cli-app-sync/references/comparison-map.md +13 -0
  27. package/templates/skills/cli-app-sync/references/diff-entities.md +162 -0
  28. package/templates/skills/documentation/templates.md +16 -16
  29. package/templates/skills/migrate/SKILL.md +312 -0
  30. package/templates/skills/migrate/references/v3.34-to-v3.46.md +289 -0
  31. package/templates/skills/smoke-generation/SKILL.md +313 -0
  32. package/templates/skills/ui-components/SKILL.md +10 -0
  33. package/templates/skills/ui-components/references/component-catalog.md +82 -0
  34. package/templates/skills/workflow/SKILL.md +70 -1
@@ -0,0 +1,313 @@
1
+ ---
2
+ name: smoke-generation
3
+ description: Validate CLI templates by checking that every imported component, type, and method signature documented in /templates/skills/ actually exists in SmartStack.app (IA-Workflow). Catches the "EntityLookup paradox" class of drift where docs reference things that don't exist in the platform.
4
+ argument-hint: "[--quick|--full] [--scope=frontend|backend|all] [--app-path=<path>] [--report-only]"
5
+ model: sonnet
6
+ allowed-tools: Read, Grep, Glob, Bash, Write
7
+ ---
8
+
9
+ ## Current state (auto-injected)
10
+
11
+ - CLI version: !`node -p "require('./package.json').version" 2>/dev/null || echo "unknown"`
12
+ - App branch: !`git -C "D:/01 - projets/SmartStack.app/features/IA-Workflow" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown"`
13
+ - App last commit: !`git -C "D:/01 - projets/SmartStack.app/features/IA-Workflow" log --oneline -1 2>/dev/null || echo "unknown"`
14
+ - Last smoke run: !`cat .claude/cache/smoke-generation.json 2>/dev/null | head -5 || echo "no previous run"`
15
+
16
+ <objective>
17
+ Detect "documentation lies": patterns/imports/types that the CLI documents as canonical (and may even enforce via post-checks) but that do NOT exist in SmartStack.app. The canonical example is `EntityLookup`: documented in 4 CLI files and enforced by check C7, but the component does not exist in `web/smartstack-web/src/components/ui/`. This skill would have caught that on day 1.
18
+
19
+ Two modes :
20
+ - **`--quick` (default)** — pure static analysis (~30s). Greps imports / types / method signatures in `templates/skills/**/*.md`, verifies each one resolves to a real file or symbol in `D:/01 - projets/SmartStack.app/features/IA-Workflow/`.
21
+ - **`--full`** — runs an actual scaffold + `dotnet build` + `npm run build` in a sandbox. Heavier (~5-10 min) but catches runtime errors not visible by static analysis.
22
+ </objective>
23
+
24
+ <quick_start>
25
+ ```bash
26
+ /smoke-generation # Quick static analysis on all CLI templates
27
+ /smoke-generation --quick # Same as above (explicit)
28
+ /smoke-generation --full # Full sandbox scaffold + build (slow, thorough)
29
+ /smoke-generation --scope=frontend # Static analysis on frontend imports only
30
+ /smoke-generation --scope=backend # Static analysis on backend types/signatures only
31
+ /smoke-generation --report-only # Skip writing cache, print to stdout only
32
+ /smoke-generation --app-path=<path> # Override default IA-Workflow path
33
+ ```
34
+ </quick_start>
35
+
36
+ <paths>
37
+
38
+ ```
39
+ APP_ROOT = D:/01 - projets/SmartStack.app/features/IA-Workflow # default
40
+ APP_FRONTEND = $APP_ROOT/web/smartstack-web/src
41
+ APP_BACKEND = $APP_ROOT/src/SmartStack.Domain (+ Application + Infrastructure + Api)
42
+
43
+ CLI_TEMPLATES = D:/01 - projets/SmartStack.cli/02-Develop/templates/skills
44
+ CACHE_FILE = D:/01 - projets/SmartStack.cli/02-Develop/.claude/cache/smoke-generation.json
45
+ ```
46
+
47
+ If `--app-path=<path>` is provided, override `APP_ROOT`.
48
+
49
+ </paths>
50
+
51
+ <workflow>
52
+
53
+ ## Step 0 — Preflight
54
+
55
+ ```bash
56
+ APP_ROOT="${APP_PATH:-D:/01 - projets/SmartStack.app/features/IA-Workflow}"
57
+ [ -d "$APP_ROOT/src/SmartStack.Domain" ] || { echo "ERROR: APP_ROOT not found at $APP_ROOT"; exit 1; }
58
+ [ -d "$APP_ROOT/web/smartstack-web/src" ] || { echo "ERROR: app frontend not found"; exit 1; }
59
+ mkdir -p "D:/01 - projets/SmartStack.cli/02-Develop/.claude/cache"
60
+ ```
61
+
62
+ ## Step 1 — Frontend static checks (`--scope=frontend|all`)
63
+
64
+ ### 1.1 Extract every documented frontend import
65
+
66
+ Grep all `import { X } from '@/components/...'` (and similar) across `templates/skills/**/*.md` :
67
+
68
+ ```bash
69
+ TEMPLATES_ROOT="D:/01 - projets/SmartStack.cli/02-Develop/templates/skills"
70
+ APP_FRONTEND="$APP_ROOT/web/smartstack-web/src"
71
+
72
+ # Collect imports of the form: import { Foo, Bar } from '@/{path}'
73
+ grep -rPnho "import\s+\{[^}]+\}\s+from\s+['\"]@/[^'\"]+['\"]" "$TEMPLATES_ROOT" \
74
+ --include='*.md' --include='*.tsx' --include='*.ts' \
75
+ | sort -u > /tmp/smoke-imports.txt
76
+ ```
77
+
78
+ ### 1.2 Resolve each import against the real file system
79
+
80
+ For each line in `/tmp/smoke-imports.txt`:
81
+ - Extract the path part : `@/components/ui/EntityLookup` → `components/ui/EntityLookup`
82
+ - Extract the symbol(s) : `EntityLookup`, `EntityCard`, etc.
83
+ - Test : does `$APP_FRONTEND/components/ui/EntityLookup.tsx` exist ?
84
+ - If file exists, optional deeper check : grep the symbol export in the file (`export.*EntityLookup`)
85
+
86
+ ```bash
87
+ while IFS= read -r LINE; do
88
+ # Parse the path
89
+ PATH_PART=$(echo "$LINE" | sed -E "s/.*from\s+['\"]@\/([^'\"]+)['\"].*/\1/")
90
+ # Resolve to .ts / .tsx / .ts (index.ts)
91
+ FOUND=""
92
+ for EXT in ".tsx" ".ts" "/index.tsx" "/index.ts"; do
93
+ if [ -f "$APP_FRONTEND/${PATH_PART}${EXT}" ]; then
94
+ FOUND="$APP_FRONTEND/${PATH_PART}${EXT}"
95
+ break
96
+ fi
97
+ done
98
+ if [ -z "$FOUND" ]; then
99
+ echo "[BROKEN] @/${PATH_PART} ← documented in CLI, NOT in app"
100
+ fi
101
+ done < /tmp/smoke-imports.txt
102
+ ```
103
+
104
+ ### 1.3 Hook signatures (useTheme, useAuth, etc.)
105
+
106
+ Grep documented hook usages and verify the destructured field exists in the source :
107
+
108
+ ```bash
109
+ # Documented usages like : const { user, login, logout } = useAuth();
110
+ grep -rPnh "const\s+\{([^}]+)\}\s*=\s*use\w+\(\)" "$TEMPLATES_ROOT" \
111
+ --include='*.md' \
112
+ | sort -u > /tmp/smoke-hook-usages.txt
113
+ ```
114
+
115
+ For each `useX()` call, locate the matching context in `$APP_FRONTEND/contexts/{X}Context.tsx` (e.g. `useAuth` → `AuthContext.tsx`), extract the context value type, and verify each destructured field is exported. Symbols missing from the context value → `[BROKEN]`.
116
+
117
+ ### 1.4 Component props (DataTable, EntityCard, etc.)
118
+
119
+ For each documented component prop usage in templates (e.g. `<DataTable data={...} columns={...} searchable />`), open the component source file and verify the prop is declared in its `Props` interface. Mismatches → `[BROKEN]`.
120
+
121
+ ## Step 2 — Backend static checks (`--scope=backend|all`)
122
+
123
+ ### 2.1 Extract documented C# types and signatures
124
+
125
+ Grep all `using SmartStack.{X}` and explicit type names referenced in code blocks of `templates/skills/**/*.md` :
126
+
127
+ ```bash
128
+ APP_BACKEND_ROOT="$APP_ROOT/src"
129
+ grep -rPnh "^\s*using\s+SmartStack\.[A-Za-z.]+;" "$TEMPLATES_ROOT" --include='*.md' \
130
+ | sort -u > /tmp/smoke-usings.txt
131
+ ```
132
+
133
+ For each `using SmartStack.X.Y.Z;`, verify a corresponding directory or file exists under `$APP_BACKEND_ROOT/SmartStack.{Layer}/...`.
134
+
135
+ ### 2.2 Domain entity references
136
+
137
+ Grep documented C# class names (like `NavigationApplication`, `AiTool`, `WorkflowVersion`) in templates, then verify each one exists in `$APP_BACKEND_ROOT/SmartStack.Domain/`.
138
+
139
+ ```bash
140
+ # Pattern : public class Foo : BaseEntity
141
+ grep -rPnho "(?:public\s+)?(?:class|record|interface)\s+([A-Z][A-Za-z0-9]+)\s*:?\s*(?:BaseEntity|IRequest|I[A-Z][A-Za-z]+Entity)" "$TEMPLATES_ROOT" \
142
+ --include='*.md' \
143
+ | sort -u > /tmp/smoke-types.txt
144
+ ```
145
+
146
+ For each extracted type, run a Glob in `$APP_BACKEND_ROOT/**/*.cs` for `class TypeName` or `record TypeName`. No match → `[BROKEN]`.
147
+
148
+ ### 2.3 Method signatures
149
+
150
+ For commonly cited methods (`NavigationApplication.Create(...)`, `Permission.CreateForModule(...)`, etc.), grep the signature in the documented template and the actual signature in the source file. Compare parameter list (count + names). Diff → `[DRIFT]`.
151
+
152
+ Critical method signatures to cross-check :
153
+ - `NavigationApplication.Create` (currently `code, label, description?, icon?, iconType, route?, displayOrder, isOpen=false, isPersonal=false`)
154
+ - `Permission.CreateForModule`, `Permission.CreateForSection`, `Permission.CreateForResource`
155
+ - `BaseEntity.GetExtensionValue<T>` / `SetExtensionValue<T>` / `RemoveExtensionValue` / etc.
156
+
157
+ ## Step 3 — Cross-cut checks (always run)
158
+
159
+ ### 3.1 i18n namespace consistency
160
+ Already covered by `frontend-checks.sh` C28 — call it directly :
161
+ ```bash
162
+ bash "$TEMPLATES_ROOT/apex/references/checks/frontend-checks.sh" 2>&1 | grep -E "C28|i18n"
163
+ ```
164
+
165
+ ### 3.2 Theme tokens documented vs exposed
166
+ Compare the CSS variables documented in `application/references/themes-db-driven.md` against `$APP_FRONTEND/index.css`. Variables in doc but not in CSS → `[BROKEN]`.
167
+
168
+ ### 3.3 Layouts count
169
+ Verify exactly 4 layout files in `$APP_FRONTEND/layouts/` (`AppLayout`, `AuthLayout`, `DocsLayout`, `PublicLayout`).
170
+
171
+ ## Step 4 — Build the report
172
+
173
+ ```
174
+ ================================================================================
175
+ SMOKE GENERATION REPORT — {date}
176
+ ================================================================================
177
+ APP : IA-Workflow @ {commit}
178
+ CLI : v{version} @ {branch}
179
+ SCOPE : {scope} MODE : {quick|full}
180
+
181
+ [FRONTEND]
182
+ imports scanned : {N}
183
+ imports broken : {B}
184
+ hooks scanned : {N}
185
+ hooks broken : {B}
186
+ component props : {N} drift : {D}
187
+
188
+ [BACKEND]
189
+ usings scanned : {N} broken : {B}
190
+ types scanned : {N} missing : {M}
191
+ signatures scanned : {N} drift : {D}
192
+
193
+ [CROSS-CUT]
194
+ i18n consistency : {OK|FAIL}
195
+ theme tokens : {OK|FAIL — {n} missing}
196
+ layouts count : {OK|FAIL — found {n}, expected 4}
197
+
198
+ --------------------------------------------------------------------------------
199
+ DETAILED ISSUES
200
+ --------------------------------------------------------------------------------
201
+
202
+ [BROKEN] @/components/ui/EntityLookup
203
+ → Referenced in :
204
+ - templates/skills/ui-components/SKILL.md:64
205
+ - templates/skills/apex/references/smartstack-frontend.md:6 (multiple)
206
+ - templates/skills/apex/references/checks/frontend-checks.sh:147 (C7 enforcement)
207
+ → Action : either scaffold the component in app, OR remove from CLI doc.
208
+
209
+ [DRIFT] NavigationApplication.Create signature
210
+ → CLI docs : Create(code, label, ..., isOpen=false, isPersonal=false)
211
+ → App impl : Create(code, label, ..., isOpen=false, isPersonal=false, isHidden=false)
212
+ → Action : update templates to include `isHidden` parameter.
213
+
214
+ ...
215
+
216
+ --------------------------------------------------------------------------------
217
+ SUMMARY : {totalIssues} issues ({broken} BROKEN, {drift} DRIFT, {missing} MISSING)
218
+ ================================================================================
219
+ ```
220
+
221
+ ## Step 5 — Persist cache (unless `--report-only`)
222
+
223
+ ```bash
224
+ cat > "$CACHE_FILE" << EOF
225
+ {
226
+ "lastRun": "$(date -Iseconds)",
227
+ "appCommit": "$(git -C "$APP_ROOT" rev-parse --short HEAD)",
228
+ "appBranch": "$(git -C "$APP_ROOT" rev-parse --abbrev-ref HEAD)",
229
+ "scope": "{scope}",
230
+ "mode": "{quick|full}",
231
+ "totalIssues": {N},
232
+ "broken": {B},
233
+ "drift": {D},
234
+ "missing": {M}
235
+ }
236
+ EOF
237
+ ```
238
+
239
+ ## Step 6 — Exit code
240
+
241
+ - 0 issues → exit 0
242
+ - ≥ 1 issues → exit 1 (so the skill can be called as a CI quality gate, e.g. inside a pre-commit hook).
243
+
244
+ </workflow>
245
+
246
+ <full_mode>
247
+
248
+ ## `--full` mode (sandbox + real build)
249
+
250
+ This mode is documented for completeness but is OPTIONAL — `--quick` covers ~80 % of drifts at a tiny fraction of the cost.
251
+
252
+ ### Steps (full mode only)
253
+
254
+ 1. Create a sandbox under `~/.smartstack-smoke/run-{timestamp}/`
255
+ 2. Run `ss init smoke-test --provider=azure-devops --no-prompt` in the sandbox
256
+ 3. Generate a representative module via MCP : 1 entity (`Product`), 1 FK (`CategoryId`), one CRUD page set (List, Detail, Create, Edit)
257
+ 4. Run :
258
+ - `cd src/SmartStack.Api && dotnet restore && dotnet build`
259
+ - `cd web/smartstack-web && npm install && npm run build`
260
+ 5. Capture stderr/stdout, parse for errors, fail if any compile error or missing import
261
+ 6. Cleanup the sandbox unless `--keep-sandbox` flag is passed
262
+
263
+ ### When to prefer `--full` over `--quick`
264
+
265
+ - Before publishing a new CLI version (release gate)
266
+ - After a non-trivial refactor of MCP scaffolding
267
+ - When `--quick` reports 0 issues but you suspect a runtime-only problem
268
+
269
+ ### Cost
270
+ - Network : ~50-150 MB (npm install)
271
+ - Disk : ~500 MB (sandbox + node_modules)
272
+ - Time : 5-10 min (mostly npm install + dotnet restore)
273
+
274
+ </full_mode>
275
+
276
+ <integration>
277
+
278
+ ### Pre-commit hook
279
+ Add to `.git/hooks/pre-commit` (or via husky) :
280
+
281
+ ```bash
282
+ #!/bin/bash
283
+ # Block commits that introduce documentation drift
284
+ bash -c '/smoke-generation --quick --report-only' && exit 0 || {
285
+ echo "[smoke-generation] BROKEN imports / DRIFT detected — fix before commit."
286
+ exit 1
287
+ }
288
+ ```
289
+
290
+ ### Manual workflow
291
+ - After enriching any `templates/skills/**/*.md` with new imports/types : run `/smoke-generation --quick`
292
+ - Before opening a PR that touches multiple skills : run `/smoke-generation --quick` and paste the report into the PR description
293
+ - After bumping the SmartStack.app target branch : run `/smoke-generation --quick` to surface drifts triggered by the new version
294
+
295
+ </integration>
296
+
297
+ <known_limitations>
298
+
299
+ - **Quick mode misses runtime-only errors** : a bad TS generic, a wrong async return shape, a missing CSS class — `--full` mode is needed for these.
300
+ - **Heuristic regex** : may produce false positives on unusual import syntaxes (rare in practice). Verify each `[BROKEN]` manually if in doubt.
301
+ - **Single source of truth** : assumes the IA-Workflow branch IS the source of truth for v3.46+. Override via `--app-path` if testing against a different branch (e.g. for forward-compat testing on a feature branch).
302
+ - **Does not check MCP scaffolders** : the C# code emitted by MCP tools (`scaffold_extension`, `scaffold_routes`, …) is not validated by this skill. Use `--full` for that path.
303
+
304
+ </known_limitations>
305
+
306
+ <success_criteria>
307
+ - Quick mode runs in < 60 seconds on a clean install
308
+ - Detects the "EntityLookup class of drift" reliably (documented import not present in app)
309
+ - Detects method signature drift (parameters added/removed in app but doc not updated)
310
+ - Detects missing CSS theme variables (doc claims a token, app doesn't expose it)
311
+ - Reports are deterministic, scannable, and actionable
312
+ - Exit code reflects the number of issues — usable as a quality gate
313
+ </success_criteria>
@@ -66,6 +66,16 @@ description: |
66
66
 
67
67
  ---
68
68
 
69
+ ## Complete Component Catalog (v3.46+)
70
+
71
+ 32 shared components grouped in 7 categories : **Layout & Page chrome** (5), **Data display** (6), **Forms & dialogs** (5), **Permissions & tenant** (7), **Theme & branding** (5), **App shell** (2), **Documentation panel** (3).
72
+
73
+ **Always import from `@/components/ui/{Component}`** (or `@/components/docs/...` for doc panel pieces). **Never re-implement when one exists** (`<div role="button">`, `<input>` for FK, custom modal divs — all forbidden).
74
+
75
+ **See [references/component-catalog.md](references/component-catalog.md)** for the full table : import path + use case + relevant pattern reference for each of the 32 components.
76
+
77
+ ---
78
+
69
79
  ## CORE RULES (always apply)
70
80
 
71
81
  ### EntityCard is Mandatory
@@ -0,0 +1,82 @@
1
+ # Complete Component Catalog (v3.46+)
2
+
3
+ > Extracted from `SKILL.md` for clarity. Loaded only when generating a page or component that needs to discover what's available.
4
+
5
+ > Source : `D:/01 - projets/SmartStack.app/features/IA-Workflow/web/smartstack-web/src/components/ui/`
6
+
7
+ 32 shared components are exported by `@atlashub/smartstack`. Always import from `@/components/ui/{Component}` (or `@/components/docs/...` for doc panel pieces). **Never re-implement when one exists.**
8
+
9
+ ## Layout & Page chrome (always import)
10
+
11
+ | Component | Import | Use case |
12
+ |---|---|---|
13
+ | `PageTemplate` | `@/components/ui/PageTemplate` | Wraps every authenticated page — provides `space-y-6` rhythm and width container |
14
+ | `PageHeader` | `@/components/ui/PageHeader` | Title + subtitle + actions slot — used at top of every list/detail/form page |
15
+ | `Breadcrumb` | `@/components/ui/Breadcrumb` | Hierarchical nav (auto-derived from menu) |
16
+ | `PageLoader` | `@/components/ui/PageLoader` | Suspense fallback ; centered spinner |
17
+ | `UnderDevelopment` | `@/components/ui/UnderDevelopment` | Placeholder for routes that exist in seed but have no real page yet |
18
+
19
+ ## Data display
20
+
21
+ | Component | Import | Use case |
22
+ |---|---|---|
23
+ | `DataTable` | `@/components/ui/DataTable` | Sortable, searchable, paginated table — see [../patterns/data-table.md](../patterns/data-table.md) |
24
+ | `DataView` | `@/components/ui/DataView` | Envelope multi-mode (`table` / `cards` / `kanban`). Re-exports `ViewToggle`, `Pagination`, `StatusBadge`, `Avatar`, `KanbanColumn`, `KanbanCard` |
25
+ | `EntityCard` | `@/components/ui/EntityCard` | Entity card with avatar / badges / actions — see [../patterns/entity-card.md](../patterns/entity-card.md) |
26
+ | `KanbanBoard` | `@/components/ui/KanbanBoard` | Kanban board — see [../patterns/kanban.md](../patterns/kanban.md) |
27
+ | `ViewModeToggle` | `@/components/ui/ViewModeToggle` | Standalone view-mode toggle (`table`/`cards`/`kanban`) |
28
+ | `SortableList` | `@/components/ui/SortableList` | dnd-kit reorderable list (drag & drop) |
29
+
30
+ ## Forms & dialogs
31
+
32
+ | Component | Import | Use case |
33
+ |---|---|---|
34
+ | `EntityLookup` | `@/components/ui/EntityLookup` | **Mandatory** for FK Guid fields (debounced search, paginated results, display name resolution). See `apex/references/smartstack-frontend.md` §6 |
35
+ | `SelectWithOther` | `@/components/ui/SelectWithOther` | Select with "Autre…" free-text fallback |
36
+ | `ConfirmModal` | `@/components/ui/ConfirmModal` | Destructive action confirmation (Delete, Archive, …). 3 variants : `danger`, `warning`, `info` |
37
+ | `Drawer` | `@/components/ui/Drawer` | Side drawer (read-only details, filter panels). **Forbidden for create/edit forms** (use full-route pages instead, cf. C4) |
38
+ | `UnlockAccountModal` | `@/components/ui/UnlockAccountModal` | Account unlock flow (admin) |
39
+
40
+ ## Permissions & tenant
41
+
42
+ | Component | Import | Use case |
43
+ |---|---|---|
44
+ | `ProtectedButton` | `@/components/ui/ProtectedButton` | Button hidden / disabled when user lacks `permission` prop |
45
+ | `PermissionMatrix` | `@/components/ui/PermissionMatrix` | Roles × permissions grid (used on roles pages) |
46
+ | `ScopeBanner` | `@/components/ui/ScopeBanner` | Top banner showing the current tenant / global scope |
47
+ | `RestrictedModuleBanner` | `@/components/ui/RestrictedModuleBanner` | Shown when a module requires a license feature the user doesn't have |
48
+ | `TenantSelector` | `@/components/ui/TenantSelector` | Dropdown for switching tenant (header) |
49
+ | `TenantScopeSelector` | `@/components/ui/TenantScopeSelector` | Choose `tenant`/`shared`/`platform` scope when creating cross-tenant entities |
50
+ | `TenantScopeFilter` | `@/components/ui/TenantScopeFilter` | Filter list by scope (admin lists with cross-tenant data) |
51
+
52
+ ## Theme & branding
53
+
54
+ | Component | Import | Use case |
55
+ |---|---|---|
56
+ | `ThemeSwitcher` | `@/components/ui/ThemeSwitcher` | Light/Dark toggle (header) |
57
+ | `ThemeCustomizer` | `@/components/ui/ThemeCustomizer` | Per-user theme customization (preferences page) |
58
+ | `ThemeScopeSelector` | `@/components/ui/ThemeScopeSelector` | Choose theme apply scope (Global/Tenant/User) |
59
+ | `LanguageSwitcher` | `@/components/ui/LanguageSwitcher` | i18n language picker (header) |
60
+ | `Tooltip` | `@/components/ui/Tooltip` | Tooltip with variants (`error`, `warning`, `success`, `info`) |
61
+
62
+ ## App shell
63
+
64
+ | Component | Import | Use case |
65
+ |---|---|---|
66
+ | `AvatarMenu` | `@/components/ui/AvatarMenu` | User avatar + dropdown (logout, profile) — header right |
67
+ | `AppSwitcher` | `@/components/ui/AppSwitcher` | Module/app switcher in the sidebar (auto-built from menu) |
68
+
69
+ ## Documentation panel (auto-installed)
70
+
71
+ | Component | Import | Use case |
72
+ |---|---|---|
73
+ | `DocPanel` | `@/components/ui/DocPanel` | Side panel showing contextual `doc-data.ts` content (consumed via `DocPanelContext`) |
74
+ | `DocToggleButton` | `@/components/docs/DocToggleButton` | **Mandatory** in every list/detail page header — opens DocPanel |
75
+ | `DocEdgeButton` | `@/components/ui/DocEdgeButton` | Edge-attached button variant (rare — use `DocToggleButton` first) |
76
+
77
+ ## Component-availability rules
78
+
79
+ - If a component above exists, **always import it** — never re-implement (`<div role="button">`, `<input>` for FK, etc.).
80
+ - For new project-specific UI (e.g., `OrderTimeline`), generate locally under `src/components/{module}/`.
81
+ - For dashboard-only widgets (`StatCard`, `ChartCard`, `PeriodFilter`), generate inline — see [../patterns/dashboard-chart.md](../patterns/dashboard-chart.md).
82
+ - The 32 catalog components above are part of the SmartStack package contract — clients consume them via `@atlashub/smartstack`.
@@ -108,6 +108,73 @@ See `review-code/references/smartstack-conventions.md` (Domain Events section) f
108
108
  | Unique kebab-case codes | Infinite loops (A->B->A) |
109
109
  | Log executions | Forget email templates |
110
110
 
111
+ ## WorkflowVersion (R18 — v3.46+) — immutable snapshots
112
+
113
+ Every time a `Workflow` definition (metadata or steps) is modified, the application creates a `WorkflowVersion` snapshot:
114
+
115
+ ```csharp
116
+ class WorkflowVersion
117
+ {
118
+ public Guid Id { get; }
119
+ public Guid WorkflowId { get; }
120
+ public int VersionNumber { get; } // Monotonic per workflow, starts at 1
121
+ public string? ChangeDescription { get; } // Commit-message style, optional
122
+ public string SnapshotJson { get; } // { workflow: {…}, steps: [{…}] } — self-contained
123
+ public DateTime CreatedAt { get; }
124
+ public string? CreatedBy { get; }
125
+ }
126
+ ```
127
+
128
+ **Properties:**
129
+ - **Immutable** — once created, never updated. To "revert" a workflow → create a new version derived from a historical snapshot.
130
+ - **Self-contained JSON** — reading a snapshot is a JSON parse, not a query. Snapshots survive schema migration.
131
+ - Stored alongside the live workflow in `wkf_WorkflowVersions`.
132
+
133
+ **Use cases:**
134
+ - Audit trail (who changed what, when, why)
135
+ - Compare two versions side-by-side in admin UI
136
+ - Roll back a faulty workflow change without losing history
137
+ - Re-execute a paused execution against the version that was active when it started
138
+
139
+ **DO / DON'T:**
140
+ - DO populate `ChangeDescription` — empty descriptions blind operators
141
+ - DO surface version history in the admin UI on each `Workflow` detail page
142
+ - DON'T mutate or delete versions (the table should have only INSERT permissions in DB)
143
+ - DON'T snapshot on every single field change — batch via "Save" UX action
144
+
145
+ ## WorkflowExecution.PausedAtStepOrder (R6 — Wait step resumption)
146
+
147
+ `WorkflowExecution` exposes `PausedAtStepOrder` (nullable int) to support `Wait` step suspension:
148
+
149
+ ```csharp
150
+ // Suspend on a Wait step — Hangfire job will resume later
151
+ execution.PauseUntilResume(nextStepOrder: 5);
152
+ // Status becomes WaitingForResume (6), PausedAtStepOrder = 5
153
+
154
+ // When the Hangfire job fires :
155
+ execution.MarkResumed();
156
+ // Status becomes Running, PausedAtStepOrder reset to null
157
+ // Then the resumer iterates from PausedAtStepOrder onward
158
+ ```
159
+
160
+ **Status enum (with v3.46+ value 6):**
161
+ ```csharp
162
+ enum WorkflowExecutionStatus
163
+ {
164
+ Pending = 0, Running = 1, Completed = 2, Failed = 3,
165
+ PartiallyCompleted = 4, Cancelled = 5,
166
+ WaitingForResume = 6 // R6 — Wait step in progress, Hangfire scheduled
167
+ }
168
+ ```
169
+
170
+ **Implementation note:** the Hangfire job is scheduled by `WorkflowExecutionService` when a Wait step is encountered. The job's payload is the execution Id ; on fire, it loads the execution, calls `MarkResumed()`, and continues iterating from `PausedAtStepOrder`.
171
+
172
+ **DO / DON'T:**
173
+ - DO use `WaitingForResume` exclusively for Wait steps (not for other "in progress with delay" patterns)
174
+ - DO ensure the Hangfire job is idempotent (executions may resume more than once if the job retries)
175
+ - DON'T poll executions in `WaitingForResume` — Hangfire owns the scheduling
176
+ - DON'T remove `PausedAtStepOrder` history from completed executions (audit trail)
177
+
111
178
  ## Key Files
112
179
 
113
180
  | File | Role |
@@ -115,8 +182,10 @@ See `review-code/references/smartstack-conventions.md` (Domain Events section) f
115
182
  | `Domain/Communications/Workflow.cs` | Workflow entity |
116
183
  | `Domain/Communications/WorkflowStep.cs` | Step entity |
117
184
  | `Domain/Communications/WorkflowTrigger.cs` | Trigger entity |
185
+ | `Domain/Communications/WorkflowVersion.cs` | Immutable snapshot (R18 — v3.46+) |
186
+ | `Domain/Communications/WorkflowExecution.cs` | Execution + `PausedAtStepOrder` (R6 — v3.46+) |
118
187
  | `Application/Common/Interfaces/IWorkflowService.cs` | Interface |
119
- | `Infrastructure/Services/Workflow/WorkflowExecutionService.cs` | Implementation |
188
+ | `Infrastructure/Services/Workflow/WorkflowExecutionService.cs` | Implementation (Hangfire scheduling for Wait) |
120
189
  | `Infrastructure/.../WorkflowConfiguration.cs` | EF Config + Seed |
121
190
 
122
191
  <success_criteria>