@atlashub/smartstack-cli 3.34.0 → 3.35.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/.documentation/init.html +409 -0
- package/dist/index.js +32 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-entry.mjs +7 -24
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -2
- package/templates/mcp-scaffolding/controller.cs.hbs +5 -1
- package/templates/skills/apex/SKILL.md +3 -3
- package/templates/skills/apex/references/post-checks.md +225 -0
- package/templates/skills/apex/references/smartstack-api.md +29 -1
- package/templates/skills/apex/references/smartstack-frontend.md +27 -0
- package/templates/skills/apex/references/smartstack-layers.md +18 -2
- package/templates/skills/apex/steps/step-00-init.md +73 -0
- package/templates/skills/apex/steps/step-01-analyze.md +21 -0
- package/templates/skills/apex/steps/step-03-execute.md +72 -5
- package/templates/skills/apex/steps/step-04-examine.md +7 -1
- package/templates/skills/business-analyse/SKILL.md +4 -3
- package/templates/skills/business-analyse/_shared.md +9 -0
- package/templates/skills/business-analyse/schemas/application-schema.json +13 -0
- package/templates/skills/business-analyse/steps/step-00-init.md +190 -34
- package/templates/skills/business-analyse/steps/step-01-cadrage.md +129 -10
- package/templates/skills/business-analyse/steps/step-01b-applications.md +184 -13
- package/templates/skills/business-analyse/steps/step-03c-compile.md +14 -2
- package/templates/skills/business-analyse/steps/step-03d-validate.md +5 -1
- package/templates/skills/ralph-loop/SKILL.md +5 -0
- package/templates/skills/ralph-loop/references/category-rules.md +29 -0
- package/templates/skills/ralph-loop/references/compact-loop.md +85 -2
- package/templates/skills/ralph-loop/references/section-splitting.md +439 -0
- package/templates/skills/ralph-loop/steps/step-01-task.md +27 -0
- package/templates/skills/ralph-loop/steps/step-02-execute.md +45 -1
- package/templates/skills/ralph-loop/steps/step-05-report.md +19 -0
- package/scripts/health-check.sh +0 -168
- package/scripts/postinstall.js +0 -18
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlashub/smartstack-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.35.0",
|
|
4
4
|
"description": "SmartStack Claude Code automation toolkit - GitFlow, EF Core migrations, prompts and more",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "SmartStack",
|
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
"dist",
|
|
22
22
|
"templates",
|
|
23
23
|
"config",
|
|
24
|
-
"scripts",
|
|
25
24
|
".documentation"
|
|
26
25
|
],
|
|
27
26
|
"engines": {
|
|
@@ -6,6 +6,9 @@ using Microsoft.AspNetCore.Authorization;
|
|
|
6
6
|
using Microsoft.AspNetCore.Mvc;
|
|
7
7
|
using Microsoft.Extensions.Logging;
|
|
8
8
|
using SmartStack.Api.Authorization;
|
|
9
|
+
{{#if navRoute}}
|
|
10
|
+
using SmartStack.Api.Routing;
|
|
11
|
+
{{/if}}
|
|
9
12
|
using SmartStack.Application.Common.Models;
|
|
10
13
|
|
|
11
14
|
namespace {{namespace}}.Controllers;
|
|
@@ -14,9 +17,10 @@ namespace {{namespace}}.Controllers;
|
|
|
14
17
|
/// API controller for {{name}} operations
|
|
15
18
|
/// </summary>
|
|
16
19
|
[ApiController]
|
|
17
|
-
[Route("api/[controller]")]
|
|
18
20
|
{{#if navRoute}}
|
|
19
21
|
[NavRoute("{{navRoute}}")]
|
|
22
|
+
{{else}}
|
|
23
|
+
[Route("api/[controller]")]
|
|
20
24
|
{{/if}}
|
|
21
25
|
[Authorize]
|
|
22
26
|
[Produces("application/json")]
|
|
@@ -86,7 +86,7 @@ Execute incremental SmartStack development using the APEX methodology. This skil
|
|
|
86
86
|
| 01 | `steps/step-01-analyze.md` | Opus | Explore existing code (Agent Teams or direct) |
|
|
87
87
|
| 02 | `steps/step-02-plan.md` | Opus | Layer-by-layer plan with skill/MCP mapping |
|
|
88
88
|
| 03 | `steps/step-03-execute.md` | Opus | Orchestrate execution via skills and MCP |
|
|
89
|
-
| 04 | `steps/step-04-examine.md` | Opus | eXamine: MCP validation, build,
|
|
89
|
+
| 04 | `steps/step-04-examine.md` | Opus | eXamine: MCP validation, build, 50 POST-CHECKs, acceptance criteria |
|
|
90
90
|
| 05 | `steps/step-05-deep-review.md` | Opus | Deep Review: adversarial code review (if -x) |
|
|
91
91
|
| 06 | `steps/step-06-resolve.md` | Opus | Fix BLOCKING findings (if any) |
|
|
92
92
|
| 07 | `steps/step-07-tests.md` | Opus | Scaffold tests via MCP |
|
|
@@ -98,11 +98,11 @@ Execute incremental SmartStack development using the APEX methodology. This skil
|
|
|
98
98
|
|
|
99
99
|
| Phase | Step | Obligatory | Description |
|
|
100
100
|
|-------|------|------------|-------------|
|
|
101
|
-
| *Init* | 00 | Yes | Setup, hierarchy, challenge the need (skipped in `-d` delegate mode) |
|
|
101
|
+
| *Init* | 00 | Yes | Setup, hierarchy, challenge the need, **scope guard** (skipped in `-d` delegate mode) |
|
|
102
102
|
| **A** — Analyze | 01 | Yes | Explore existing code |
|
|
103
103
|
| **P** — Plan | 02 | Yes | File-by-file plan with skill/MCP mapping |
|
|
104
104
|
| **E** — Execute | 03 | Yes | Orchestrate creation via skills and MCP |
|
|
105
|
-
| **X** — eXamine | 04 | Yes |
|
|
105
|
+
| **X** — eXamine | 04 | Yes | 50 POST-CHECKs, MCP validation, build, acceptance criteria |
|
|
106
106
|
| *Deep Review* | 05 (if -x) | No | Adversarial code review beyond automated checks |
|
|
107
107
|
| *Resolve* | 06 (if BLOCKING) | No | Fix BLOCKING findings |
|
|
108
108
|
| *Tests* | 07-08 | **Yes** | Scaffold and run tests |
|
|
@@ -1251,4 +1251,229 @@ if [ -n "$DETAIL_PAGES" ]; then
|
|
|
1251
1251
|
fi
|
|
1252
1252
|
```
|
|
1253
1253
|
|
|
1254
|
+
### POST-CHECK 44: Migration ModelSnapshot must contain ALL entities registered in DbContext (BLOCKING)
|
|
1255
|
+
|
|
1256
|
+
```bash
|
|
1257
|
+
# Root cause (test-apex-007): 7 entities registered in DbContext but migration only covered 3.
|
|
1258
|
+
# Happens when migration is created ONCE in Layer 0 for the first batch, then additional entities
|
|
1259
|
+
# are added in subsequent iterations without re-running migration.
|
|
1260
|
+
SNAPSHOT=$(find src/ -name "*ModelSnapshot.cs" -path "*/Migrations/*" 2>/dev/null | head -1)
|
|
1261
|
+
DBCONTEXT=$(find src/ -name "*DbContext.cs" -path "*/Persistence/*" ! -name "*DesignTime*" 2>/dev/null | head -1)
|
|
1262
|
+
if [ -n "$SNAPSHOT" ] && [ -n "$DBCONTEXT" ]; then
|
|
1263
|
+
# Extract DbSet entity names from DbContext (DbSet<EntityName>)
|
|
1264
|
+
DBSET_ENTITIES=$(grep -oP 'DbSet<(\w+)>' "$DBCONTEXT" 2>/dev/null | grep -oP '<\K\w+(?=>)' | sort -u)
|
|
1265
|
+
FAIL=false
|
|
1266
|
+
for ENTITY in $DBSET_ENTITIES; do
|
|
1267
|
+
# Skip base SmartStack entities (handled by core migrations)
|
|
1268
|
+
if echo "$ENTITY" | grep -qP '^(Navigation|Tenant|User|Role|Permission|AuditLog|ApplicationTracking)'; then
|
|
1269
|
+
continue
|
|
1270
|
+
fi
|
|
1271
|
+
# Check if the entity appears in ModelSnapshot (builder.Entity<EntityName>)
|
|
1272
|
+
if ! grep -q "Entity<$ENTITY>" "$SNAPSHOT" 2>/dev/null; then
|
|
1273
|
+
echo "BLOCKING: Entity '$ENTITY' is registered as DbSet in $DBCONTEXT but MISSING from ModelSnapshot"
|
|
1274
|
+
echo " This means no migration was created for this entity — it will not exist in the database."
|
|
1275
|
+
echo " Fix: Run 'dotnet ef migrations add' to include all new entities"
|
|
1276
|
+
FAIL=true
|
|
1277
|
+
fi
|
|
1278
|
+
done
|
|
1279
|
+
if [ "$FAIL" = true ]; then
|
|
1280
|
+
echo ""
|
|
1281
|
+
echo " Root cause: Migration was likely created once for the first batch of entities,"
|
|
1282
|
+
echo " but additional entities were added later without regenerating the migration."
|
|
1283
|
+
echo " Fix: Create a new migration that covers ALL missing entities."
|
|
1284
|
+
exit 1
|
|
1285
|
+
fi
|
|
1286
|
+
fi
|
|
1287
|
+
```
|
|
1288
|
+
|
|
1289
|
+
### POST-CHECK 45: I18n namespace files must be registered in i18n config (BLOCKING)
|
|
1290
|
+
|
|
1291
|
+
```bash
|
|
1292
|
+
# Root cause (test-apex-007): i18n JSON files existed in src/i18n/locales/ but were never
|
|
1293
|
+
# registered in the i18n config (config.ts or index.ts). Pages calling useTranslation(['module'])
|
|
1294
|
+
# got empty translations at runtime.
|
|
1295
|
+
I18N_CONFIG=$(find src/ web/ -path "*/i18n/config.ts" -o -path "*/i18n/index.ts" -o -path "*/i18n/i18n.ts" 2>/dev/null | grep -v node_modules | head -1)
|
|
1296
|
+
if [ -n "$I18N_CONFIG" ]; then
|
|
1297
|
+
# Find all module JSON files in the primary language (fr)
|
|
1298
|
+
FR_FILES=$(find src/ web/ -path "*/i18n/locales/fr/*.json" 2>/dev/null | grep -v node_modules | grep -v common.json | grep -v navigation.json)
|
|
1299
|
+
if [ -n "$FR_FILES" ]; then
|
|
1300
|
+
FAIL=false
|
|
1301
|
+
for JSON_FILE in $FR_FILES; do
|
|
1302
|
+
NS=$(basename "$JSON_FILE" .json)
|
|
1303
|
+
# Check if namespace is referenced in config (import or resource key)
|
|
1304
|
+
if ! grep -q "$NS" "$I18N_CONFIG" 2>/dev/null; then
|
|
1305
|
+
echo "BLOCKING: i18n namespace '$NS' (from $JSON_FILE) is not registered in $I18N_CONFIG"
|
|
1306
|
+
echo " Pages using useTranslation(['$NS']) will get empty translations at runtime"
|
|
1307
|
+
echo " Fix: Add '$NS' to the resources/ns configuration in $I18N_CONFIG"
|
|
1308
|
+
FAIL=true
|
|
1309
|
+
fi
|
|
1310
|
+
done
|
|
1311
|
+
if [ "$FAIL" = true ]; then
|
|
1312
|
+
exit 1
|
|
1313
|
+
fi
|
|
1314
|
+
fi
|
|
1315
|
+
fi
|
|
1316
|
+
```
|
|
1317
|
+
|
|
1318
|
+
### POST-CHECK 46: FluentValidation validators must be registered via DI (BLOCKING)
|
|
1319
|
+
|
|
1320
|
+
```bash
|
|
1321
|
+
# Root cause (test-apex-007): Validators existed but were never registered in DI.
|
|
1322
|
+
# Without DI registration, [FromBody] DTOs are never validated — any data is accepted.
|
|
1323
|
+
VALIDATOR_FILES=$(find src/ -name "*Validator.cs" -path "*/Validators/*" 2>/dev/null | grep -v test | grep -v Test)
|
|
1324
|
+
if [ -n "$VALIDATOR_FILES" ]; then
|
|
1325
|
+
# Check DI registration file exists
|
|
1326
|
+
DI_FILE=$(find src/ -name "DependencyInjection.cs" -o -name "ServiceCollectionExtensions.cs" 2>/dev/null | grep -v test | head -1)
|
|
1327
|
+
if [ -z "$DI_FILE" ]; then
|
|
1328
|
+
echo "BLOCKING: Validators exist but no DependencyInjection.cs found for DI registration"
|
|
1329
|
+
exit 1
|
|
1330
|
+
fi
|
|
1331
|
+
# Check for AddValidatorsFromAssembly or individual validator registration
|
|
1332
|
+
HAS_ASSEMBLY_REG=$(grep -c "AddValidatorsFromAssembly\|AddValidatorsFromAssemblyContaining" "$DI_FILE" 2>/dev/null)
|
|
1333
|
+
if [ "$HAS_ASSEMBLY_REG" -eq 0 ]; then
|
|
1334
|
+
# Check individual registrations as fallback
|
|
1335
|
+
VALIDATOR_COUNT=$(echo "$VALIDATOR_FILES" | wc -l)
|
|
1336
|
+
REGISTERED_COUNT=0
|
|
1337
|
+
for VF in $VALIDATOR_FILES; do
|
|
1338
|
+
VN=$(basename "$VF" .cs)
|
|
1339
|
+
if grep -q "$VN" "$DI_FILE" 2>/dev/null; then
|
|
1340
|
+
REGISTERED_COUNT=$((REGISTERED_COUNT + 1))
|
|
1341
|
+
fi
|
|
1342
|
+
done
|
|
1343
|
+
if [ "$REGISTERED_COUNT" -eq 0 ]; then
|
|
1344
|
+
echo "BLOCKING: $VALIDATOR_COUNT validators exist but NONE are registered in DI ($DI_FILE)"
|
|
1345
|
+
echo " Fix: Add 'services.AddValidatorsFromAssemblyContaining<Create{Entity}DtoValidator>();' to $DI_FILE"
|
|
1346
|
+
echo " Or use 'services.AddValidatorsFromAssembly(typeof(Create{Entity}DtoValidator).Assembly);'"
|
|
1347
|
+
exit 1
|
|
1348
|
+
fi
|
|
1349
|
+
fi
|
|
1350
|
+
fi
|
|
1351
|
+
```
|
|
1352
|
+
|
|
1353
|
+
### POST-CHECK 47: Date/date properties in DTOs must use DateOnly, not string (BLOCKING)
|
|
1354
|
+
|
|
1355
|
+
```bash
|
|
1356
|
+
# Root cause (test-apex-007): WorkLog DTO had Date property typed as string instead of DateOnly.
|
|
1357
|
+
# This causes: invalid date parsing, no date validation, inconsistent formats across clients.
|
|
1358
|
+
DTO_FILES=$(find src/ -name "*Dto.cs" -path "*/DTOs/*" 2>/dev/null)
|
|
1359
|
+
if [ -n "$DTO_FILES" ]; then
|
|
1360
|
+
FAIL=false
|
|
1361
|
+
for f in $DTO_FILES; do
|
|
1362
|
+
# Find string properties whose name contains "Date" (case-insensitive)
|
|
1363
|
+
BAD_DATES=$(grep -Pn 'string\??\s+\w*[Dd]ate\w*\s*[{;,]' "$f" 2>/dev/null | grep -vi "Updated\|Created\|format\|pattern\|string\|parse")
|
|
1364
|
+
if [ -n "$BAD_DATES" ]; then
|
|
1365
|
+
echo "BLOCKING: DTO has string type for date field — must use DateOnly: $f"
|
|
1366
|
+
echo "$BAD_DATES"
|
|
1367
|
+
echo " Fix: Change 'string Date' to 'DateOnly Date' (or 'DateOnly? Date' if nullable)"
|
|
1368
|
+
echo " DateOnly is the correct .NET type for date-only values (no time component)"
|
|
1369
|
+
FAIL=true
|
|
1370
|
+
fi
|
|
1371
|
+
done
|
|
1372
|
+
if [ "$FAIL" = true ]; then
|
|
1373
|
+
exit 1
|
|
1374
|
+
fi
|
|
1375
|
+
fi
|
|
1376
|
+
```
|
|
1377
|
+
|
|
1378
|
+
### POST-CHECK 48: NavRoute attribute values must use kebab-case (BLOCKING)
|
|
1379
|
+
|
|
1380
|
+
```bash
|
|
1381
|
+
# Root cause (test-apex-007): Controllers had [NavRoute("business.humanresources.employees")]
|
|
1382
|
+
# instead of [NavRoute("business.human-resources.employees")]. This causes route mismatch with
|
|
1383
|
+
# seed data and permission codes, resulting in 404s at runtime.
|
|
1384
|
+
CTRL_FILES=$(find src/ -path "*/Controllers/*" -name "*Controller.cs" 2>/dev/null)
|
|
1385
|
+
if [ -n "$CTRL_FILES" ]; then
|
|
1386
|
+
FAIL=false
|
|
1387
|
+
for f in $CTRL_FILES; do
|
|
1388
|
+
NAVROUTE_VALS=$(grep -oP 'NavRoute\("([^"]+)"' "$f" 2>/dev/null | grep -oP '"[^"]+"' | tr -d '"')
|
|
1389
|
+
for NR in $NAVROUTE_VALS; do
|
|
1390
|
+
# Check each segment for concatenated multi-word without hyphens
|
|
1391
|
+
SEGMENTS=$(echo "$NR" | tr '.' '\n')
|
|
1392
|
+
for SEG in $SEGMENTS; do
|
|
1393
|
+
# Detect segments that look like concatenated words (lowercase, 8+ chars, no hyphens)
|
|
1394
|
+
# Use a simpler heuristic: lowercase-only segment with known multi-word patterns
|
|
1395
|
+
if echo "$SEG" | grep -qP '^[a-z]{8,}$'; then
|
|
1396
|
+
# Additional check: does it contain a known multi-word pattern?
|
|
1397
|
+
if echo "$SEG" | grep -qP '(human|project|leave|client|support|email|time|work|resource)'; then
|
|
1398
|
+
echo "BLOCKING: NavRoute segment '$SEG' in $f appears to be concatenated multi-word without hyphens"
|
|
1399
|
+
echo " Full NavRoute: $NR"
|
|
1400
|
+
echo " Fix: Use kebab-case: e.g., 'humanresources' → 'human-resources', 'projectmanagement' → 'project-management'"
|
|
1401
|
+
FAIL=true
|
|
1402
|
+
fi
|
|
1403
|
+
fi
|
|
1404
|
+
done
|
|
1405
|
+
done
|
|
1406
|
+
done
|
|
1407
|
+
if [ "$FAIL" = true ]; then
|
|
1408
|
+
exit 1
|
|
1409
|
+
fi
|
|
1410
|
+
fi
|
|
1411
|
+
```
|
|
1412
|
+
|
|
1413
|
+
### POST-CHECK 49: Every module with entities must have a migration covering them (BLOCKING)
|
|
1414
|
+
|
|
1415
|
+
```bash
|
|
1416
|
+
# Complementary to POST-CHECK 44 — checks from the entity side.
|
|
1417
|
+
# Finds entity .cs files in Domain/ and verifies they appear in at least one migration file.
|
|
1418
|
+
ENTITY_FILES=$(find src/ -path "*/Domain/Entities/*" -name "*.cs" 2>/dev/null | grep -v test)
|
|
1419
|
+
MIGRATION_DIR=$(find src/ -path "*/Migrations" -type d 2>/dev/null | head -1)
|
|
1420
|
+
if [ -n "$ENTITY_FILES" ] && [ -n "$MIGRATION_DIR" ]; then
|
|
1421
|
+
MIGRATION_FILES=$(find "$MIGRATION_DIR" -name "*.cs" ! -name "*ModelSnapshot*" ! -name "*DesignTime*" 2>/dev/null)
|
|
1422
|
+
if [ -z "$MIGRATION_FILES" ]; then
|
|
1423
|
+
echo "BLOCKING: Entity files exist in Domain/Entities but NO migration files found in $MIGRATION_DIR"
|
|
1424
|
+
exit 1
|
|
1425
|
+
fi
|
|
1426
|
+
FAIL=false
|
|
1427
|
+
for EF in $ENTITY_FILES; do
|
|
1428
|
+
ENTITY_NAME=$(basename "$EF" .cs)
|
|
1429
|
+
# Skip abstract base classes and interfaces
|
|
1430
|
+
if grep -qP '^\s*(public\s+)?(abstract|interface)\s' "$EF" 2>/dev/null; then continue; fi
|
|
1431
|
+
# Check if entity appears in any migration (CreateTable or AddColumn or entity reference)
|
|
1432
|
+
FOUND=$(grep -l "$ENTITY_NAME" $MIGRATION_FILES 2>/dev/null)
|
|
1433
|
+
if [ -z "$FOUND" ]; then
|
|
1434
|
+
echo "BLOCKING: Entity '$ENTITY_NAME' ($EF) not found in any migration file"
|
|
1435
|
+
echo " This entity will NOT have a database table."
|
|
1436
|
+
echo " Fix: Run 'dotnet ef migrations add' to create a migration covering this entity"
|
|
1437
|
+
FAIL=true
|
|
1438
|
+
fi
|
|
1439
|
+
done
|
|
1440
|
+
if [ "$FAIL" = true ]; then
|
|
1441
|
+
exit 1
|
|
1442
|
+
fi
|
|
1443
|
+
fi
|
|
1444
|
+
```
|
|
1445
|
+
|
|
1446
|
+
### POST-CHECK 50: Controllers must NOT have both [Route] and [NavRoute] attributes (BLOCKING)
|
|
1447
|
+
|
|
1448
|
+
```bash
|
|
1449
|
+
# Root cause (test-apex-007): All 7 controllers had BOTH [Route("api/...")] and [NavRoute("...")].
|
|
1450
|
+
# In SmartStack, [NavRoute] resolves routes dynamically from Navigation entities at startup.
|
|
1451
|
+
# [Route] is standard ASP.NET Core static routing. When both exist:
|
|
1452
|
+
# - NavRoute middleware tries to resolve from DB → fails if seed data not applied → no route
|
|
1453
|
+
# - [Route] may or may not take over depending on middleware order
|
|
1454
|
+
# - Result: 404 on ALL endpoints
|
|
1455
|
+
# The MCP validate_conventions previously ENCOURAGED adding [Route] with [NavRoute] — this was a bug.
|
|
1456
|
+
CTRL_FILES=$(find src/ -path "*/Controllers/*" -name "*Controller.cs" 2>/dev/null)
|
|
1457
|
+
if [ -n "$CTRL_FILES" ]; then
|
|
1458
|
+
FAIL=false
|
|
1459
|
+
for f in $CTRL_FILES; do
|
|
1460
|
+
HAS_NAVROUTE=$(grep -c '\[NavRoute(' "$f" 2>/dev/null)
|
|
1461
|
+
HAS_ROUTE=$(grep -c '\[Route(' "$f" 2>/dev/null)
|
|
1462
|
+
if [ "$HAS_NAVROUTE" -gt 0 ] && [ "$HAS_ROUTE" -gt 0 ]; then
|
|
1463
|
+
NAVROUTE_VAL=$(grep -oP 'NavRoute\("([^"]+)"' "$f" 2>/dev/null | head -1)
|
|
1464
|
+
ROUTE_VAL=$(grep -oP 'Route\("([^"]+)"' "$f" 2>/dev/null | head -1)
|
|
1465
|
+
echo "BLOCKING: Controller has BOTH [Route] and [NavRoute] — remove [Route]: $f"
|
|
1466
|
+
echo " Found: [$ROUTE_VAL] + [$NAVROUTE_VAL]"
|
|
1467
|
+
echo " In SmartStack, [NavRoute] resolves routes dynamically from the database."
|
|
1468
|
+
echo " Having [Route] alongside it causes route conflicts and 404s."
|
|
1469
|
+
echo " Fix: Remove the [Route(...)] attribute, keep only [NavRoute(...)]"
|
|
1470
|
+
FAIL=true
|
|
1471
|
+
fi
|
|
1472
|
+
done
|
|
1473
|
+
if [ "$FAIL" = true ]; then
|
|
1474
|
+
exit 1
|
|
1475
|
+
fi
|
|
1476
|
+
fi
|
|
1477
|
+
```
|
|
1478
|
+
|
|
1254
1479
|
**If ANY POST-CHECK fails → fix in step-03, re-validate.**
|
|
@@ -491,6 +491,12 @@ public class {Name}Controller : ControllerBase
|
|
|
491
491
|
}
|
|
492
492
|
```
|
|
493
493
|
|
|
494
|
+
**CRITICAL — Route attribute rules:**
|
|
495
|
+
- `[NavRoute]` is the ONLY route attribute needed — it resolves routes dynamically from Navigation entities at startup
|
|
496
|
+
- **FORBIDDEN:** `[Route("api/...")]` alongside `[NavRoute]` — causes route conflicts and 404s at runtime
|
|
497
|
+
- **FORBIDDEN:** `[Route("api/[controller]")]` — this is standard ASP.NET Core, NOT SmartStack
|
|
498
|
+
- If a controller has `[NavRoute]`, there must be NO `[Route]` attribute on the class
|
|
499
|
+
|
|
494
500
|
**CRITICAL:** Use `[RequirePermission(Permissions.{Module}.{Action})]` on EVERY endpoint — NEVER `[Authorize]` alone (no RBAC enforcement).
|
|
495
501
|
|
|
496
502
|
**CRITICAL — Permission paths use IDENTICAL segments to NavRoute codes (kebab-case):**
|
|
@@ -703,6 +709,26 @@ services.AddValidatorsFromAssemblyContaining<Create{Name}DtoValidator>();
|
|
|
703
709
|
|
|
704
710
|
---
|
|
705
711
|
|
|
712
|
+
## DTO Type Mapping (CRITICAL)
|
|
713
|
+
|
|
714
|
+
> **Use the correct .NET type for each property.** Incorrect types cause runtime parsing errors.
|
|
715
|
+
|
|
716
|
+
| Property Pattern | .NET Type | JSON Format | Example |
|
|
717
|
+
|-----------------|-----------|-------------|---------|
|
|
718
|
+
| `*Date`, `StartDate`, `EndDate`, `BirthDate` | `DateOnly` | `"2025-03-15"` | `public DateOnly Date { get; set; }` |
|
|
719
|
+
| `CreatedAt`, `UpdatedAt` | `DateTime` | `"2025-03-15T10:30:00Z"` | `public DateTime CreatedAt { get; set; }` |
|
|
720
|
+
| `*Time`, `StartTime` | `TimeOnly` | `"14:30:00"` | `public TimeOnly StartTime { get; set; }` |
|
|
721
|
+
| Duration, hours | `decimal` | `8.5` | `public decimal HoursWorked { get; set; }` |
|
|
722
|
+
| FK reference | `Guid` | `"uuid-string"` | `public Guid EmployeeId { get; set; }` |
|
|
723
|
+
|
|
724
|
+
**FORBIDDEN in DTOs:**
|
|
725
|
+
- `string Date` / `string StartDate` — use `DateOnly`
|
|
726
|
+
- `string Time` — use `TimeOnly`
|
|
727
|
+
- `DateTime BirthDate` — use `DateOnly` (no time component needed)
|
|
728
|
+
- `int` for hours/duration — use `decimal` for fractional values
|
|
729
|
+
|
|
730
|
+
---
|
|
731
|
+
|
|
706
732
|
## Common Mistakes to Avoid
|
|
707
733
|
|
|
708
734
|
| Mistake | Reality |
|
|
@@ -713,7 +739,7 @@ services.AddValidatorsFromAssemblyContaining<Create{Name}DtoValidator>();
|
|
|
713
739
|
| `e.IsDeleted` filter | Does NOT exist — no soft delete |
|
|
714
740
|
| `SmartStack.Api.Core.Routing` | Wrong — use `SmartStack.Api.Routing` |
|
|
715
741
|
| `SystemEntity` base class | Does NOT exist — use `BaseEntity` for all |
|
|
716
|
-
| `[Route] + [NavRoute]` | Only `[NavRoute]` needed (resolves route from DB) |
|
|
742
|
+
| `[Route("api/...")] + [NavRoute]` | **FORBIDDEN** — causes 404s. Only `[NavRoute]` needed (resolves route from DB at startup). Remove ALL `[Route]` attributes when `[NavRoute]` is present. |
|
|
717
743
|
| `SmartStack.Domain.Common.Interfaces` | Wrong — interfaces are in `SmartStack.Domain.Common` directly |
|
|
718
744
|
| `[Authorize]` without `[RequirePermission]` | No RBAC enforcement — always use `[RequirePermission]` |
|
|
719
745
|
| `tenantId: Guid.Empty` in services | OWASP A01 — always use validated `_currentTenant.TenantId` |
|
|
@@ -726,6 +752,8 @@ services.AddValidatorsFromAssemblyContaining<Create{Name}DtoValidator>();
|
|
|
726
752
|
| `business.humanresources.employees.read` in permissions | Permission segments MUST match NavRoute kebab-case: `business.human-resources.employees.read` |
|
|
727
753
|
| `Permission.Create()` | Does NOT exist — use `CreateForModule()`, `CreateForSection()`, etc. |
|
|
728
754
|
| `GetAllAsync()` without search param | ALL GetAll endpoints MUST support `?search=` for EntityLookup |
|
|
755
|
+
| `string Date` in DTO | Date-only fields MUST use `DateOnly`, NEVER `string` |
|
|
756
|
+
| `DateTime` for date-only | Use `DateOnly` when no time component needed |
|
|
729
757
|
| FK field as plain text input | Frontend MUST use `EntityLookup` component for Guid FK fields |
|
|
730
758
|
| `PagedResult<T>` / `PaginatedResultDto<T>` | FORBIDDEN — use `PaginatedResult<T>` only |
|
|
731
759
|
|
|
@@ -187,11 +187,38 @@ t('common:actions.save', 'Save')
|
|
|
187
187
|
t('common:errors.network', 'Network error')
|
|
188
188
|
```
|
|
189
189
|
|
|
190
|
+
### Namespace Registration (CRITICAL)
|
|
191
|
+
|
|
192
|
+
> **After creating i18n JSON files, you MUST register each namespace in the i18n config.**
|
|
193
|
+
> Root cause (test-apex-007): JSON files existed but namespaces were not registered → `useTranslation(['module'])` returned empty strings.
|
|
194
|
+
|
|
195
|
+
In the i18n config file (`src/i18n/config.ts` or `src/i18n/index.ts`), add each new namespace:
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// Example: registering new module namespaces
|
|
199
|
+
import employees from './locales/fr/employees.json';
|
|
200
|
+
import projects from './locales/fr/projects.json';
|
|
201
|
+
import clients from './locales/fr/clients.json';
|
|
202
|
+
|
|
203
|
+
// In resources configuration:
|
|
204
|
+
resources: {
|
|
205
|
+
fr: { employees, projects, clients, common, navigation },
|
|
206
|
+
en: { employees: employeesEn, projects: projectsEn, clients: clientsEn, ... },
|
|
207
|
+
// ... it, de
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// OR with ns array:
|
|
211
|
+
ns: ['common', 'navigation', 'employees', 'projects', 'clients'],
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
POST-CHECK 45 validates this. Unregistered namespaces → BLOCKING.
|
|
215
|
+
|
|
190
216
|
### Rules
|
|
191
217
|
|
|
192
218
|
- **ALWAYS** provide a fallback value as 2nd argument to `t()`
|
|
193
219
|
- **ALWAYS** use namespace prefix: `t('namespace:key')`
|
|
194
220
|
- **ALWAYS** generate 4 language files (fr, en, it, de) with identical key structures
|
|
221
|
+
- **ALWAYS** register new namespaces in i18n config file after creating JSON files
|
|
195
222
|
- **NEVER** hardcode user-facing strings in JSX
|
|
196
223
|
- **NEVER** use `t('key')` without namespace prefix
|
|
197
224
|
|
|
@@ -51,6 +51,11 @@
|
|
|
51
51
|
|
|
52
52
|
**BLOCKING:** `dotnet build --no-restore` MUST pass after migration.
|
|
53
53
|
|
|
54
|
+
> **CRITICAL — Migration must cover ALL entities (POST-CHECK 44, 49):**
|
|
55
|
+
> Create/update migration AFTER ALL entities and EF configs are registered in DbContext.
|
|
56
|
+
> Verify with `dotnet ef migrations has-pending-model-changes` — must report NO pending changes.
|
|
57
|
+
> If entities are added incrementally across modules, create a NEW migration for each batch.
|
|
58
|
+
|
|
54
59
|
---
|
|
55
60
|
|
|
56
61
|
## Layer 1 — Application (parallel with API)
|
|
@@ -75,10 +80,13 @@
|
|
|
75
80
|
- **ALL services MUST inject `ICurrentUserService`** for audit trails
|
|
76
81
|
- **ALL services MUST inject `ILogger<T>`** for production diagnostics
|
|
77
82
|
- CQRS with MediatR
|
|
78
|
-
- FluentValidation for all commands
|
|
83
|
+
- FluentValidation for all commands — **MUST register validators via DI:**
|
|
84
|
+
`services.AddValidatorsFromAssemblyContaining<Create{Entity}DtoValidator>();`
|
|
85
|
+
Without DI registration, `[FromBody]` DTOs are never validated (POST-CHECK 46)
|
|
86
|
+
- **Date fields in DTOs MUST use `DateOnly`**, not `string` (POST-CHECK 47). See `smartstack-api.md` DTO Type Mapping.
|
|
79
87
|
- DTOs separate from domain entities
|
|
80
88
|
- Service interfaces in Application, implementations in Infrastructure
|
|
81
|
-
- **FORBIDDEN:** `tenantId: Guid.Empty`, `TenantId!.Value`, queries without TenantId filter, `ICurrentUser` (does not exist — use `ICurrentUserService` + `ICurrentTenantService`)
|
|
89
|
+
- **FORBIDDEN:** `tenantId: Guid.Empty`, `TenantId!.Value`, queries without TenantId filter, `ICurrentUser` (does not exist — use `ICurrentUserService` + `ICurrentTenantService`), `string` type for date fields
|
|
82
90
|
|
|
83
91
|
---
|
|
84
92
|
|
|
@@ -101,8 +109,16 @@
|
|
|
101
109
|
|
|
102
110
|
**Rules:**
|
|
103
111
|
- `[RequirePermission(Permissions.{Module}.{Action})]` on EVERY endpoint
|
|
112
|
+
- **NavRoute values MUST use kebab-case for ALL multi-word segments:**
|
|
113
|
+
- `[NavRoute("business.human-resources.employees")]` (CORRECT)
|
|
114
|
+
- `[NavRoute("business.humanresources.employees")]` (WRONG — missing hyphens)
|
|
115
|
+
- `[NavRoute("business.project-management.projects")]` (CORRECT)
|
|
116
|
+
- `[NavRoute("business.projectmanagement.projects")]` (WRONG)
|
|
104
117
|
- Permission paths MUST use kebab-case matching NavRoute codes (e.g., `business.human-resources.employees.read`)
|
|
105
118
|
- FORBIDDEN: concatenated segments like `humanresources` — must be `human-resources`
|
|
119
|
+
- POST-CHECK 48 detects non-kebab-case NavRoute values. POST-CHECK 41 detects non-kebab-case permissions.
|
|
120
|
+
- **FORBIDDEN:** `[Route("api/...")]` alongside `[NavRoute]` — causes 404s (POST-CHECK 50)
|
|
121
|
+
- `[NavRoute]` is the ONLY route attribute needed — resolves routes from DB at startup
|
|
106
122
|
- NEVER use `[Authorize]` without specific permission
|
|
107
123
|
- Swagger XML documentation
|
|
108
124
|
- Return DTOs, never domain entities
|
|
@@ -194,6 +194,79 @@ These values are propagated to:
|
|
|
194
194
|
|
|
195
195
|
---
|
|
196
196
|
|
|
197
|
+
## 5d. Scope Complexity Guard (BLOCKING)
|
|
198
|
+
|
|
199
|
+
> **Root cause (test-apex-007):** `/apex` was invoked with 3 applications and 7 entities.
|
|
200
|
+
> The model's context window saturated, causing: incomplete migrations, lost conventions,
|
|
201
|
+
> missing pages, unregistered i18n, forgotten DI registrations.
|
|
202
|
+
>
|
|
203
|
+
> `/apex` is designed for **incremental** development (1 module at a time).
|
|
204
|
+
> Multi-module projects should use `/ralph-loop` which calls `/apex -d` per module.
|
|
205
|
+
|
|
206
|
+
### Scope Detection
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
entity_count = {entities}.length
|
|
210
|
+
section_count = {sections}.length
|
|
211
|
+
app_count = number of DISTINCT applications detected in {task_description}
|
|
212
|
+
(heuristics: "application X et application Y", "module X, module Y, module Z"
|
|
213
|
+
with different app names, "3 apps", etc.)
|
|
214
|
+
|
|
215
|
+
scope_score = entity_count + (section_count * 0.5) + (app_count * 3)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Guard Rules
|
|
219
|
+
|
|
220
|
+
```
|
|
221
|
+
IF delegate_mode (-d flag):
|
|
222
|
+
→ SKIP guard (ralph-loop already handles scope per module)
|
|
223
|
+
|
|
224
|
+
ELSE IF app_count > 1:
|
|
225
|
+
→ BLOCKING: "Multiple applications detected ({app_count} apps, {entity_count} entities).
|
|
226
|
+
/apex handles 1 module at a time. For multi-module projects, use:
|
|
227
|
+
- /ralph-loop (automated: reads PRD, generates all modules sequentially)
|
|
228
|
+
- Multiple /apex calls (manual: one /apex per module)
|
|
229
|
+
|
|
230
|
+
To override this guard, split your request:
|
|
231
|
+
/apex -e add HR employee management
|
|
232
|
+
/apex -e add CRM client management
|
|
233
|
+
/apex -e add Project management"
|
|
234
|
+
|
|
235
|
+
ELSE IF scope_score > 8:
|
|
236
|
+
→ WARNING: "Large scope detected ({entity_count} entities, {section_count} sections).
|
|
237
|
+
/apex works best with ≤ 4 entities per invocation.
|
|
238
|
+
Consider splitting into smaller iterations.
|
|
239
|
+
Proceeding, but expect higher risk of omissions."
|
|
240
|
+
|
|
241
|
+
AskUserQuestion:
|
|
242
|
+
header: "Scope"
|
|
243
|
+
question: "Le périmètre est large ({entity_count} entités). Réduire le scope ou continuer ?"
|
|
244
|
+
options:
|
|
245
|
+
- label: "Continue anyway"
|
|
246
|
+
description: "Proceed with full scope (higher risk of omissions)"
|
|
247
|
+
- label: "Split into iterations"
|
|
248
|
+
description: "Focus on the first module/app, then run /apex again for the rest"
|
|
249
|
+
- label: "Use /ralph-loop"
|
|
250
|
+
description: "Switch to /ralph-loop for automated multi-module orchestration"
|
|
251
|
+
|
|
252
|
+
IF "Split" → ask user which module to focus on first, update {entities}/{sections}
|
|
253
|
+
IF "/ralph-loop" → display command to run, STOP execution
|
|
254
|
+
|
|
255
|
+
ELSE:
|
|
256
|
+
→ PASS (scope is manageable)
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Recommended Scope per /apex Invocation
|
|
260
|
+
|
|
261
|
+
| Metric | Safe | Warning | Blocking |
|
|
262
|
+
|--------|------|---------|----------|
|
|
263
|
+
| Applications | 1 | 1 (large) | >1 |
|
|
264
|
+
| Entities | 1-4 | 5-6 | >6 without -d |
|
|
265
|
+
| Sections | 1-3 | 4-5 | >5 without -d |
|
|
266
|
+
| Sub-resources | 0-2 | 3-4 | >4 without -d |
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
197
270
|
## 6. Determine Needs
|
|
198
271
|
|
|
199
272
|
```
|
|
@@ -211,6 +211,27 @@ Cross-reference with step-00 challenge responses:
|
|
|
211
211
|
|
|
212
212
|
---
|
|
213
213
|
|
|
214
|
+
## 5b. Scope Re-Check (after exploration)
|
|
215
|
+
|
|
216
|
+
> **Re-validate scope after code exploration reveals the true entity count.**
|
|
217
|
+
> Step-00 guard uses the user's description (may undercount). Now we know the actual entities.
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
IF NOT delegate_mode:
|
|
221
|
+
actual_entities = count of entities marked "create" in gap analysis
|
|
222
|
+
actual_sections = count of sections marked "create"
|
|
223
|
+
|
|
224
|
+
IF actual_entities > 6:
|
|
225
|
+
WARNING: "Code exploration reveals {actual_entities} entities to create.
|
|
226
|
+
This exceeds the recommended maximum (4) for a single /apex invocation.
|
|
227
|
+
Risk: incomplete migrations, lost conventions, missing pages.
|
|
228
|
+
Consider: split into {ceil(actual_entities/4)} iterations of ~4 entities each."
|
|
229
|
+
|
|
230
|
+
AskUserQuestion: (same options as step-00 section 5d)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
214
235
|
## 6. Analysis Validation (User Checkpoint)
|
|
215
236
|
|
|
216
237
|
> **Objective:** Present findings and validate scope with the user BEFORE planning.
|
|
@@ -44,16 +44,26 @@ For each entity:
|
|
|
44
44
|
|
|
45
45
|
### Migration (BLOCKING)
|
|
46
46
|
|
|
47
|
+
> **CRITICAL — Migration must cover ALL entities, not just the first batch.**
|
|
48
|
+
> Root cause (test-apex-007): Migration was created once for 3 entities, then 4 more entities
|
|
49
|
+
> were added later without re-running migration → 4 entities had no database tables.
|
|
50
|
+
> **RULE:** Create/update migration AFTER ALL entities and EF configs are registered in DbContext.
|
|
51
|
+
> If entities are added incrementally, create a NEW migration for each batch.
|
|
52
|
+
|
|
47
53
|
```
|
|
48
|
-
1.
|
|
49
|
-
2.
|
|
50
|
-
3.
|
|
54
|
+
1. Verify ALL entities have been added as DbSet in ExtensionsDbContext
|
|
55
|
+
2. Verify ALL EF configurations are registered (ApplyConfigurationsFromAssembly or individual)
|
|
56
|
+
3. MCP suggest_migration → get standardized name
|
|
57
|
+
4. dotnet ef migrations add {Name} --project src/{Infra}.csproj --startup-project src/{Api}.csproj -o Persistence/Migrations
|
|
58
|
+
5. Cleanup corrupted EF Core artifacts:
|
|
51
59
|
for d in src/*/bin?Debug; do [ -d "$d" ] && rm -rf "$d"; done
|
|
52
|
-
|
|
53
|
-
|
|
60
|
+
6. dotnet ef database update (if local DB)
|
|
61
|
+
7. dotnet build → MUST PASS
|
|
62
|
+
8. Verify: dotnet ef migrations has-pending-model-changes → MUST report "No pending model changes"
|
|
54
63
|
```
|
|
55
64
|
|
|
56
65
|
**BLOCKING:** If build fails after migration, fix EF configs before proceeding.
|
|
66
|
+
**BLOCKING:** If `has-pending-model-changes` reports pending changes, entities are missing from the migration — create a new migration.
|
|
57
67
|
|
|
58
68
|
### Post-Layer 0 Build Gate
|
|
59
69
|
|
|
@@ -67,10 +77,66 @@ dotnet build
|
|
|
67
77
|
|
|
68
78
|
## Layer 1 — Application + API + Seed Data
|
|
69
79
|
|
|
80
|
+
### NavRoute and Permission Kebab-Case (CRITICAL)
|
|
81
|
+
|
|
82
|
+
> **ALL NavRoute segments and permission codes MUST use kebab-case for multi-word identifiers.**
|
|
83
|
+
> Root cause (test-apex-007): Controllers had `[NavRoute("business.humanresources.employees")]`
|
|
84
|
+
> instead of `[NavRoute("business.human-resources.employees")]`. This mismatched seed data routes
|
|
85
|
+
> and permission codes, causing 404s and permission denials at runtime.
|
|
86
|
+
|
|
87
|
+
**Rules:**
|
|
88
|
+
- NavRoute: `business.human-resources.employees` (NEVER `business.humanresources.employees`)
|
|
89
|
+
- Permissions: `business.human-resources.employees.read` (segments MATCH NavRoute exactly)
|
|
90
|
+
- Seed data codes: `human-resources` (NEVER `humanresources`)
|
|
91
|
+
- C# class names stay PascalCase (`HumanResourcesController`) — only route/permission strings use kebab-case
|
|
92
|
+
- POST-CHECKs 41 + 48 validate this. Fix BEFORE committing.
|
|
93
|
+
|
|
94
|
+
### Controller Route Attribute (BLOCKING)
|
|
95
|
+
|
|
96
|
+
> **Controllers with `[NavRoute]` must NOT have `[Route]` attribute.**
|
|
97
|
+
> Root cause (test-apex-007): ALL 7 controllers had BOTH `[Route("api/...")]` AND `[NavRoute("...")]`.
|
|
98
|
+
> In SmartStack, `[NavRoute]` resolves routes dynamically from Navigation entities in the database at startup.
|
|
99
|
+
> Having `[Route]` alongside causes route conflicts → all endpoints return 404.
|
|
100
|
+
|
|
101
|
+
**Rules:**
|
|
102
|
+
- `[NavRoute("context.app.module")]` is the ONLY route attribute needed on controllers
|
|
103
|
+
- **FORBIDDEN:** `[Route("api/business/human-resources/employees")]` alongside `[NavRoute]`
|
|
104
|
+
- **FORBIDDEN:** `[Route("api/[controller]")]` alongside `[NavRoute]`
|
|
105
|
+
- If generating via MCP `scaffold_extension` with `navRoute` option → output is correct (NavRoute only)
|
|
106
|
+
- If generating via `/controller` skill → verify NO `[Route]` is added
|
|
107
|
+
- POST-CHECK 50 validates this. Fix BEFORE committing.
|
|
108
|
+
|
|
109
|
+
### Validators DI Registration (CRITICAL)
|
|
110
|
+
|
|
111
|
+
> After creating validators, they MUST be registered in DI. Without registration, `[FromBody]` DTOs are never validated.
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
In DependencyInjection.cs (or ServiceCollectionExtensions.cs):
|
|
115
|
+
services.AddValidatorsFromAssemblyContaining<Create{Entity}DtoValidator>();
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
POST-CHECK 46 validates this. If validators exist but no DI registration → BLOCKING.
|
|
119
|
+
|
|
70
120
|
### If economy_mode: Sequential execution
|
|
71
121
|
|
|
72
122
|
Execute each item from the plan sequentially using skills and MCP.
|
|
73
123
|
|
|
124
|
+
### Date Fields — Use DateOnly (CRITICAL)
|
|
125
|
+
|
|
126
|
+
> **ALL date-only fields in DTOs MUST use `DateOnly`, NEVER `string`.**
|
|
127
|
+
> Root cause (test-apex-007): WorkLog DTO had `string Date` instead of `DateOnly Date`.
|
|
128
|
+
> This causes: no date validation, inconsistent date formats, parsing errors.
|
|
129
|
+
|
|
130
|
+
**Type mapping for DTOs:**
|
|
131
|
+
| Domain type | DTO type | Example |
|
|
132
|
+
|-------------|----------|---------|
|
|
133
|
+
| `DateTime` | `DateTime` | `CreatedAt`, `UpdatedAt` |
|
|
134
|
+
| Date-only field | `DateOnly` | `Date`, `StartDate`, `EndDate`, `BirthDate` |
|
|
135
|
+
| `string` for date | **FORBIDDEN** | Never use `string` for dates |
|
|
136
|
+
| `DateTime` for date-only | **Avoid** | Use `DateOnly` when no time component needed |
|
|
137
|
+
|
|
138
|
+
POST-CHECK 47 validates this. If a DTO has `string` type for a property named `*Date*` → BLOCKING.
|
|
139
|
+
|
|
74
140
|
### Code Generation (if entities have codePattern != "manual")
|
|
75
141
|
|
|
76
142
|
For each entity with auto-generated code pattern (from feature.json or step-02 decisions):
|
|
@@ -114,6 +180,7 @@ Code stays in CreateDto, user provides it, validator has regex rule.
|
|
|
114
180
|
- A dead link (navigate to a route with no page) is a BLOCKING issue (POST-CHECK 42)
|
|
115
181
|
- Read `references/smartstack-frontend.md` for mandatory patterns (sections 3b + 8)
|
|
116
182
|
- Generate i18n JSON files for all 4 languages (fr, en, it, de) — `src/i18n/locales/{lang}/{module}.json`
|
|
183
|
+
- **I18n REGISTRATION (CRITICAL):** After creating i18n JSON files, register EACH new namespace in the i18n config file (config.ts/index.ts/i18n.ts). Unregistered namespaces → `useTranslation(['module'])` returns empty strings at runtime. POST-CHECK 45 validates this.
|
|
117
184
|
- All pages must follow loading → error → content pattern with CSS variables
|
|
118
185
|
|
|
119
186
|
### If NOT economy_mode: Agent Teams (parallel)
|