@atlashub/smartstack-cli 3.24.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/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp-entry.mjs +51 -14
- 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/references/post-checks.md +457 -0
- package/templates/skills/apex/references/smartstack-api.md +234 -14
- package/templates/skills/apex/references/smartstack-frontend.md +20 -0
- 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 +6 -4
- 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/efcore/steps/migration/step-02-create.md +14 -1
- package/templates/skills/ralph-loop/references/category-rules.md +26 -2
- package/templates/skills/ralph-loop/references/compact-loop.md +1 -1
- package/templates/skills/ralph-loop/references/core-seed-data.md +45 -10
- package/templates/skills/ralph-loop/steps/step-02-execute.md +128 -1
- package/templates/skills/validate-feature/steps/step-01-compile.md +4 -1
- package/templates/skills/apex/steps/step-04-validate.md +0 -448
|
@@ -1,448 +0,0 @@
|
|
|
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
|
-
# Backend
|
|
58
|
-
dotnet clean && dotnet restore && dotnet build
|
|
59
|
-
|
|
60
|
-
# Frontend (if applicable)
|
|
61
|
-
npm run typecheck
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
**BLOCKING:** Both must pass. If failure, fix and retry.
|
|
65
|
-
|
|
66
|
-
---
|
|
67
|
-
|
|
68
|
-
## 5. Database & Migration Validation (if needs_migration)
|
|
69
|
-
|
|
70
|
-
### 5a. Pending Model Changes Check
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
INFRA_PROJECT=$(ls src/*Infrastructure*/*.csproj 2>/dev/null | head -1)
|
|
74
|
-
API_PROJECT=$(ls src/*Api*/*.csproj 2>/dev/null | head -1)
|
|
75
|
-
|
|
76
|
-
dotnet ef migrations has-pending-model-changes \
|
|
77
|
-
--project "$INFRA_PROJECT" \
|
|
78
|
-
--startup-project "$API_PROJECT"
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
**BLOCKING** if pending changes detected → migration is missing.
|
|
82
|
-
|
|
83
|
-
### 5b. Migration Application Test (SQL Server LocalDB)
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
DB_NAME="SmartStack_Apex_Validate_$(date +%s)"
|
|
87
|
-
CONN_STRING="Server=(localdb)\\MSSQLLocalDB;Database=$DB_NAME;Integrated Security=true;TrustServerCertificate=true;Connect Timeout=120;"
|
|
88
|
-
|
|
89
|
-
dotnet ef database update \
|
|
90
|
-
--connection "$CONN_STRING" \
|
|
91
|
-
--project "$INFRA_PROJECT" \
|
|
92
|
-
--startup-project "$API_PROJECT"
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
**BLOCKING** if migration fails on SQL Server. Common issues:
|
|
96
|
-
- SQLite-only syntax in migrations (fix: regenerate migration)
|
|
97
|
-
- Column type mismatches (fix: update EF configuration)
|
|
98
|
-
- Missing foreign key targets (fix: reorder migrations)
|
|
99
|
-
|
|
100
|
-
### 5c. Integration Tests on Real SQL Server
|
|
101
|
-
|
|
102
|
-
```bash
|
|
103
|
-
# Integration tests use DatabaseFixture → real SQL Server LocalDB
|
|
104
|
-
# This validates: LINQ→SQL, multi-tenant isolation, soft delete, EF configs
|
|
105
|
-
INT_TEST_PROJECT=$(ls tests/*Tests.Integration*/*.csproj 2>/dev/null | head -1)
|
|
106
|
-
if [ -n "$INT_TEST_PROJECT" ]; then
|
|
107
|
-
dotnet test "$INT_TEST_PROJECT" --no-build --verbosity normal
|
|
108
|
-
fi
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
Tests running against SQL Server catch issues that SQLite misses:
|
|
112
|
-
- Case sensitivity in string comparisons
|
|
113
|
-
- Date/time function differences
|
|
114
|
-
- IDENTITY vs AUTOINCREMENT behavior
|
|
115
|
-
- Global query filter translation to T-SQL
|
|
116
|
-
|
|
117
|
-
### 5d. Cleanup
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
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
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
## 6. Seed Data Completeness Check (if needs_seed_data)
|
|
126
|
-
|
|
127
|
-
| File | Checks |
|
|
128
|
-
|------|--------|
|
|
129
|
-
| NavigationApplicationSeedData | MUST be first, deterministic GUID, 4 lang translations |
|
|
130
|
-
| NavigationModuleSeedData | Deterministic GUIDs (SHA256), 4 languages, GetModuleEntry + GetTranslationEntries |
|
|
131
|
-
| PermissionsSeedData | MCP generate_permissions used, paths match Permissions.cs, wildcard + CRUD |
|
|
132
|
-
| RolesSeedData | Admin=wildcard, Manager=CRU, Contributor=CR, Viewer=R |
|
|
133
|
-
| IClientSeedDataProvider | 3 Seed methods, idempotent, factory methods, SaveChanges per group |
|
|
134
|
-
| DI Registration | `services.AddScoped<IClientSeedDataProvider, {App}SeedDataProvider>()` |
|
|
135
|
-
|
|
136
|
-
---
|
|
137
|
-
|
|
138
|
-
## 6b. BLOCKING POST-CHECKs (bash verification on real files)
|
|
139
|
-
|
|
140
|
-
> These checks run on the actual generated files. Model-interpreted checks are unreliable.
|
|
141
|
-
|
|
142
|
-
### POST-CHECK 1: Navigation routes must be full paths starting with /
|
|
143
|
-
|
|
144
|
-
```bash
|
|
145
|
-
# Find all seed data files and check route values
|
|
146
|
-
SEED_FILES=$(find src/ -path "*/Seeding/Data/*" -name "*.cs" 2>/dev/null)
|
|
147
|
-
if [ -n "$SEED_FILES" ]; then
|
|
148
|
-
# Check for short routes (no leading /) in Create() calls for navigation entities
|
|
149
|
-
BAD_ROUTES=$(grep -Pn 'NavigationApplication\.Create\(|NavigationModule\.Create\(|NavigationSection\.Create\(|NavigationResource\.Create\(' $SEED_FILES | grep -v '"/[a-z]')
|
|
150
|
-
if [ -n "$BAD_ROUTES" ]; then
|
|
151
|
-
echo "BLOCKING: Navigation routes must be full paths starting with /"
|
|
152
|
-
echo "$BAD_ROUTES"
|
|
153
|
-
echo "Expected: \"/business/human-resources\" NOT \"humanresources\""
|
|
154
|
-
exit 1
|
|
155
|
-
fi
|
|
156
|
-
fi
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### POST-CHECK 2: All services must filter by TenantId (OWASP A01)
|
|
160
|
-
|
|
161
|
-
```bash
|
|
162
|
-
# Find all service implementation files
|
|
163
|
-
SERVICE_FILES=$(find src/ -path "*/Services/*" -name "*Service.cs" ! -name "I*Service.cs" 2>/dev/null)
|
|
164
|
-
if [ -n "$SERVICE_FILES" ]; then
|
|
165
|
-
# Check each service file has TenantId reference (either _currentUser.TenantId or TenantId filter)
|
|
166
|
-
for f in $SERVICE_FILES; do
|
|
167
|
-
if ! grep -q "TenantId" "$f"; then
|
|
168
|
-
echo "BLOCKING (OWASP A01): Service missing TenantId filter: $f"
|
|
169
|
-
echo "Every service query MUST filter by _currentUser.TenantId"
|
|
170
|
-
exit 1
|
|
171
|
-
fi
|
|
172
|
-
if grep -q "Guid.Empty" "$f"; then
|
|
173
|
-
echo "BLOCKING (OWASP A01): Service uses Guid.Empty instead of _currentUser.TenantId: $f"
|
|
174
|
-
exit 1
|
|
175
|
-
fi
|
|
176
|
-
done
|
|
177
|
-
fi
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### POST-CHECK 3: Controllers must use [RequirePermission], not just [Authorize]
|
|
181
|
-
|
|
182
|
-
```bash
|
|
183
|
-
# Find all controller files
|
|
184
|
-
CTRL_FILES=$(find src/ -path "*/Controllers/*" -name "*Controller.cs" 2>/dev/null)
|
|
185
|
-
if [ -n "$CTRL_FILES" ]; then
|
|
186
|
-
for f in $CTRL_FILES; do
|
|
187
|
-
# Check controller has at least one RequirePermission attribute
|
|
188
|
-
if grep -q "\[Authorize\]" "$f" && ! grep -q "\[RequirePermission" "$f"; then
|
|
189
|
-
echo "WARNING: Controller uses [Authorize] without [RequirePermission]: $f"
|
|
190
|
-
echo "Use [RequirePermission(Permissions.{Module}.{Action})] on each endpoint"
|
|
191
|
-
fi
|
|
192
|
-
done
|
|
193
|
-
fi
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### POST-CHECK 4: Seed data must not use Guid.NewGuid()
|
|
197
|
-
|
|
198
|
-
```bash
|
|
199
|
-
SEED_FILES=$(find src/ -path "*/Seeding/Data/*" -name "*.cs" 2>/dev/null)
|
|
200
|
-
if [ -n "$SEED_FILES" ]; then
|
|
201
|
-
BAD_GUIDS=$(grep -n "Guid.NewGuid()" $SEED_FILES 2>/dev/null)
|
|
202
|
-
if [ -n "$BAD_GUIDS" ]; then
|
|
203
|
-
echo "BLOCKING: Seed data must use deterministic GUIDs (SHA256), not Guid.NewGuid()"
|
|
204
|
-
echo "$BAD_GUIDS"
|
|
205
|
-
exit 1
|
|
206
|
-
fi
|
|
207
|
-
fi
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### POST-CHECK 5: Services must inject ICurrentUser
|
|
211
|
-
|
|
212
|
-
```bash
|
|
213
|
-
SERVICE_FILES=$(find src/ -path "*/Services/*" -name "*Service.cs" ! -name "I*Service.cs" 2>/dev/null)
|
|
214
|
-
if [ -n "$SERVICE_FILES" ]; then
|
|
215
|
-
for f in $SERVICE_FILES; do
|
|
216
|
-
if ! grep -q "ICurrentUser" "$f"; then
|
|
217
|
-
echo "BLOCKING: Service missing ICurrentUser injection: $f"
|
|
218
|
-
echo "All services MUST inject ICurrentUser for tenant isolation"
|
|
219
|
-
exit 1
|
|
220
|
-
fi
|
|
221
|
-
done
|
|
222
|
-
fi
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### POST-CHECK 6: Translation files must exist for all 4 languages (if frontend)
|
|
226
|
-
|
|
227
|
-
```bash
|
|
228
|
-
# Find all i18n namespaces used in tsx files
|
|
229
|
-
TSX_FILES=$(find src/pages/ -name "*.tsx" 2>/dev/null)
|
|
230
|
-
if [ -n "$TSX_FILES" ]; then
|
|
231
|
-
NAMESPACES=$(grep -ohP "useTranslation\(\[?'([^']+)" $TSX_FILES | sed "s/.*'//" | sort -u)
|
|
232
|
-
for NS in $NAMESPACES; do
|
|
233
|
-
for LANG in fr en it de; do
|
|
234
|
-
if [ ! -f "src/i18n/locales/$LANG/$NS.json" ]; then
|
|
235
|
-
echo "BLOCKING: Missing translation file: src/i18n/locales/$LANG/$NS.json"
|
|
236
|
-
exit 1
|
|
237
|
-
fi
|
|
238
|
-
done
|
|
239
|
-
done
|
|
240
|
-
fi
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
### POST-CHECK 7: Pages must use lazy loading (no static page imports in routes)
|
|
244
|
-
|
|
245
|
-
```bash
|
|
246
|
-
ROUTE_FILES=$(find src/routes/ -name "*.tsx" -o -name "*.ts" 2>/dev/null)
|
|
247
|
-
if [ -n "$ROUTE_FILES" ]; then
|
|
248
|
-
STATIC_PAGE_IMPORTS=$(grep -Pn "^import .+ from '@/pages/" $ROUTE_FILES 2>/dev/null)
|
|
249
|
-
if [ -n "$STATIC_PAGE_IMPORTS" ]; then
|
|
250
|
-
echo "BLOCKING: Route files must use React.lazy() for page imports, not static imports"
|
|
251
|
-
echo "$STATIC_PAGE_IMPORTS"
|
|
252
|
-
echo "Fix: const Page = lazy(() => import('@/pages/...').then(m => ({ default: m.Page })));"
|
|
253
|
-
exit 1
|
|
254
|
-
fi
|
|
255
|
-
fi
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
### POST-CHECK 8: Forms must be full pages with routes — ZERO modals/popups/drawers
|
|
259
|
-
|
|
260
|
-
```bash
|
|
261
|
-
# Check for modal/dialog/drawer imports in page files (create/edit forms)
|
|
262
|
-
PAGE_FILES=$(find src/pages/ -name "*.tsx" 2>/dev/null)
|
|
263
|
-
if [ -n "$PAGE_FILES" ]; then
|
|
264
|
-
MODAL_IMPORTS=$(grep -Pn "import.*(?:Modal|Dialog|Drawer|Popup|Sheet)" $PAGE_FILES 2>/dev/null)
|
|
265
|
-
if [ -n "$MODAL_IMPORTS" ]; then
|
|
266
|
-
echo "BLOCKING: Form pages must NOT use Modal/Dialog/Drawer/Popup components"
|
|
267
|
-
echo "Create/Edit forms MUST be full pages with their own URL routes"
|
|
268
|
-
echo "Found modal imports in page files:"
|
|
269
|
-
echo "$MODAL_IMPORTS"
|
|
270
|
-
echo "Fix: Create EntityCreatePage.tsx with route /create and EntityEditPage.tsx with route /:id/edit"
|
|
271
|
-
exit 1
|
|
272
|
-
fi
|
|
273
|
-
fi
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
### POST-CHECK 9: Create/Edit pages must exist as separate route pages
|
|
277
|
-
|
|
278
|
-
```bash
|
|
279
|
-
# For each module with a list page, verify create and edit pages exist
|
|
280
|
-
LIST_PAGES=$(find src/pages/ -name "*ListPage.tsx" -o -name "*sPage.tsx" 2>/dev/null | grep -v test)
|
|
281
|
-
if [ -n "$LIST_PAGES" ]; then
|
|
282
|
-
for LIST_PAGE in $LIST_PAGES; do
|
|
283
|
-
PAGE_DIR=$(dirname "$LIST_PAGE")
|
|
284
|
-
MODULE_NAME=$(basename "$PAGE_DIR")
|
|
285
|
-
# Check for create page
|
|
286
|
-
CREATE_PAGE=$(find "$PAGE_DIR" -name "*CreatePage.tsx" 2>/dev/null)
|
|
287
|
-
if [ -z "$CREATE_PAGE" ]; then
|
|
288
|
-
echo "WARNING: Module $MODULE_NAME has a list page but no CreatePage — expected EntityCreatePage.tsx"
|
|
289
|
-
fi
|
|
290
|
-
# Check for edit page
|
|
291
|
-
EDIT_PAGE=$(find "$PAGE_DIR" -name "*EditPage.tsx" 2>/dev/null)
|
|
292
|
-
if [ -z "$EDIT_PAGE" ]; then
|
|
293
|
-
echo "WARNING: Module $MODULE_NAME has a list page but no EditPage — expected EntityEditPage.tsx"
|
|
294
|
-
fi
|
|
295
|
-
done
|
|
296
|
-
fi
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
### POST-CHECK 10: Form pages must have companion test files
|
|
300
|
-
|
|
301
|
-
```bash
|
|
302
|
-
# Every CreatePage and EditPage must have a .test.tsx file
|
|
303
|
-
FORM_PAGES=$(find src/pages/ -name "*CreatePage.tsx" -o -name "*EditPage.tsx" 2>/dev/null | grep -v test)
|
|
304
|
-
if [ -n "$FORM_PAGES" ]; then
|
|
305
|
-
for FORM_PAGE in $FORM_PAGES; do
|
|
306
|
-
TEST_FILE="${FORM_PAGE%.tsx}.test.tsx"
|
|
307
|
-
if [ ! -f "$TEST_FILE" ]; then
|
|
308
|
-
echo "BLOCKING: Form page missing test file: $FORM_PAGE"
|
|
309
|
-
echo "Expected: $TEST_FILE"
|
|
310
|
-
echo "All form pages MUST have companion test files (rendering, validation, submit, navigation)"
|
|
311
|
-
exit 1
|
|
312
|
-
fi
|
|
313
|
-
done
|
|
314
|
-
fi
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
### POST-CHECK 11: FK fields must NOT be plain text inputs (EntityLookup required)
|
|
318
|
-
|
|
319
|
-
```bash
|
|
320
|
-
# Check for FK fields rendered as plain text inputs in form pages
|
|
321
|
-
FORM_PAGES=$(find src/pages/ -name "*CreatePage.tsx" -o -name "*EditPage.tsx" 2>/dev/null | grep -v test | grep -v node_modules)
|
|
322
|
-
if [ -n "$FORM_PAGES" ]; then
|
|
323
|
-
# Detect pattern: input with value containing "Id" (e.g., employeeId, departmentId)
|
|
324
|
-
FK_TEXT_INPUTS=$(grep -Pn 'type=["\x27]text["\x27].*[a-z]+Id|value=\{[^}]*\.[a-z]+Id\}.*type=["\x27]text["\x27]' $FORM_PAGES 2>/dev/null)
|
|
325
|
-
if [ -n "$FK_TEXT_INPUTS" ]; then
|
|
326
|
-
echo "BLOCKING: FK fields rendered as plain text inputs — MUST use EntityLookup component"
|
|
327
|
-
echo "Users cannot type GUIDs manually. Use <EntityLookup /> from @/components/ui/EntityLookup"
|
|
328
|
-
echo "See smartstack-frontend.md section 6 for the EntityLookup pattern"
|
|
329
|
-
echo "$FK_TEXT_INPUTS"
|
|
330
|
-
exit 1
|
|
331
|
-
fi
|
|
332
|
-
|
|
333
|
-
# Check for input placeholders mentioning "ID" or "id" or "Enter...Id"
|
|
334
|
-
FK_PLACEHOLDER=$(grep -Pn 'placeholder=["\x27].*[Ee]nter.*[Ii][Dd]|placeholder=["\x27].*[Gg][Uu][Ii][Dd]' $FORM_PAGES 2>/dev/null)
|
|
335
|
-
if [ -n "$FK_PLACEHOLDER" ]; then
|
|
336
|
-
echo "BLOCKING: Form has placeholder asking user to enter an ID/GUID — use EntityLookup instead"
|
|
337
|
-
echo "$FK_PLACEHOLDER"
|
|
338
|
-
exit 1
|
|
339
|
-
fi
|
|
340
|
-
fi
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
### POST-CHECK 12: Backend APIs must support search parameter for EntityLookup
|
|
344
|
-
|
|
345
|
-
```bash
|
|
346
|
-
# Check that controller GetAll methods accept search parameter
|
|
347
|
-
CTRL_FILES=$(find src/ -path "*/Controllers/*" -name "*Controller.cs" 2>/dev/null)
|
|
348
|
-
if [ -n "$CTRL_FILES" ]; then
|
|
349
|
-
for f in $CTRL_FILES; do
|
|
350
|
-
# Check if controller has GetAll but no search parameter
|
|
351
|
-
if grep -q "\[HttpGet\]" "$f" && grep -q "GetAll" "$f"; then
|
|
352
|
-
if ! grep -q "search" "$f"; then
|
|
353
|
-
echo "WARNING: Controller missing search parameter on GetAll: $f"
|
|
354
|
-
echo "GetAll endpoints MUST accept ?search= to enable EntityLookup on frontend"
|
|
355
|
-
echo "Fix: Add [FromQuery] string? search parameter to GetAll action"
|
|
356
|
-
fi
|
|
357
|
-
fi
|
|
358
|
-
done
|
|
359
|
-
fi
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
### POST-CHECK 13: No hardcoded Tailwind colors in generated pages
|
|
363
|
-
|
|
364
|
-
```bash
|
|
365
|
-
NEW_PAGES=$(git diff --name-only HEAD 2>/dev/null | grep "src/pages/.*\.tsx$")
|
|
366
|
-
if [ -n "$NEW_PAGES" ]; then
|
|
367
|
-
HARDCODED=$(grep -Pn '(bg|text|border)-(?!\[)(red|blue|green|gray|white|black|slate|zinc|neutral|stone)-' $NEW_PAGES 2>/dev/null)
|
|
368
|
-
if [ -n "$HARDCODED" ]; then
|
|
369
|
-
echo "WARNING: Pages should use CSS variables instead of hardcoded Tailwind colors"
|
|
370
|
-
echo "Fix: bg-[var(--bg-card)] instead of bg-white, text-[var(--text-primary)] instead of text-gray-900"
|
|
371
|
-
echo "$HARDCODED"
|
|
372
|
-
fi
|
|
373
|
-
fi
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
**If ANY POST-CHECK fails → fix in step-03, re-validate.**
|
|
377
|
-
|
|
378
|
-
---
|
|
379
|
-
|
|
380
|
-
## 7. Acceptance Criteria POST-CHECK
|
|
381
|
-
|
|
382
|
-
For each AC inferred in step-01:
|
|
383
|
-
|
|
384
|
-
```
|
|
385
|
-
AC1: {criterion} → PASS / FAIL (evidence: {file:line or test})
|
|
386
|
-
AC2: {criterion} → PASS / FAIL (evidence: {file:line or test})
|
|
387
|
-
...
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
**All ACs must PASS. If any FAIL, go back to step-03 to fix.**
|
|
391
|
-
|
|
392
|
-
---
|
|
393
|
-
|
|
394
|
-
## 8. Validation Summary
|
|
395
|
-
|
|
396
|
-
```
|
|
397
|
-
**APEX SmartStack - Validation Complete**
|
|
398
|
-
|
|
399
|
-
| Check | Status |
|
|
400
|
-
|-------|--------|
|
|
401
|
-
| MCP validate_conventions | PASS (0 errors) |
|
|
402
|
-
| EF Core migrations | PASS / N/A |
|
|
403
|
-
| DB: Migrations apply (SQL Server) | PASS / N/A |
|
|
404
|
-
| DB: Integration tests (SQL Server) | PASS / N/A |
|
|
405
|
-
| Frontend routes | PASS / N/A |
|
|
406
|
-
| dotnet build | PASS |
|
|
407
|
-
| npm typecheck | PASS / N/A |
|
|
408
|
-
| Seed data | PASS / N/A |
|
|
409
|
-
| I18n: 4 languages per namespace | PASS / N/A |
|
|
410
|
-
| Lazy loading: no static page imports | PASS / N/A |
|
|
411
|
-
| Forms: full pages, zero modals | PASS / N/A |
|
|
412
|
-
| Forms: create/edit pages exist | PASS / N/A |
|
|
413
|
-
| Forms: test files exist | PASS / N/A |
|
|
414
|
-
| FK fields: EntityLookup, no plain text | PASS / N/A |
|
|
415
|
-
| APIs: search parameter on GetAll | PASS / N/A |
|
|
416
|
-
| CSS variables: no hardcoded colors | PASS / N/A |
|
|
417
|
-
| Acceptance criteria | {X}/{Y} PASS |
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
---
|
|
421
|
-
|
|
422
|
-
## 9. Save Output (if save_mode)
|
|
423
|
-
|
|
424
|
-
Write to `{output_dir}/04-validate.md` with validation results.
|
|
425
|
-
|
|
426
|
-
---
|
|
427
|
-
|
|
428
|
-
## 10. Route to Next Step
|
|
429
|
-
|
|
430
|
-
```
|
|
431
|
-
IF examine_mode = true:
|
|
432
|
-
→ Load steps/step-05-examine.md
|
|
433
|
-
|
|
434
|
-
ELSE IF test_mode = true:
|
|
435
|
-
→ Load steps/step-07-tests.md
|
|
436
|
-
|
|
437
|
-
ELSE IF pr_mode = true:
|
|
438
|
-
→ Create PR and show final summary
|
|
439
|
-
|
|
440
|
-
ELSE:
|
|
441
|
-
→ Show final summary and exit
|
|
442
|
-
```
|
|
443
|
-
|
|
444
|
-
---
|
|
445
|
-
|
|
446
|
-
## FINAL SUMMARY (if no more steps)
|
|
447
|
-
|
|
448
|
-
Display: task, context, files created/modified, validation status, commits count, next steps (git diff, dotnet test, deploy).
|