@atlashub/smartstack-cli 3.31.0 → 3.32.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 (52) hide show
  1. package/.documentation/installation.html +7 -2
  2. package/README.md +7 -1
  3. package/dist/index.js +33 -37
  4. package/dist/index.js.map +1 -1
  5. package/dist/mcp-entry.mjs +547 -97
  6. package/dist/mcp-entry.mjs.map +1 -1
  7. package/package.json +1 -1
  8. package/scripts/health-check.sh +2 -1
  9. package/templates/mcp-scaffolding/controller.cs.hbs +10 -7
  10. package/templates/mcp-scaffolding/entity-extension.cs.hbs +132 -124
  11. package/templates/mcp-scaffolding/frontend/api-client.ts.hbs +4 -4
  12. package/templates/mcp-scaffolding/tests/controller.test.cs.hbs +38 -15
  13. package/templates/mcp-scaffolding/tests/service.test.cs.hbs +20 -8
  14. package/templates/skills/apex/SKILL.md +7 -9
  15. package/templates/skills/apex/_shared.md +9 -2
  16. package/templates/skills/apex/references/code-generation.md +412 -0
  17. package/templates/skills/apex/references/post-checks.md +377 -37
  18. package/templates/skills/apex/references/smartstack-api.md +229 -5
  19. package/templates/skills/apex/references/smartstack-frontend.md +368 -11
  20. package/templates/skills/apex/references/smartstack-layers.md +54 -7
  21. package/templates/skills/apex/steps/step-00-init.md +1 -2
  22. package/templates/skills/apex/steps/step-01-analyze.md +45 -2
  23. package/templates/skills/apex/steps/step-02-plan.md +23 -2
  24. package/templates/skills/apex/steps/step-03-execute.md +195 -5
  25. package/templates/skills/apex/steps/step-04-examine.md +18 -5
  26. package/templates/skills/apex/steps/step-05-deep-review.md +9 -11
  27. package/templates/skills/apex/steps/step-06-resolve.md +5 -9
  28. package/templates/skills/apex/steps/step-07-tests.md +66 -1
  29. package/templates/skills/apex/steps/step-08-run-tests.md +12 -3
  30. package/templates/skills/application/references/provider-template.md +62 -39
  31. package/templates/skills/application/templates-backend.md +3 -3
  32. package/templates/skills/application/templates-frontend.md +12 -12
  33. package/templates/skills/application/templates-seed.md +14 -4
  34. package/templates/skills/business-analyse/SKILL.md +9 -6
  35. package/templates/skills/business-analyse/questionnaire/04-data.md +8 -0
  36. package/templates/skills/business-analyse/references/agent-module-prompt.md +84 -5
  37. package/templates/skills/business-analyse/references/agent-pooling-best-practices.md +83 -19
  38. package/templates/skills/business-analyse/references/consolidation-structural-checks.md +6 -2
  39. package/templates/skills/business-analyse/references/team-orchestration.md +443 -110
  40. package/templates/skills/business-analyse/references/validation-checklist.md +5 -4
  41. package/templates/skills/business-analyse/schemas/sections/analysis-schema.json +44 -0
  42. package/templates/skills/business-analyse/steps/step-03a2-analysis.md +72 -1
  43. package/templates/skills/business-analyse/steps/step-03c-compile.md +93 -7
  44. package/templates/skills/business-analyse/steps/step-03d-validate.md +34 -2
  45. package/templates/skills/business-analyse/steps/step-04b-analyze.md +40 -0
  46. package/templates/skills/controller/references/controller-code-templates.md +2 -2
  47. package/templates/skills/controller/templates.md +12 -12
  48. package/templates/skills/feature-full/steps/step-01-implementation.md +4 -4
  49. package/templates/skills/ralph-loop/references/category-rules.md +44 -2
  50. package/templates/skills/ralph-loop/references/compact-loop.md +37 -0
  51. package/templates/skills/ralph-loop/references/core-seed-data.md +51 -20
  52. package/templates/skills/review-code/references/owasp-api-top10.md +1 -1
@@ -17,7 +17,12 @@
17
17
  | Validate | MCP `validate_conventions` |
18
18
 
19
19
  **Rules:**
20
- - Inherit `BaseEntity`, implement `ITenantEntity` + `IAuditableEntity`
20
+ - Inherit `BaseEntity`, choose tenant interface based on data isolation requirements:
21
+ - **`ITenantEntity`** (strict mode, default): User can only access their tenant's data. Implement `Guid TenantId { get; set; }`. Service MUST filter by `_currentTenant.TenantId` with guard clause.
22
+ - **`IOptionalTenantEntity`** (optional mode): Cross-tenant data (shared lookup tables, public content). Implement `Guid? TenantId { get; set; }`. Service MAY accept null TenantId. EF global filter handles both shared (null) and tenant-scoped (TenantId == current) rows automatically.
23
+ - **`IScopedTenantEntity`** (scoped mode): Data scoped by Scope + TenantId combination. Validate both match current context in service layer.
24
+ - **No tenant interface** (none mode): Cross-tenant system data (no isolation). No TenantId property, no filtering needed.
25
+ - Also implement `IAuditableEntity` for CreatedBy/UpdatedBy tracking
21
26
  - See `references/smartstack-api.md` for exact BaseEntity API (Id, CreatedAt, UpdatedAt only)
22
27
  - No Code/IsDeleted/RowVersion in BaseEntity — add business properties yourself
23
28
  - Domain events for state changes
@@ -62,8 +67,12 @@
62
67
  | Validate | MCP `validate_conventions` |
63
68
 
64
69
  **Rules:**
65
- - **ALL services MUST inject `ICurrentUserService` + `ICurrentTenantService` and filter by `TenantId`** (see `smartstack-api.md` Service Pattern)
66
- - **ALL services MUST use guard clause:** `var tenantId = _currentTenant.TenantId ?? throw new TenantContextRequiredException();` (returns 400, NOT 401 — a missing tenant is a bad request, not an auth failure)
70
+ - **Tenant injection depends on entity tenant mode** (see entity rules below):
71
+ - **strict mode (default):** Inject `ICurrentTenantService` + guard clause: `var tenantId = _currentTenant.TenantId ?? throw new TenantContextRequiredException();` (mandatory, returns 400)
72
+ - **optional mode:** Inject `ICurrentTenantService`, no guard: `var tenantId = _currentTenant.TenantId;` (nullable). EF global filter handles shared+tenant data.
73
+ - **scoped mode:** Inject `ICurrentTenantService`, validate Scope + TenantId consistency. Tenant scope requires TenantId.
74
+ - **none mode:** No `ICurrentTenantService` injection needed (cross-tenant data, no filtering)
75
+ - **ALL services MUST inject `ICurrentUserService`** for audit trails
67
76
  - **ALL services MUST inject `ILogger<T>`** for production diagnostics
68
77
  - CQRS with MediatR
69
78
  - FluentValidation for all commands
@@ -272,7 +281,19 @@ const [loading, setLoading] = useState(true);
272
281
  ### Components & CSS
273
282
 
274
283
  **Components:** SmartTable, SmartFilter, EntityCard, SmartForm, StatCard (NEVER raw HTML)
275
- **CSS:** Variables only `bg-[var(--bg-card)]`, `text-[var(--text-primary)]`, `border-[var(--border-color)]`
284
+ **CSS:** Variables ONLY hardcoded Tailwind colors are **BLOCKING** in POST-CHECK 13:
285
+
286
+ | Instead of | Use |
287
+ |-----------|-----|
288
+ | `bg-white` | `bg-[var(--bg-card)]` |
289
+ | `bg-gray-50` | `bg-[var(--bg-primary)]` |
290
+ | `text-gray-900` | `text-[var(--text-primary)]` |
291
+ | `text-gray-500` | `text-[var(--text-secondary)]` |
292
+ | `border-gray-200` | `border-[var(--border-color)]` |
293
+ | `bg-blue-600` | `bg-[var(--color-accent-500)]` |
294
+ | `hover:bg-blue-700` | `hover:bg-[var(--color-accent-600)]` |
295
+ | `text-red-500` | `text-[var(--error-text)]` |
296
+
276
297
  **Loader:** `Loader2` from `lucide-react` for spinners, `PageLoader` for Suspense fallback
277
298
 
278
299
  ### Section Routes (when module has sections)
@@ -291,10 +312,10 @@ Section pages live in `src/pages/{ContextPascal}/{AppPascal}/{Module}/{Section}/
291
312
 
292
313
  ### FK Fields in Forms (CRITICAL)
293
314
 
294
- Any entity property that is a FK Guid (e.g., `EmployeeId`, `DepartmentId`) MUST use the `EntityLookup` component — NEVER a plain text input. Users cannot type GUIDs manually.
315
+ Any entity property that is a FK Guid (e.g., `EmployeeId`, `DepartmentId`) MUST use the `EntityLookup` component — NEVER a `<select>` dropdown, NEVER a `<input type="text">`. Users cannot type GUIDs manually, and `<select>` fails at scale (no search, loads all options).
295
316
 
296
317
  ```tsx
297
- // CORRECT — EntityLookup for FK field
318
+ // CORRECT — EntityLookup for FK field (ONLY acceptable pattern)
298
319
  <EntityLookup
299
320
  apiEndpoint="/api/business/human-resources/employees"
300
321
  value={formData.employeeId}
@@ -306,6 +327,12 @@ Any entity property that is a FK Guid (e.g., `EmployeeId`, `DepartmentId`) MUST
306
327
 
307
328
  // WRONG — plain text input for FK GUID
308
329
  <input type="text" value={formData.employeeId} placeholder="Enter employee ID" />
330
+
331
+ // WRONG — <select> dropdown for FK field (even with API-loaded options)
332
+ <select value={formData.departmentId} onChange={(e) => setFormData({...formData, departmentId: e.target.value})}>
333
+ <option value="">Select...</option>
334
+ {departments.map(d => <option key={d.id} value={d.id}>{d.name}</option>)}
335
+ </select>
309
336
  ```
310
337
 
311
338
  **Backend requirement:** Each target entity's GetAll endpoint MUST accept `?search=` parameter. See `smartstack-api.md` Service Pattern.
@@ -317,6 +344,7 @@ See `references/smartstack-frontend.md` section 6 for the full `EntityLookup` co
317
344
  - `import axios` → use `@/services/api/apiClient`
318
345
  - `<table>` → use SmartTable
319
346
  - `<input type="text">` for FK Guid fields → use `EntityLookup`
347
+ - `<select>` for FK Guid fields → use `EntityLookup` (even with API-loaded options)
320
348
  - Placeholder "Enter ID" or "Enter GUID" → use `EntityLookup`
321
349
  - Hardcoded Tailwind colors (`bg-white`, `text-gray-900`) → use CSS variables
322
350
  - Static page imports in route files → use `React.lazy()`
@@ -346,7 +374,26 @@ t('{module}:actions.create', 'Create entity') // ALWAYS with namespace prefix
346
374
 
347
375
  ---
348
376
 
349
- ## Layer 3Tests (sequential, if -t)
377
+ ## Layer 2bDocumentation (after frontend pages exist)
378
+
379
+ > **After frontend pages are created, generate module documentation.**
380
+
381
+ | Action | Tool |
382
+ |--------|------|
383
+ | Generate doc-data.ts + page wrapper | `/documentation` skill (type: user) |
384
+ | Verify DocToggleButton in pages | POST-CHECK 29 |
385
+
386
+ **Output files:**
387
+ - `src/pages/docs/business/{app}/{module}/doc-data.ts` — data-driven documentation
388
+ - `src/pages/docs/business/{app}/{module}/index.tsx` — page wrapper using `DocRenderer`
389
+ - `src/i18n/locales/fr/docs-{app}-{module}.json` — French doc translations
390
+
391
+ **DocToggleButton (MANDATORY):** Every list/detail page must include `DocToggleButton` in its header.
392
+ See `references/smartstack-frontend.md` section 7 for the component pattern.
393
+
394
+ ---
395
+
396
+ ## Layer 3 — Tests (sequential)
350
397
 
351
398
  | Action | Tool |
352
399
  |--------|------|
@@ -28,7 +28,7 @@ Extract flags from the raw input:
28
28
  ```
29
29
  Input: "{raw_input}"
30
30
 
31
- Flags to detect: -a, -x, -s, -t, -e, -r, -pr
31
+ Flags to detect: -a, -x, -s, -e, -r, -pr
32
32
  Remaining text after flag removal = {task_description}
33
33
  ```
34
34
 
@@ -38,7 +38,6 @@ Remaining text after flag removal = {task_description}
38
38
  auto_mode: false
39
39
  examine_mode: false
40
40
  save_mode: false
41
- test_mode: false
42
41
  economy_mode: false
43
42
  pr_mode: false
44
43
  resume_mode: false
@@ -111,8 +111,51 @@ For each entity found (or to be created), identify FK relationships:
111
111
  - Record: `{ entity, fkProperty, targetEntity, isRequired }`
112
112
 
113
113
  **Why:** FK fields drive two critical requirements:
114
- 1. **Frontend:** Each FK field MUST use `EntityLookup` (NEVER plain text for GUIDs)
115
- 2. **Backend:** Each target entity's GetAll MUST support `?search=`
114
+ 1. **Frontend:** Each FK field MUST use `<EntityLookup />` (NEVER `<input>`, NEVER `<select>` — even with API-loaded options)
115
+ 2. **Backend:** Each target entity's GetAll MUST support `?search=` parameter + return `PaginatedResult<T>`
116
+
117
+ ---
118
+
119
+ ## 4a. Tenant Mode Decision
120
+
121
+ For each entity found (or to be created), determine the `tenantMode`:
122
+
123
+ - **`strict`** (default) — Data belongs to a specific tenant. Examples: Employee, Order, Invoice, CustomerInteraction
124
+ - **`optional`** — Data can be shared across tenants OR tenant-specific. Examples: Department, Currency, JobTitle, Language
125
+ - **`scoped`** — Data has explicit visibility scope controlled by workflow/feature rules. Examples: Settings, Workflow, EmailTemplate, ApprovalConfig
126
+ - **`none`** — Platform-wide data (never tenant-filtered). Examples: Navigation, Permission, User, SystemConfiguration
127
+
128
+ **Why:** Tenant mode drives EF query filters, seed data generation, and API access control. Must be decided before planning.
129
+
130
+ **Reference:** See `references/smartstack-api.md` for TenantId handling patterns and `smartstack-layers.md` for seed data strategies per tenant mode.
131
+
132
+ ---
133
+
134
+ ## 4b. Code Pattern Detection
135
+
136
+ For each entity found (or to be created), identify code generation needs:
137
+
138
+ ```
139
+ IF feature.json exists AND entity has codePattern:
140
+ → Use codePattern config from feature.json (strategy, prefix, digits, etc.)
141
+ → Record in analysis: entity has auto-generated code
142
+
143
+ ELSE IF feature.json exists BUT entity has NO codePattern:
144
+ → Record: entity needs codePattern decision in step-02
145
+ → Apply heuristic default based on entity name:
146
+ Invoice/Order/Receipt → timestamp-daily
147
+ Ticket/Incident → timestamp-minute
148
+ Contract/Policy → year-sequential
149
+ Reference/Category → uuid-short
150
+ Employee/Customer/Project → sequential
151
+
152
+ ELSE (no feature.json):
153
+ → Propose codePattern during step-02 planning based on task description
154
+ ```
155
+
156
+ **Why:** Code generation strategy drives CreateDto structure (Code field removed when auto-generated), service injection (ICodeGenerator<T>), and DI registration. Must be decided before planning.
157
+
158
+ **Reference:** See `references/code-generation.md` for strategy table, volume-to-digits calculation, and backend patterns.
116
159
 
117
160
  ---
118
161
 
@@ -32,6 +32,17 @@ For each element identified in step-01 (create or modify), assign to a SmartStac
32
32
  | 2 | I18n (translations) | Parallel |
33
33
  | 3 | Tests | Sequential |
34
34
 
35
+ **Entity Definition Template:** Each entity in the plan MUST include:
36
+ ```
37
+ Entity: {EntityName}
38
+ - tenantMode: strict | optional | scoped | none
39
+ - codePattern: auto-generated strategy (if applicable)
40
+ - fkFields: [{field, targetEntity}] (if applicable)
41
+ - acceptance criteria: [AC1, AC2, ...]
42
+ ```
43
+
44
+ The `tenantMode` decision (from step-01, section 4a) drives EF query filters, seed data approach, and API authorization. See `smartstack-layers.md` for tenant mode seed data strategies.
45
+
35
46
  ---
36
47
 
37
48
  ## 2. Assign Skill/MCP per File
@@ -56,6 +67,7 @@ For EACH file in the plan, specify HOW it will be created/modified:
56
67
  | 6 | Api/Controllers/.../MyController.cs | create | /controller skill |
57
68
  | 7 | Seeding/Data/NavigationApplicationSeedData.cs | create | ref smartstack-layers.md (once per app) |
58
69
  | 7b | Seeding/Data/ApplicationRolesSeedData.cs | create | ref smartstack-layers.md (once per app) |
70
+ | 7c | Infrastructure/Services/CodeGeneration/ | create | ref code-generation.md (ICodeGenerator<T> + DI, per entity with codePattern != manual) |
59
71
  | 8 | Seeding/Data/.../NavigationModuleSeedData.cs | create | ref smartstack-layers.md |
60
72
  | 8b | Application/Authorization/Permissions.cs | create | MCP generate_permissions → static constants |
61
73
  | 9 | Seeding/Data/.../PermissionsSeedData.cs | create | MCP generate_permissions |
@@ -76,7 +88,14 @@ For EACH file in the plan, specify HOW it will be created/modified:
76
88
 
77
89
  **FK Field Guidance:** If step-01 identified `fkFields[]`, every Create/Edit page MUST use `EntityLookup` for those fields (see `smartstack-frontend.md` section 6). The corresponding backend GetAll endpoints (Layer 1) MUST support `?search=` parameter.
78
90
 
79
- ### Layer 3Tests (sequential, if -t)
91
+ ### Layer 2bDocumentation (after frontend pages exist)
92
+
93
+ | # | File | Action | Tool |
94
+ |---|------|--------|------|
95
+ | 14b | src/pages/docs/business/{app}/{module}/doc-data.ts | create | /documentation skill |
96
+ | 14c | src/pages/docs/business/{app}/{module}/index.tsx | create | /documentation skill |
97
+
98
+ ### Layer 3 — Tests (sequential)
80
99
 
81
100
  | # | File | Action | Tool |
82
101
  |---|------|--------|------|
@@ -114,6 +133,8 @@ Verify the plan respects dependencies:
114
133
  ```
115
134
  - Migration AFTER EF configs (always)
116
135
  - Application services AFTER domain entities (always)
136
+ - Code generator service AFTER entity + EF config (needs DbSet for sequence query)
137
+ - CreateDto adjustments AFTER code pattern decision (remove Code property if auto-generated)
117
138
  - Controllers AFTER application services (always)
118
139
  - Frontend AFTER API controllers (API contract needed)
119
140
  - Seed data AFTER navigation module exists
@@ -130,7 +151,7 @@ feat({module}): [domain+infra] {description}
130
151
  feat({module}): [app+api] {description}
131
152
  feat({module}): [frontend] {description}
132
153
  feat({module}): [seed] {description}
133
- feat({module}): [tests] {description} # if -t
154
+ feat({module}): [tests] {description}
134
155
  ```
135
156
 
136
157
  ---
@@ -69,12 +69,32 @@ dotnet build
69
69
 
70
70
  Execute each item from the plan sequentially using skills and MCP.
71
71
 
72
+ ### Code Generation (if entities have codePattern != "manual")
73
+
74
+ For each entity with auto-generated code pattern (from feature.json or step-02 decisions):
75
+
76
+ ```
77
+ 1. Create CodePatternConfig for the entity (strategy, prefix, digits from codePattern)
78
+ 2. Register ICodeGenerator<TEntity> in DependencyInjection.cs (Infrastructure layer)
79
+ → See references/code-generation.md for DI registration pattern
80
+ 3. Update CreateDto: REMOVE Code property (auto-generated, not user-provided)
81
+ 4. Update CreateDtoValidator: REMOVE Code regex rule (not in DTO anymore)
82
+ 5. Update service CreateAsync: inject ICodeGenerator<TEntity>, call NextCodeAsync()
83
+ → Code is auto-generated BEFORE entity creation
84
+ → See references/code-generation.md for service integration pattern
85
+ 6. Keep Code in ResponseDto (returned to frontend after creation)
86
+ 7. Keep Code in UpdateDto ONLY if code is mutable (rare — discuss with user)
87
+ ```
88
+
89
+ **CRITICAL:** If `codePattern.strategy == "manual"` (or no codePattern), keep the current behavior:
90
+ Code stays in CreateDto, user provides it, validator has regex rule.
91
+
72
92
  **For frontend tasks (economy_mode):** Follow the same rules as exec-frontend above:
73
93
  - `MCP scaffold_api_client` → API client + types + React Query hook
74
94
  - `MCP scaffold_routes` with `outputFormat: 'clientRoutes'` for lazy imports
75
95
  - Pages: use `/ui-components` skill — MANDATORY for entity lists, grids, tables, dashboards
76
96
  - **Form pages: Create `EntityCreatePage.tsx` (route: `/create`) and `EntityEditPage.tsx` (route: `/:id/edit`)**
77
- - **FK FIELDS (CRITICAL):** Any Guid FK property (e.g., EmployeeId, DepartmentId) MUST use `EntityLookup` component — NEVER a plain text input. See `smartstack-frontend.md` section 6.
97
+ - **FK FIELDS (CRITICAL):** Any Guid FK property (e.g., EmployeeId, DepartmentId) MUST use `EntityLookup` component — NEVER a `<select>` dropdown, NEVER a `<input type="text">`. A `<select>` loaded from API state is NOT a substitute for EntityLookup. See `smartstack-frontend.md` section 6.
78
98
  - **ZERO modals/popups/drawers for forms — ALL forms are full pages with their own URL**
79
99
  - **Form tests: Generate `EntityCreatePage.test.tsx` and `EntityEditPage.test.tsx` (co-located)**
80
100
  - **SECTION PERMISSIONS:** After calling `MCP generate_permissions` for the module navRoute (3 segments: `{context}.{app}.{module}`), also call it for EACH section navRoute (4 segments: `{context}.{app}.{module}.{section}`)
@@ -127,9 +147,11 @@ Spawn 2 teammates (Opus, full tools):
127
147
  → Back button with navigate(-1) on every form page
128
148
  → See smartstack-frontend.md section 3b for templates
129
149
  - **FK FIELDS (CRITICAL):** Foreign key Guid fields (e.g., EmployeeId) MUST use EntityLookup:
130
- → NEVER render FK fields as plain text inputs — users cannot type GUIDs
131
- Use EntityLookup from @/components/ui/EntityLookup for searchable selection
150
+ → NEVER render FK fields as `<input>` — users cannot type GUIDs
151
+ NEVER render FK fields as `<select>` — even with API-loaded options, `<select>` is NOT acceptable
152
+ → ONLY use `<EntityLookup />` from @/components/ui/EntityLookup for searchable selection
132
153
  → Each FK field needs: apiEndpoint, mapOption (display name), search support on backend
154
+ → FORBIDDEN: `<select value={formData.departmentId}>`, `<option value={dept.id}>`, `e.target.value` for FK fields
133
155
  → See smartstack-frontend.md section 6 for the full EntityLookup pattern
134
156
  - **FORM TESTS (MANDATORY):**
135
157
  → EntityCreatePage.test.tsx (co-located next to page)
@@ -173,6 +195,28 @@ shutdown_request → shutdown_response → TeamDelete("apex-exec")
173
195
 
174
196
  ---
175
197
 
198
+ ## Layer 2b — Documentation (after frontend pages exist)
199
+
200
+ > **After frontend pages are created, generate module documentation via `/documentation` skill.**
201
+
202
+ ```
203
+ Invoke /documentation {module_code} --type user
204
+
205
+ This generates:
206
+ - src/pages/docs/business/{app}/{module}/doc-data.ts (data file)
207
+ - src/pages/docs/business/{app}/{module}/index.tsx (page wrapper)
208
+ - src/i18n/locales/fr/docs-{app}-{module}.json (French doc translations)
209
+ - Updates App.tsx routing for doc page
210
+ - Updates docs-manifest.json
211
+ ```
212
+
213
+ **Verify DocToggleButton presence in list/detail pages:**
214
+ - Every `*ListPage.tsx` and `*DetailPage.tsx` MUST import and render `DocToggleButton` in their header
215
+ - Import: `import { DocToggleButton } from '@/components/docs/DocToggleButton';`
216
+ - Placement: inside the header actions area (see `smartstack-frontend.md` section 7)
217
+
218
+ ---
219
+
176
220
  ## Layer 2 — Final Seed Data + Validation (sequential)
177
221
 
178
222
  After Layer 1 completes:
@@ -192,14 +236,160 @@ After Layer 1 completes:
192
236
 
193
237
  ---
194
238
 
239
+ ## FRONTEND COMPLIANCE GATE (MANDATORY before commit)
240
+
241
+ > **BLOCKING:** Do NOT commit frontend changes until ALL checks pass.
242
+ > These issues are the most common failures in generated code — verify EVERY item.
243
+
244
+ **Run these checks on ALL generated/modified `.tsx` files BEFORE creating the frontend commit:**
245
+
246
+ ### Gate 1: CSS Variables (Theme System)
247
+
248
+ ```bash
249
+ # Check for hardcoded Tailwind colors — MUST use CSS variables
250
+ ALL_PAGES=$(find src/pages/ src/components/ -name "*.tsx" 2>/dev/null | grep -v node_modules | grep -v "\.test\.")
251
+ if [ -n "$ALL_PAGES" ]; then
252
+ HARDCODED=$(grep -Pn '(bg|text|border)-(?!\[)(red|blue|green|gray|white|black|slate|zinc|neutral|stone)-' $ALL_PAGES 2>/dev/null)
253
+ if [ -n "$HARDCODED" ]; then
254
+ echo "FAIL: Hardcoded Tailwind colors found — must use CSS variables"
255
+ echo "$HARDCODED"
256
+ else
257
+ echo "PASS: CSS variables"
258
+ fi
259
+ fi
260
+ ```
261
+
262
+ **If hardcoded colors found, replace BEFORE committing:**
263
+ - `bg-white` → `bg-[var(--bg-card)]`
264
+ - `bg-gray-50` → `bg-[var(--bg-primary)]`
265
+ - `text-gray-900` → `text-[var(--text-primary)]`
266
+ - `text-gray-500/600` → `text-[var(--text-secondary)]`
267
+ - `border-gray-200` → `border-[var(--border-color)]`
268
+ - `bg-blue-600` / `text-blue-600` → `bg-[var(--color-accent-500)]` / `text-[var(--color-accent-500)]`
269
+ - `hover:bg-blue-700` → `hover:bg-[var(--color-accent-600)]`
270
+ - `text-red-500` → `text-[var(--error-text)]`
271
+ - `bg-green-500` → `bg-[var(--success-bg)]`
272
+
273
+ ### Gate 2: Forms as Pages (ZERO Modals/Drawers/Slide-overs)
274
+
275
+ ```bash
276
+ # Check for modal/dialog/drawer/slide-over imports and inline form patterns — FORBIDDEN
277
+ PAGE_FILES=$(find src/pages/ -name "*.tsx" 2>/dev/null)
278
+ if [ -n "$PAGE_FILES" ]; then
279
+ FAIL=false
280
+
281
+ # 2a. Component imports
282
+ MODAL_IMPORTS=$(grep -Pn "import.*(?:Modal|Dialog|Drawer|Popup|Sheet|SlideOver|Overlay)" $PAGE_FILES 2>/dev/null)
283
+ if [ -n "$MODAL_IMPORTS" ]; then
284
+ echo "FAIL: Modal/Dialog/Drawer component imports — forms MUST be full pages"
285
+ echo "$MODAL_IMPORTS"
286
+ FAIL=true
287
+ fi
288
+
289
+ # 2b. State variables for inline forms (catches drawers/slide-overs without imports)
290
+ MODAL_STATE=$(grep -Pn "useState.*(?:isOpen|showModal|showDialog|showCreate|showEdit|showForm|isCreating|isEditing|showDrawer|showPanel|showSlideOver|selectedEntity|editingEntity)" $PAGE_FILES 2>/dev/null)
291
+ if [ -n "$MODAL_STATE" ]; then
292
+ echo "FAIL: Inline form state detected — forms MUST be separate page components with own routes"
293
+ echo "$MODAL_STATE"
294
+ FAIL=true
295
+ fi
296
+
297
+ if [ "$FAIL" = true ]; then
298
+ echo ""
299
+ echo "Fix: Create EntityCreatePage.tsx (route: /create) and EntityEditPage.tsx (route: /:id/edit)"
300
+ echo "See smartstack-frontend.md section 3b"
301
+ else
302
+ echo "PASS: No modals/drawers"
303
+ fi
304
+ fi
305
+ ```
306
+
307
+ **If modals/drawers found:** Replace with separate `EntityCreatePage.tsx` (route: `/{module}/create`) and `EntityEditPage.tsx` (route: `/{module}/:id/edit`). See `smartstack-frontend.md` section 3b.
308
+
309
+ ### Gate 3: I18n File Structure
310
+
311
+ ```bash
312
+ # Verify translation files exist as separate JSON per language
313
+ if [ ! -d "src/i18n/locales" ]; then
314
+ echo "FAIL: Missing src/i18n/locales/ directory — create it with 4 languages"
315
+ else
316
+ for LANG in fr en it de; do
317
+ JSON_FILES=$(find "src/i18n/locales/$LANG" -name "*.json" 2>/dev/null | wc -l)
318
+ if [ "$JSON_FILES" -eq 0 ]; then
319
+ echo "FAIL: No JSON files in src/i18n/locales/$LANG/"
320
+ else
321
+ echo "PASS: $LANG ($JSON_FILES files)"
322
+ fi
323
+ done
324
+ fi
325
+ ```
326
+
327
+ **If i18n structure wrong:** Create `src/i18n/locales/{fr,en,it,de}/{module}.json` following the template in `smartstack-frontend.md` section 2. NEVER embed translations in a single `.ts` file.
328
+
329
+ ### Gate 4: Lazy Loading
330
+
331
+ ```bash
332
+ # Check for static page imports in route/App files
333
+ APP_TSX=$(find src/ -name "App.tsx" -not -path "*/node_modules/*" 2>/dev/null | head -1)
334
+ ROUTE_FILES=$(find src/routes/ -name "*.tsx" -o -name "*.ts" 2>/dev/null)
335
+ if [ -n "$APP_TSX" ]; then
336
+ STATIC_IMPORTS=$(grep -Pn "^import .+ from '@/pages/" "$APP_TSX" $ROUTE_FILES 2>/dev/null)
337
+ if [ -n "$STATIC_IMPORTS" ]; then
338
+ echo "FAIL: Static page imports in App.tsx/routes — MUST use React.lazy()"
339
+ echo "$STATIC_IMPORTS"
340
+ else
341
+ echo "PASS: Lazy loading"
342
+ fi
343
+ fi
344
+ ```
345
+
346
+ ### Gate 5: useTranslation in Pages
347
+
348
+ ```bash
349
+ # Verify pages use i18n
350
+ PAGE_FILES=$(find src/pages/ -name "*.tsx" 2>/dev/null | grep -v "\.test\." | grep -v node_modules)
351
+ if [ -n "$PAGE_FILES" ]; then
352
+ TOTAL=$(echo "$PAGE_FILES" | wc -l)
353
+ WITH_I18N=$(grep -l "useTranslation" $PAGE_FILES 2>/dev/null | wc -l)
354
+ if [ "$WITH_I18N" -eq 0 ]; then
355
+ echo "FAIL: No pages use useTranslation — all text must be translated"
356
+ else
357
+ echo "PASS: $WITH_I18N/$TOTAL pages use useTranslation"
358
+ fi
359
+ fi
360
+ ```
361
+
362
+ > **ALL 5 gates MUST pass before creating the frontend commit.** If ANY gate fails, fix the issues first.
363
+
364
+ ### Explicit I18n File Creation
365
+
366
+ When creating i18n files, generate EXACTLY this structure:
367
+
368
+ ```
369
+ src/i18n/locales/
370
+ ├── fr/{module}.json ← French (primary)
371
+ ├── en/{module}.json ← English
372
+ ├── it/{module}.json ← Italian
373
+ └── de/{module}.json ← German
374
+ ```
375
+
376
+ Each file MUST contain these keys: `title`, `description`, `actions`, `labels`, `columns`, `form`, `errors`, `validation`, `messages`, `empty`. See `smartstack-frontend.md` section 2 for the complete JSON template.
377
+
378
+ **When delegating to `/ui-components`:** ALWAYS include these explicit instructions in the delegation context:
379
+ - "CSS: Use CSS variables ONLY — `bg-[var(--bg-card)]`, `text-[var(--text-primary)]`. NEVER use hardcoded Tailwind colors like `bg-white` or `text-gray-900`."
380
+ - "Forms: Create/Edit forms are FULL PAGES with own routes (e.g., `/create`, `/:id/edit`). NEVER use modals/dialogs."
381
+ - "I18n: ALL text must use `t('namespace:key', 'Fallback')`. Generate JSON files in `src/i18n/locales/`."
382
+
383
+ ---
384
+
195
385
  ## Commits Per Layer
196
386
 
197
- After each layer completes and builds pass:
387
+ After each layer completes, gates pass, and builds pass:
198
388
 
199
389
  ```
200
390
  Layer 0: feat({module}): [domain+infra] {short description}
201
391
  Layer 1: feat({module}): [app+api] {short description}
202
- Layer 1: feat({module}): [frontend] {short description} # if applicable
392
+ Layer 1: feat({module}): [frontend] {short description} # if applicable — AFTER all 5 gates pass
203
393
  Layer 2: feat({module}): [seed] {short description} # if applicable
204
394
  ```
205
395
 
@@ -178,8 +178,8 @@ AC2: {criterion} → PASS / FAIL (evidence: {file:line or test})
178
178
  | Frontend | routes, lazy loading, forms as pages, i18n (4 langs + keys) | PASS / N/A |
179
179
  | Security | TenantId filter, RequirePermission, no Guid.Empty, no !.Value | PASS / N/A |
180
180
  | Seed data | completeness, deterministic GUIDs, no ContextId/RoleId constants | PASS / N/A |
181
- | Code quality | PaginatedResult, EntityLookup, CSS vars, search param | PASS / N/A |
182
- | POST-CHECKs | 21 checks from references/post-checks.md | PASS / N/A |
181
+ | Code quality | PaginatedResult, EntityLookup (no FK select/input), CSS vars, search param | PASS / N/A |
182
+ | POST-CHECKs | 30 checks from references/post-checks.md | PASS / N/A |
183
183
  | Acceptance criteria | AC1..ACn | {X}/{Y} PASS |
184
184
  ```
185
185
 
@@ -191,10 +191,23 @@ Write to `{output_dir}/04-examine.md` with validation results.
191
191
 
192
192
  ---
193
193
 
194
- ## 10. Route to Next Step
194
+ ## 10. Route to Next Step — TESTS ARE MANDATORY
195
+
196
+ > **CRITICAL — DO NOT STOP HERE.**
197
+ > Step-04 (eXamine) is NOT the final step. Tests MUST be scaffolded and run.
198
+ > Completing APEX without tests violates the methodology — skip is FORBIDDEN.
195
199
 
196
200
  ```
197
- examine_mode → step-05-deep-review | test_mode → step-07-tests | pr_mode → create PR | else → final summary
201
+ IF examine_mode (-x flag):
202
+ → Load steps/step-05-deep-review.md (adversarial review)
203
+ → Then step-06 (resolve) if BLOCKING findings
204
+ → Then step-07 (tests) — ALWAYS
205
+
206
+ ELSE:
207
+ → Load steps/step-07-tests.md — IMMEDIATELY after eXamine completes
198
208
  ```
199
209
 
200
- **FINAL SUMMARY (if no more steps):** task, context, files created/modified, validation status, commits count, next steps.
210
+ **BLOCKING RULE:** The APEX workflow is NOT complete until steps 07-08 execute.
211
+ The success criteria require: "Tests: 100% pass, >= 80% coverage" — this is impossible without step-07.
212
+
213
+ **NEXT ACTION:** Load `steps/step-07-tests.md` now.
@@ -61,9 +61,10 @@ For each changed file, check:
61
61
  - [ ] Correct Layout wrapper per context
62
62
 
63
63
  **FK Fields & Forms:**
64
- - [ ] FK Guid fields use `EntityLookup` component (NEVER plain text `<input>`)
65
- - [ ] No placeholder text asking user to "Enter ID" or "Enter GUID"
66
- - [ ] Create/Edit forms are full pages with own routes (ZERO modals/dialogs)
64
+ - [ ] FK Guid fields use `EntityLookup` component (NEVER `<input>`, NEVER `<select>`)
65
+ - [ ] No `<select>` with `<option>` elements for FK fields (even API-loaded options)
66
+ - [ ] No placeholder text asking user to "Enter ID", "Enter GUID", or "Select {Entity}..."
67
+ - [ ] No inline forms in drawers/slide-overs — Create/Edit forms are full pages with own routes (ZERO modals/dialogs/drawers)
67
68
  - [ ] Backend GetAll endpoints support `?search=` param for EntityLookup
68
69
  - [ ] Each EntityLookup has `apiEndpoint`, `mapOption`, `label` props
69
70
 
@@ -118,14 +119,11 @@ Write to `{output_dir}/05-deep-review.md` with all findings.
118
119
 
119
120
  ```
120
121
  IF BLOCKING findings exist:
121
- → Load steps/step-06-resolve.md
122
-
123
- ELSE IF test_mode = true:
124
- → Load steps/step-07-tests.md
125
-
126
- ELSE IF pr_mode = true:
127
- → Create PR and show final summary
122
+ → Load steps/step-06-resolve.md (fix BLOCKING findings first)
123
+ → Then step-07-tests.md (tests are MANDATORY)
128
124
 
129
125
  ELSE:
130
- Show final summary and exit
126
+ Load steps/step-07-tests.md IMMEDIATELY
131
127
  ```
128
+
129
+ > **REMINDER:** Tests are MANDATORY. Do NOT stop after Deep Review — proceed to step-07.
@@ -92,14 +92,10 @@ Write to `{output_dir}/06-resolve.md` with resolution log.
92
92
 
93
93
  ```
94
94
  IF remaining BLOCKING > 0:
95
- → Loop: fix remaining, re-validate
95
+ → Loop: fix remaining, re-validate (max 3 iterations)
96
+ → If stuck, ask user before continuing
96
97
 
97
- IF test_mode = true:
98
- → Load steps/step-07-tests.md
99
-
100
- ELSE IF pr_mode = true:
101
- → Create PR and show final summary
102
-
103
- ELSE:
104
- → Show final summary and exit
98
+ Load steps/step-07-tests.md — MANDATORY, do NOT skip
105
99
  ```
100
+
101
+ > **REMINDER:** Tests are MANDATORY. After resolving all findings, proceed to step-07 immediately.
@@ -6,12 +6,77 @@ prev_step: steps/step-06-resolve.md
6
6
  next_step: steps/step-08-run-tests.md
7
7
  ---
8
8
 
9
- # Step 7: Tests (if -t)
9
+ # Step 7: Tests
10
+
11
+ > **MANDATORY STEP — This is NOT optional.** APEX requires tests for completion.
12
+ > If you reached this step, you MUST scaffold and run tests before finishing.
10
13
 
11
14
  **Goal:** Scaffold comprehensive tests using MCP tools. Target: >= 80% coverage.
12
15
 
13
16
  ---
14
17
 
18
+ ## 0. Ensure Frontend Test Tooling Exists (if frontend was generated)
19
+
20
+ > **Before scaffolding frontend tests, the test infrastructure must be in place.**
21
+
22
+ ```bash
23
+ # Check if Vitest is installed
24
+ WEB_DIR=$(find . -name "package.json" -not -path "*/node_modules/*" -exec dirname {} \; 2>/dev/null | head -1)
25
+ if [ -n "$WEB_DIR" ]; then
26
+ cd "$WEB_DIR"
27
+
28
+ # Install test dependencies if missing
29
+ if ! grep -q '"vitest"' package.json 2>/dev/null; then
30
+ npm install -D vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom @types/testing-library__jest-dom
31
+ fi
32
+
33
+ # Create vitest.config.ts if missing
34
+ if [ ! -f "vitest.config.ts" ]; then
35
+ cat > vitest.config.ts << 'VITEST_EOF'
36
+ import { defineConfig } from 'vitest/config';
37
+ import react from '@vitejs/plugin-react';
38
+ import path from 'path';
39
+
40
+ export default defineConfig({
41
+ plugins: [react()],
42
+ test: {
43
+ globals: true,
44
+ environment: 'jsdom',
45
+ setupFiles: ['./src/test/setup.ts'],
46
+ css: true,
47
+ include: ['src/**/*.test.{ts,tsx}'],
48
+ },
49
+ resolve: {
50
+ alias: {
51
+ '@': path.resolve(__dirname, './src'),
52
+ },
53
+ },
54
+ });
55
+ VITEST_EOF
56
+ fi
57
+
58
+ # Create test setup file if missing
59
+ mkdir -p src/test
60
+ if [ ! -f "src/test/setup.ts" ]; then
61
+ cat > src/test/setup.ts << 'SETUP_EOF'
62
+ import '@testing-library/jest-dom';
63
+ SETUP_EOF
64
+ fi
65
+
66
+ # Add test script to package.json if missing
67
+ if ! grep -q '"test"' package.json 2>/dev/null; then
68
+ # Use npm pkg set for safe JSON manipulation
69
+ npm pkg set scripts.test="vitest run"
70
+ npm pkg set scripts.test:watch="vitest"
71
+ npm pkg set scripts.test:coverage="vitest run --coverage"
72
+ fi
73
+
74
+ cd -
75
+ fi
76
+ ```
77
+
78
+ ---
79
+
15
80
  ## 1. Ensure Test Projects Exist
16
81
 
17
82
  ### 1a. Unit Test Project