@atlashub/smartstack-cli 3.25.0 → 3.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mcp-entry.mjs +11 -5
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/skills/apex/SKILL.md +26 -5
- package/templates/skills/apex/_shared.md +3 -3
- package/templates/skills/apex/references/agent-teams-protocol.md +8 -8
- package/templates/skills/apex/references/challenge-questions.md +165 -0
- package/templates/skills/apex/{steps/step-04-validate.md → references/post-checks.md} +82 -214
- package/templates/skills/apex/references/smartstack-api.md +91 -14
- package/templates/skills/apex/references/smartstack-layers.md +16 -4
- package/templates/skills/apex/steps/step-00-init.md +84 -56
- package/templates/skills/apex/steps/step-01-analyze.md +73 -87
- package/templates/skills/apex/steps/step-03-execute.md +2 -2
- package/templates/skills/apex/steps/step-04-examine.md +198 -0
- package/templates/skills/apex/steps/{step-05-examine.md → step-05-deep-review.md} +6 -6
- package/templates/skills/apex/steps/step-06-resolve.md +2 -2
- package/templates/skills/business-analyse/SKILL.md +28 -0
- package/templates/skills/business-analyse/references/agent-module-prompt.md +255 -0
- package/templates/skills/business-analyse/references/agent-pooling-best-practices.md +26 -10
- package/templates/skills/business-analyse/references/team-orchestration.md +437 -0
- package/templates/skills/business-analyse/steps/step-02-decomposition.md +31 -4
- package/templates/skills/business-analyse/steps/step-03a1-setup.md +21 -0
- package/templates/skills/business-analyse/steps/step-03d-validate.md +84 -0
- package/templates/skills/ralph-loop/references/core-seed-data.md +45 -10
- package/templates/skills/ralph-loop/steps/step-02-execute.md +47 -0
package/package.json
CHANGED
|
@@ -33,7 +33,7 @@ Execute incremental SmartStack development using the APEX methodology. This skil
|
|
|
33
33
|
| Flag | Description |
|
|
34
34
|
|------|-------------|
|
|
35
35
|
| `-a` | Auto mode: skip confirmations |
|
|
36
|
-
| `-x` |
|
|
36
|
+
| `-x` | Deep review: adversarial code review (beyond step-04 automated checks) |
|
|
37
37
|
| `-s` | Save mode: output to `.claude/output/apex/` |
|
|
38
38
|
| `-t` | Test mode: scaffold + run tests via MCP |
|
|
39
39
|
| `-e` | Economy mode: no subagents |
|
|
@@ -57,11 +57,17 @@ Execute incremental SmartStack development using the APEX methodology. This skil
|
|
|
57
57
|
| `{context_code}` | string | "business", "platform", "personal" |
|
|
58
58
|
| `{app_name}` | string | Application name |
|
|
59
59
|
| `{module_code}` | string | Module code |
|
|
60
|
-
| `{sections}` |
|
|
60
|
+
| `{sections}` | object[] | Sections (MANDATORY, min 1) with code/labels/icon/displayOrder |
|
|
61
|
+
| `{entities}` | string[] | Main entities to manage (from need-challenge) |
|
|
62
|
+
| `{module_complexity}` | string | "simple-crud", "crud-rules", "crud-workflow", "complex" |
|
|
63
|
+
| `{has_dependencies}` | string | "none", "references", "unknown" |
|
|
64
|
+
| `{key_properties}` | string[] | Key business properties mentioned by user |
|
|
61
65
|
| `{prd_path}` | string? | `.ralph/prd-{module}.json` if exists |
|
|
62
66
|
| `{feature_path}` | string? | `docs/business/.../feature.json` if exists |
|
|
63
67
|
| `{needs_seed_data}` | boolean | Seed data creation required |
|
|
64
68
|
| `{needs_migration}` | boolean | EF Core migration required |
|
|
69
|
+
| `{needs_workflow}` | boolean | Workflow integration required |
|
|
70
|
+
| `{needs_notification}` | boolean | Notification integration required |
|
|
65
71
|
</state_variables>
|
|
66
72
|
|
|
67
73
|
<entry_point>
|
|
@@ -75,17 +81,32 @@ Execute incremental SmartStack development using the APEX methodology. This skil
|
|
|
75
81
|
|
|
76
82
|
| Step | File | Model | Purpose |
|
|
77
83
|
|------|------|-------|---------|
|
|
78
|
-
| 00 | `steps/step-00-init.md` | Sonnet | Parse flags, detect
|
|
84
|
+
| 00 | `steps/step-00-init.md` | Sonnet | Parse flags, detect context, verify MCP, define hierarchy (5 levels), challenge need |
|
|
79
85
|
| 01 | `steps/step-01-analyze.md` | Opus | Explore existing code (Agent Teams or direct) |
|
|
80
86
|
| 02 | `steps/step-02-plan.md` | Opus | Layer-by-layer plan with skill/MCP mapping |
|
|
81
87
|
| 03 | `steps/step-03-execute.md` | Opus | Orchestrate execution via skills and MCP |
|
|
82
|
-
| 04 | `steps/step-04-
|
|
83
|
-
| 05 | `steps/step-05-
|
|
88
|
+
| 04 | `steps/step-04-examine.md` | Opus | eXamine: MCP validation, build, 21 POST-CHECKs, acceptance criteria |
|
|
89
|
+
| 05 | `steps/step-05-deep-review.md` | Opus | Deep Review: adversarial code review (if -x) |
|
|
84
90
|
| 06 | `steps/step-06-resolve.md` | Opus | Fix BLOCKING findings (if any) |
|
|
85
91
|
| 07 | `steps/step-07-tests.md` | Opus | Scaffold tests via MCP (if -t) |
|
|
86
92
|
| 08 | `steps/step-08-run-tests.md` | Opus | Run tests until 100% pass (if -t) |
|
|
87
93
|
</step_files>
|
|
88
94
|
|
|
95
|
+
<apex_phases>
|
|
96
|
+
**APEX = Analyze → Plan → Execute → eXamine**
|
|
97
|
+
|
|
98
|
+
| Phase | Step | Obligatory | Description |
|
|
99
|
+
|-------|------|------------|-------------|
|
|
100
|
+
| *Init* | 00 | Yes | Setup, hierarchy, challenge the need |
|
|
101
|
+
| **A** — Analyze | 01 | Yes | Explore existing code |
|
|
102
|
+
| **P** — Plan | 02 | Yes | File-by-file plan with skill/MCP mapping |
|
|
103
|
+
| **E** — Execute | 03 | Yes | Orchestrate creation via skills and MCP |
|
|
104
|
+
| **X** — eXamine | 04 | Yes | 21 POST-CHECKs, MCP validation, build, acceptance criteria |
|
|
105
|
+
| *Deep Review* | 05 (if -x) | No | Adversarial code review beyond automated checks |
|
|
106
|
+
| *Resolve* | 06 (if BLOCKING) | No | Fix BLOCKING findings |
|
|
107
|
+
| *Tests* | 07-08 (if -t) | No | Scaffold and run tests |
|
|
108
|
+
</apex_phases>
|
|
109
|
+
|
|
89
110
|
<reference_files>
|
|
90
111
|
**Loaded conditionally by steps that need them:**
|
|
91
112
|
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
| Tool | Purpose | Step |
|
|
32
32
|
|------|---------|------|
|
|
33
|
-
| `validate_conventions` | Validate SmartStack conventions | 00 (check), 04 (
|
|
33
|
+
| `validate_conventions` | Validate SmartStack conventions | 00 (check), 04 (examine) |
|
|
34
34
|
|
|
35
35
|
### Generation (step-03)
|
|
36
36
|
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
| `scaffold_api_client` | Generate TypeScript API client | Frontend changes |
|
|
43
43
|
| `scaffold_routes` | Generate React Router routes | Frontend changes |
|
|
44
44
|
|
|
45
|
-
###
|
|
45
|
+
### eXamine (step-04)
|
|
46
46
|
|
|
47
47
|
| Tool | Purpose | Condition |
|
|
48
48
|
|------|---------|-----------|
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
| `suggest_test_scenarios` | Suggest test scenarios |
|
|
66
66
|
| `analyze_test_coverage` | Check coverage percentage |
|
|
67
67
|
|
|
68
|
-
### Review (step-05, if -x)
|
|
68
|
+
### Deep Review (step-05, if -x)
|
|
69
69
|
|
|
70
70
|
| Tool | Purpose |
|
|
71
71
|
|------|---------|
|
|
@@ -22,7 +22,7 @@ Always provide both `team_name` and `description`.
|
|
|
22
22
|
|
|
23
23
|
```yaml
|
|
24
24
|
Task:
|
|
25
|
-
subagent_type: "general-purpose"
|
|
25
|
+
subagent_type: "Explore" | "general-purpose" # See assignment table below
|
|
26
26
|
team_name: "apex-{phase}" # Must match TeamCreate
|
|
27
27
|
name: "{teammate-name}" # e.g., "scan-backend", "exec-frontend"
|
|
28
28
|
model: "sonnet" | "opus" # sonnet for scan, opus for dev (T02/T06)
|
|
@@ -30,14 +30,14 @@ Task:
|
|
|
30
30
|
prompt: "{detailed task prompt}"
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
### Model Assignment (T02/T06)
|
|
33
|
+
### Model & Agent Assignment (T02/T03/T06)
|
|
34
34
|
|
|
35
|
-
| Task Type | Model | Justification |
|
|
36
|
-
|
|
37
|
-
| Scan/read files | Sonnet | Read-only,
|
|
38
|
-
| Read context (PRD, feature.json) | Sonnet | Read-only extraction |
|
|
39
|
-
| Code development | Opus |
|
|
40
|
-
| Fix/resolve | Opus | Requires reasoning |
|
|
35
|
+
| Task Type | subagent_type | Model | Justification |
|
|
36
|
+
|-----------|---------------|-------|---------------|
|
|
37
|
+
| Scan/read files | Explore | Sonnet | Read-only (Glob, Grep, Read) |
|
|
38
|
+
| Read context (PRD, feature.json) | Explore | Sonnet | Read-only extraction |
|
|
39
|
+
| Code development | general-purpose | Opus | Full tools via skills/MCP |
|
|
40
|
+
| Fix/resolve | general-purpose | Opus | Requires reasoning + editing |
|
|
41
41
|
|
|
42
42
|
---
|
|
43
43
|
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Challenge Questions — APEX
|
|
2
|
+
|
|
3
|
+
> **Referenced by:** step-00-init.md
|
|
4
|
+
> Question templates for context detection, hierarchy validation, and need challenging.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Context Detection (section 2)
|
|
9
|
+
|
|
10
|
+
If hierarchy cannot be inferred, ask the user:
|
|
11
|
+
|
|
12
|
+
```yaml
|
|
13
|
+
questions:
|
|
14
|
+
- header: "Context"
|
|
15
|
+
question: "What is the SmartStack context for this work?"
|
|
16
|
+
options:
|
|
17
|
+
- label: "Business (Recommended)"
|
|
18
|
+
description: "Business application module"
|
|
19
|
+
- label: "Platform"
|
|
20
|
+
description: "Platform administration or support"
|
|
21
|
+
- label: "Personal"
|
|
22
|
+
description: "Personal user space"
|
|
23
|
+
multiSelect: false
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 4a. Application Validation
|
|
29
|
+
|
|
30
|
+
If `{app_name}` was NOT clearly inferred from the task description:
|
|
31
|
+
|
|
32
|
+
```yaml
|
|
33
|
+
questions:
|
|
34
|
+
- header: "Application"
|
|
35
|
+
question: "Which application does this module belong to?"
|
|
36
|
+
options:
|
|
37
|
+
- label: "<best guess from task> (Recommended)"
|
|
38
|
+
description: "Inferred from your task description"
|
|
39
|
+
- label: "New application"
|
|
40
|
+
description: "Create a new application in the {context_code} context"
|
|
41
|
+
- label: "Existing application"
|
|
42
|
+
description: "Add to an existing application (specify in Other)"
|
|
43
|
+
multiSelect: false
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
If "New application": collect `{app_name}`, `{app_code}`, `{app_icon}`, `{app_labels}` (4 langs).
|
|
47
|
+
If "Existing application": scan `**/Seeding/Data/**/NavigationApplicationSeedData.cs` and present discovered apps.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 4b. Module Validation
|
|
52
|
+
|
|
53
|
+
If `{module_code}` was NOT clearly inferred from the task description:
|
|
54
|
+
|
|
55
|
+
```yaml
|
|
56
|
+
questions:
|
|
57
|
+
- header: "Module"
|
|
58
|
+
question: "What is the module code? (kebab-case, e.g., 'order-management', 'employees')"
|
|
59
|
+
options:
|
|
60
|
+
- label: "<inferred module code> (Recommended)"
|
|
61
|
+
description: "Inferred from your task description"
|
|
62
|
+
- label: "<alternative suggestion>"
|
|
63
|
+
description: "Alternative based on keywords"
|
|
64
|
+
multiSelect: false
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 4c. Section Selection
|
|
70
|
+
|
|
71
|
+
> **BLOCKING:** This question MUST be asked. `{sections}` MUST contain at least one entry before proceeding.
|
|
72
|
+
|
|
73
|
+
Infer section suggestions from:
|
|
74
|
+
1. Task description (extract nouns/concepts that suggest functional sub-areas)
|
|
75
|
+
2. PRD/feature.json if available (module.sections)
|
|
76
|
+
3. Common patterns: "list" (default for simple CRUD), "dashboard", "settings", "reports"
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
questions:
|
|
80
|
+
- header: "Sections"
|
|
81
|
+
question: "What sections should the module '{module_code}' contain? (Select at least one — use 'Other' to add custom sections)"
|
|
82
|
+
options:
|
|
83
|
+
- label: "<inferred section 1>"
|
|
84
|
+
description: "Primary functional area based on module purpose"
|
|
85
|
+
- label: "<inferred section 2>"
|
|
86
|
+
description: "Secondary functional area"
|
|
87
|
+
- label: "<inferred section 3>"
|
|
88
|
+
description: "Additional area inferred from context"
|
|
89
|
+
multiSelect: true
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Validation (BLOCKING):**
|
|
93
|
+
```
|
|
94
|
+
IF {sections}.length == 0:
|
|
95
|
+
DISPLAY: "Every module must have at least one section. Please select or define at least one."
|
|
96
|
+
→ Re-ask the sections question
|
|
97
|
+
→ DO NOT proceed to next step
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Store for each section:**
|
|
101
|
+
```yaml
|
|
102
|
+
sections:
|
|
103
|
+
- code: "section-kebab"
|
|
104
|
+
labels: { fr: "...", en: "...", it: "...", de: "..." }
|
|
105
|
+
icon: "LucideIconName"
|
|
106
|
+
displayOrder: 10
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 5a. Entity Scope & Relationships
|
|
112
|
+
|
|
113
|
+
```yaml
|
|
114
|
+
questions:
|
|
115
|
+
- header: "Entities"
|
|
116
|
+
question: "What are the main entities this module manages? (e.g., 'Order, OrderLine, OrderStatus')"
|
|
117
|
+
options:
|
|
118
|
+
- label: "<inferred primary entity>"
|
|
119
|
+
description: "Main entity inferred from module name"
|
|
120
|
+
- label: "<inferred primary + secondary>"
|
|
121
|
+
description: "Primary entity plus related entities from context"
|
|
122
|
+
- label: "Only the primary entity"
|
|
123
|
+
description: "Simple module — single entity '{module_code}' with standard CRUD"
|
|
124
|
+
multiSelect: false
|
|
125
|
+
- header: "Complexity"
|
|
126
|
+
question: "What best describes this module's behavior?"
|
|
127
|
+
options:
|
|
128
|
+
- label: "Simple CRUD (Recommended)"
|
|
129
|
+
description: "Standard list/create/edit/delete — no special business logic"
|
|
130
|
+
- label: "CRUD + Business rules"
|
|
131
|
+
description: "CRUD with validations, computed fields, status transitions, or constraints"
|
|
132
|
+
- label: "CRUD + Workflow/Notifications"
|
|
133
|
+
description: "CRUD with automated actions (emails, approvals, webhooks)"
|
|
134
|
+
- label: "Complex module"
|
|
135
|
+
description: "Multiple interrelated entities with specific business logic"
|
|
136
|
+
multiSelect: false
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 5b. Dependencies & Key Properties
|
|
142
|
+
|
|
143
|
+
```yaml
|
|
144
|
+
questions:
|
|
145
|
+
- header: "Dependencies"
|
|
146
|
+
question: "Does this module reference entities from other existing modules?"
|
|
147
|
+
options:
|
|
148
|
+
- label: "No dependencies"
|
|
149
|
+
description: "Standalone module — no FK relationships to other modules"
|
|
150
|
+
- label: "Yes, has FK references"
|
|
151
|
+
description: "References entities from other modules (specify in Other)"
|
|
152
|
+
- label: "Not sure yet"
|
|
153
|
+
description: "Will determine during analysis — may require EntityLookup components"
|
|
154
|
+
multiSelect: false
|
|
155
|
+
- header: "Key fields"
|
|
156
|
+
question: "Beyond standard fields (Id, TenantId, Audit), what are the key business properties of the main entity?"
|
|
157
|
+
options:
|
|
158
|
+
- label: "<inferred properties from context>"
|
|
159
|
+
description: "Properties inferred from module purpose"
|
|
160
|
+
- label: "Standard fields only"
|
|
161
|
+
description: "I'll define properties later during implementation"
|
|
162
|
+
- label: "I have specific requirements"
|
|
163
|
+
description: "Describe your fields in 'Other'"
|
|
164
|
+
multiSelect: false
|
|
165
|
+
```
|
|
@@ -1,145 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
name: step-04-validate
|
|
3
|
-
description: MCP validation, build verification, seed data check, acceptance criteria
|
|
4
|
-
model: opus
|
|
5
|
-
prev_step: steps/step-03-execute.md
|
|
6
|
-
next_step: steps/step-05-examine.md
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Step 4: Validate
|
|
10
|
-
|
|
11
|
-
**Goal:** Verify everything works. MCP conventions, build, seed data, acceptance criteria.
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## 1. MCP Convention Validation
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
Call: mcp__smartstack__validate_conventions
|
|
19
|
-
|
|
20
|
-
Expected: 0 errors
|
|
21
|
-
If errors found:
|
|
22
|
-
→ Fix each error (use appropriate skill/MCP)
|
|
23
|
-
→ Re-validate until 0 errors
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
## 2. EF Core Migration Check (if needs_migration)
|
|
29
|
-
|
|
30
|
-
```
|
|
31
|
-
Call: mcp__smartstack__check_migrations
|
|
32
|
-
|
|
33
|
-
Verify:
|
|
34
|
-
- Migration exists and is applied
|
|
35
|
-
- No pending model changes
|
|
36
|
-
- ModelSnapshot matches
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## 3. Frontend Route Validation (if frontend modified)
|
|
42
|
-
|
|
43
|
-
```
|
|
44
|
-
Call: mcp__smartstack__validate_frontend_routes
|
|
45
|
-
|
|
46
|
-
Verify:
|
|
47
|
-
- Routes nested inside correct Layout wrapper
|
|
48
|
-
- Route paths match controller patterns
|
|
49
|
-
- No orphan routes
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
---
|
|
53
|
-
|
|
54
|
-
## 4. Build Verification
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
# Cleanup corrupted EF Core design-time artifacts (Roslyn BuildHost bug on Windows)
|
|
58
|
-
for d in src/*/bin?Debug; do [ -d "$d" ] && echo "Removing corrupted artifact: $d" && rm -rf "$d"; done
|
|
59
|
-
|
|
60
|
-
# Backend
|
|
61
|
-
dotnet clean && dotnet restore && dotnet build
|
|
62
|
-
|
|
63
|
-
# Frontend (if applicable)
|
|
64
|
-
npm run typecheck
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
**BLOCKING:** Both must pass. If failure, fix and retry.
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## 5. Database & Migration Validation (if needs_migration)
|
|
72
|
-
|
|
73
|
-
### 5a. Pending Model Changes Check
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
INFRA_PROJECT=$(ls src/*Infrastructure*/*.csproj 2>/dev/null | head -1)
|
|
77
|
-
API_PROJECT=$(ls src/*Api*/*.csproj 2>/dev/null | head -1)
|
|
78
|
-
|
|
79
|
-
dotnet ef migrations has-pending-model-changes \
|
|
80
|
-
--project "$INFRA_PROJECT" \
|
|
81
|
-
--startup-project "$API_PROJECT"
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
**BLOCKING** if pending changes detected → migration is missing.
|
|
85
|
-
|
|
86
|
-
### 5b. Migration Application Test (SQL Server LocalDB)
|
|
87
|
-
|
|
88
|
-
```bash
|
|
89
|
-
DB_NAME="SmartStack_Apex_Validate_$(date +%s)"
|
|
90
|
-
CONN_STRING="Server=(localdb)\\MSSQLLocalDB;Database=$DB_NAME;Integrated Security=true;TrustServerCertificate=true;Connect Timeout=120;"
|
|
91
|
-
|
|
92
|
-
dotnet ef database update \
|
|
93
|
-
--connection "$CONN_STRING" \
|
|
94
|
-
--project "$INFRA_PROJECT" \
|
|
95
|
-
--startup-project "$API_PROJECT"
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
**BLOCKING** if migration fails on SQL Server. Common issues:
|
|
99
|
-
- SQLite-only syntax in migrations (fix: regenerate migration)
|
|
100
|
-
- Column type mismatches (fix: update EF configuration)
|
|
101
|
-
- Missing foreign key targets (fix: reorder migrations)
|
|
102
|
-
|
|
103
|
-
### 5c. Integration Tests on Real SQL Server
|
|
104
|
-
|
|
105
|
-
```bash
|
|
106
|
-
# Integration tests use DatabaseFixture → real SQL Server LocalDB
|
|
107
|
-
# This validates: LINQ→SQL, multi-tenant isolation, soft delete, EF configs
|
|
108
|
-
INT_TEST_PROJECT=$(ls tests/*Tests.Integration*/*.csproj 2>/dev/null | head -1)
|
|
109
|
-
if [ -n "$INT_TEST_PROJECT" ]; then
|
|
110
|
-
dotnet test "$INT_TEST_PROJECT" --no-build --verbosity normal
|
|
111
|
-
fi
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
Tests running against SQL Server catch issues that SQLite misses:
|
|
115
|
-
- Case sensitivity in string comparisons
|
|
116
|
-
- Date/time function differences
|
|
117
|
-
- IDENTITY vs AUTOINCREMENT behavior
|
|
118
|
-
- Global query filter translation to T-SQL
|
|
119
|
-
|
|
120
|
-
### 5d. Cleanup
|
|
121
|
-
|
|
122
|
-
```bash
|
|
123
|
-
sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "IF DB_ID('$DB_NAME') IS NOT NULL BEGIN ALTER DATABASE [$DB_NAME] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [$DB_NAME]; END" 2>/dev/null
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
---
|
|
127
|
-
|
|
128
|
-
## 6. Seed Data Completeness Check (if needs_seed_data)
|
|
129
|
-
|
|
130
|
-
| File | Checks |
|
|
131
|
-
|------|--------|
|
|
132
|
-
| NavigationApplicationSeedData | MUST be first, deterministic GUID, 4 lang translations |
|
|
133
|
-
| NavigationModuleSeedData | Deterministic GUIDs (SHA256), 4 languages, GetModuleEntry + GetTranslationEntries |
|
|
134
|
-
| PermissionsSeedData | MCP generate_permissions used, paths match Permissions.cs, wildcard + CRUD |
|
|
135
|
-
| RolesSeedData | Admin=wildcard, Manager=CRU, Contributor=CR, Viewer=R |
|
|
136
|
-
| IClientSeedDataProvider | 3 Seed methods, idempotent, factory methods, SaveChanges per group |
|
|
137
|
-
| DI Registration | `services.AddScoped<IClientSeedDataProvider, {App}SeedDataProvider>()` |
|
|
138
|
-
|
|
139
|
-
---
|
|
140
|
-
|
|
141
|
-
## 6b. BLOCKING POST-CHECKs (bash verification on real files)
|
|
1
|
+
# BLOCKING POST-CHECKs
|
|
142
2
|
|
|
3
|
+
> **Referenced by:** step-04-examine.md (section 6b)
|
|
143
4
|
> These checks run on the actual generated files. Model-interpreted checks are unreliable.
|
|
144
5
|
|
|
145
6
|
### POST-CHECK 1: Navigation routes must be full paths starting with /
|
|
@@ -210,15 +71,17 @@ if [ -n "$SEED_FILES" ]; then
|
|
|
210
71
|
fi
|
|
211
72
|
```
|
|
212
73
|
|
|
213
|
-
### POST-CHECK 5: Services must inject
|
|
74
|
+
### POST-CHECK 5: Services must inject ICurrentTenantService (tenant isolation)
|
|
214
75
|
|
|
215
76
|
```bash
|
|
216
77
|
SERVICE_FILES=$(find src/ -path "*/Services/*" -name "*Service.cs" ! -name "I*Service.cs" 2>/dev/null)
|
|
217
78
|
if [ -n "$SERVICE_FILES" ]; then
|
|
218
79
|
for f in $SERVICE_FILES; do
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
echo "
|
|
80
|
+
# Accept either ICurrentTenantService or ICurrentUser (legacy) for tenant context
|
|
81
|
+
if ! grep -qE "ICurrentTenantService|ICurrentUser" "$f"; then
|
|
82
|
+
echo "BLOCKING: Service missing tenant context injection: $f"
|
|
83
|
+
echo "All services MUST inject ICurrentTenantService for tenant isolation"
|
|
84
|
+
echo "Pattern: private readonly ICurrentTenantService _currentTenant;"
|
|
222
85
|
exit 1
|
|
223
86
|
fi
|
|
224
87
|
done
|
|
@@ -509,81 +372,86 @@ if [ -n "$CREATE_VALIDATORS" ]; then
|
|
|
509
372
|
fi
|
|
510
373
|
```
|
|
511
374
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
---
|
|
515
|
-
|
|
516
|
-
## 7. Acceptance Criteria POST-CHECK
|
|
517
|
-
|
|
518
|
-
For each AC inferred in step-01:
|
|
519
|
-
|
|
520
|
-
```
|
|
521
|
-
AC1: {criterion} → PASS / FAIL (evidence: {file:line or test})
|
|
522
|
-
AC2: {criterion} → PASS / FAIL (evidence: {file:line or test})
|
|
523
|
-
...
|
|
524
|
-
```
|
|
525
|
-
|
|
526
|
-
**All ACs must PASS. If any FAIL, go back to step-03 to fix.**
|
|
527
|
-
|
|
528
|
-
---
|
|
529
|
-
|
|
530
|
-
## 8. Validation Summary
|
|
375
|
+
### POST-CHECK 19: SeedConstants must NOT contain ContextId (pre-seeded by SmartStack core)
|
|
531
376
|
|
|
377
|
+
```bash
|
|
378
|
+
# NavigationContext IDs (business, platform, personal) are pre-seeded by SmartStack core
|
|
379
|
+
# with hardcoded GUIDs. Client code MUST look them up by code at runtime, NEVER generate them.
|
|
380
|
+
SEED_CONST_FILES=$(find src/ -path "*/Seeding/*" -name "SeedConstants.cs" 2>/dev/null)
|
|
381
|
+
SEED_ALL_FILES=$(find src/ -path "*/Seeding/Data/*" -name "*.cs" 2>/dev/null)
|
|
382
|
+
if [ -n "$SEED_CONST_FILES" ]; then
|
|
383
|
+
BAD_CONTEXT_ID=$(grep -Pn 'ContextId\s*=' $SEED_CONST_FILES 2>/dev/null)
|
|
384
|
+
if [ -n "$BAD_CONTEXT_ID" ]; then
|
|
385
|
+
echo "BLOCKING: SeedConstants must NOT contain a ContextId constant"
|
|
386
|
+
echo "NavigationContext IDs are pre-seeded by SmartStack core with hardcoded GUIDs"
|
|
387
|
+
echo "Fix: Remove ContextId from SeedConstants. In SeedDataProvider, query:"
|
|
388
|
+
echo " var ctx = await db.NavigationContexts.FirstOrDefaultAsync(c => c.Code == \"business\", ct);"
|
|
389
|
+
echo "$BAD_CONTEXT_ID"
|
|
390
|
+
exit 1
|
|
391
|
+
fi
|
|
392
|
+
fi
|
|
393
|
+
if [ -n "$SEED_ALL_FILES" ]; then
|
|
394
|
+
BAD_CTX_GUID=$(grep -Pn 'DeterministicGuid\("nav:(business|platform|personal)"\)' $SEED_ALL_FILES 2>/dev/null)
|
|
395
|
+
if [ -n "$BAD_CTX_GUID" ]; then
|
|
396
|
+
echo "BLOCKING: Deterministic GUID for NavigationContext detected"
|
|
397
|
+
echo "Context IDs (business, platform, personal) are pre-seeded by SmartStack core"
|
|
398
|
+
echo "Fix: Look up context by code at runtime in SeedDataProvider.SeedNavigationAsync()"
|
|
399
|
+
echo "$BAD_CTX_GUID"
|
|
400
|
+
exit 1
|
|
401
|
+
fi
|
|
402
|
+
fi
|
|
532
403
|
```
|
|
533
|
-
**APEX SmartStack - Validation Complete**
|
|
534
|
-
|
|
535
|
-
| Check | Status |
|
|
536
|
-
|-------|--------|
|
|
537
|
-
| MCP validate_conventions | PASS (0 errors) |
|
|
538
|
-
| EF Core migrations | PASS / N/A |
|
|
539
|
-
| DB: Migrations apply (SQL Server) | PASS / N/A |
|
|
540
|
-
| DB: Integration tests (SQL Server) | PASS / N/A |
|
|
541
|
-
| Frontend routes | PASS / N/A |
|
|
542
|
-
| dotnet build | PASS |
|
|
543
|
-
| npm typecheck | PASS / N/A |
|
|
544
|
-
| Seed data | PASS / N/A |
|
|
545
|
-
| I18n: 4 languages per namespace | PASS / N/A |
|
|
546
|
-
| Lazy loading: no static page imports | PASS / N/A |
|
|
547
|
-
| Forms: full pages, zero modals | PASS / N/A |
|
|
548
|
-
| Forms: create/edit pages exist | PASS / N/A |
|
|
549
|
-
| Forms: test files exist | PASS / N/A |
|
|
550
|
-
| FK fields: EntityLookup, no plain text | PASS / N/A |
|
|
551
|
-
| APIs: search parameter on GetAll | PASS / N/A |
|
|
552
|
-
| CSS variables: no hardcoded colors | PASS / N/A |
|
|
553
|
-
| Routes: seed data vs frontend match | PASS / N/A |
|
|
554
|
-
| HasQueryFilter: no Guid.Empty pattern | PASS / N/A |
|
|
555
|
-
| GetAll: PaginatedResult required | PASS / N/A |
|
|
556
|
-
| I18n: required key structure | PASS / N/A |
|
|
557
|
-
| Entities: IAuditableEntity + validators | PASS / N/A |
|
|
558
|
-
| Acceptance criteria | {X}/{Y} PASS |
|
|
559
|
-
```
|
|
560
|
-
|
|
561
|
-
---
|
|
562
|
-
|
|
563
|
-
## 9. Save Output (if save_mode)
|
|
564
|
-
|
|
565
|
-
Write to `{output_dir}/04-validate.md` with validation results.
|
|
566
|
-
|
|
567
|
-
---
|
|
568
404
|
|
|
569
|
-
|
|
405
|
+
### POST-CHECK 20: RolePermission seed data must NOT use deterministic role GUIDs
|
|
570
406
|
|
|
407
|
+
```bash
|
|
408
|
+
# System roles (admin, manager, contributor, viewer) are pre-seeded by SmartStack core.
|
|
409
|
+
# RolePermission mappings MUST look up roles by Code at runtime, NEVER use deterministic GUIDs.
|
|
410
|
+
SEED_ALL_FILES=$(find src/ -path "*/Seeding/Data/*" -name "*.cs" 2>/dev/null)
|
|
411
|
+
SEED_CONST_FILES=$(find src/ -path "*/Seeding/*" -name "SeedConstants.cs" 2>/dev/null)
|
|
412
|
+
if [ -n "$SEED_ALL_FILES" ]; then
|
|
413
|
+
BAD_ROLE_GUID=$(grep -Pn 'DeterministicGuid\("role:' $SEED_ALL_FILES $SEED_CONST_FILES 2>/dev/null)
|
|
414
|
+
if [ -n "$BAD_ROLE_GUID" ]; then
|
|
415
|
+
echo "BLOCKING: Deterministic GUID for role detected (e.g., DeterministicGuid(\"role:admin\"))"
|
|
416
|
+
echo "System roles are pre-seeded by SmartStack core with their own IDs"
|
|
417
|
+
echo "Fix: In SeedRolePermissionsAsync(), look up roles by Code:"
|
|
418
|
+
echo " var roles = await context.Roles.Where(r => r.IsSystem || r.ApplicationId != null).ToListAsync(ct);"
|
|
419
|
+
echo " var role = roles.FirstOrDefault(r => r.Code == mapping.RoleCode);"
|
|
420
|
+
echo "$BAD_ROLE_GUID"
|
|
421
|
+
exit 1
|
|
422
|
+
fi
|
|
423
|
+
fi
|
|
424
|
+
# Also check for GenerateRoleGuid usage in RolePermission mapping files (not in ApplicationRolesSeedData itself)
|
|
425
|
+
ROLE_PERM_FILES=$(find src/ -path "*/Seeding/Data/*" -name "*RolesSeedData.cs" 2>/dev/null)
|
|
426
|
+
if [ -n "$ROLE_PERM_FILES" ]; then
|
|
427
|
+
BAD_ROLE_REF=$(grep -Pn 'GenerateRoleGuid|GetAdminRoleId|GetManagerRoleId|GetViewerRoleId|GetContributorRoleId' $ROLE_PERM_FILES 2>/dev/null)
|
|
428
|
+
if [ -n "$BAD_ROLE_REF" ]; then
|
|
429
|
+
echo "WARNING: RolesSeedData uses hardcoded role GUID helpers instead of Code-based lookup"
|
|
430
|
+
echo "Fix: Use RoleCode string (e.g., 'admin') and resolve in SeedRolePermissionsAsync()"
|
|
431
|
+
echo "$BAD_ROLE_REF"
|
|
432
|
+
fi
|
|
433
|
+
fi
|
|
571
434
|
```
|
|
572
|
-
IF examine_mode = true:
|
|
573
|
-
→ Load steps/step-05-examine.md
|
|
574
435
|
|
|
575
|
-
|
|
576
|
-
→ Load steps/step-07-tests.md
|
|
436
|
+
### POST-CHECK 21: Services must NOT use TenantId!.Value (null-forgiving crash pattern)
|
|
577
437
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
438
|
+
```bash
|
|
439
|
+
# The !.Value pattern on Guid? throws InvalidOperationException (500) instead of clean 401
|
|
440
|
+
SERVICE_FILES=$(find src/ -path "*/Services/*" -name "*Service.cs" ! -name "I*Service.cs" 2>/dev/null)
|
|
441
|
+
if [ -n "$SERVICE_FILES" ]; then
|
|
442
|
+
BAD_PATTERN=$(grep -Pn 'TenantId!\s*\.Value|TenantId!\s*\.ToString|\.TenantId!' $SERVICE_FILES 2>/dev/null)
|
|
443
|
+
if [ -n "$BAD_PATTERN" ]; then
|
|
444
|
+
echo "BLOCKING: Services use TenantId!.Value — causes 500 instead of 401 when tenant context is missing"
|
|
445
|
+
echo "$BAD_PATTERN"
|
|
446
|
+
echo ""
|
|
447
|
+
echo "Fix: Replace with guard clause at the start of every method:"
|
|
448
|
+
echo " var tenantId = _currentTenant.TenantId"
|
|
449
|
+
echo " ?? throw new UnauthorizedAccessException(\"Tenant context is required\");"
|
|
450
|
+
echo ""
|
|
451
|
+
echo "This produces a clean 401 via GlobalExceptionHandlerMiddleware instead of an opaque 500."
|
|
452
|
+
exit 1
|
|
453
|
+
fi
|
|
454
|
+
fi
|
|
583
455
|
```
|
|
584
456
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
## FINAL SUMMARY (if no more steps)
|
|
588
|
-
|
|
589
|
-
Display: task, context, files created/modified, validation status, commits count, next steps (git diff, dotnet test, deploy).
|
|
457
|
+
**If ANY POST-CHECK fails → fix in step-03, re-validate.**
|