@atlashub/smartstack-cli 3.37.0 → 3.39.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 +16 -24
- package/dist/index.js.map +1 -1
- package/dist/mcp-entry.mjs +235 -265
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -1
- package/scripts/extract-api-endpoints.ts +5 -5
- package/scripts/generate-doc-with-mock-ui.ts +10 -17
- package/templates/agents/ba-reader.md +9 -9
- package/templates/agents/ba-writer.md +12 -15
- package/templates/agents/code-reviewer.md +1 -1
- package/templates/agents/docs-context-reader.md +1 -1
- package/templates/agents/efcore/scan.md +3 -1
- package/templates/agents/gitflow/commit.md +74 -0
- package/templates/agents/gitflow/finish.md +5 -2
- package/templates/agents/gitflow/init-clone.md +3 -3
- package/templates/agents/gitflow/init-validate.md +3 -2
- package/templates/agents/gitflow/merge.md +5 -4
- package/templates/agents/gitflow/pr.md +5 -4
- package/templates/agents/gitflow/start.md +37 -5
- package/templates/hooks/hooks.json +11 -0
- package/templates/hooks/wsl-dotnet-cleanup.sh +24 -0
- package/templates/mcp-scaffolding/frontend/nav-routes.ts.hbs +20 -20
- package/templates/mcp-scaffolding/frontend/routes.tsx.hbs +16 -24
- package/templates/mcp-scaffolding/migrations/seed-roles.cs.hbs +2 -2
- package/templates/skills/_resources/mcp-validate-documentation-spec.md +3 -3
- package/templates/skills/_shared.md +15 -17
- package/templates/skills/ai-prompt/SKILL.md +1 -1
- package/templates/skills/ai-prompt/steps/step-00-init.md +47 -0
- package/templates/skills/apex/SKILL.md +3 -4
- package/templates/skills/apex/_shared.md +10 -20
- package/templates/skills/apex/references/analysis-methods.md +141 -0
- package/templates/skills/apex/references/challenge-questions.md +1 -21
- package/templates/skills/apex/references/core-seed-data.md +35 -58
- package/templates/skills/apex/references/examine-build-validation.md +82 -0
- package/templates/skills/apex/references/execution-frontend-gates.md +177 -0
- package/templates/skills/apex/references/execution-frontend-patterns.md +105 -0
- package/templates/skills/apex/references/execution-layer1-rules.md +96 -0
- package/templates/skills/apex/references/initialization-challenge-flow.md +110 -0
- package/templates/skills/apex/references/planning-layer-mapping.md +151 -0
- package/templates/skills/apex/references/post-checks.md +145 -40
- package/templates/skills/apex/references/smartstack-api.md +35 -51
- package/templates/skills/apex/references/smartstack-frontend.md +18 -18
- package/templates/skills/apex/references/smartstack-layers.md +38 -62
- package/templates/skills/apex/steps/step-00-init.md +14 -26
- package/templates/skills/apex/steps/step-01-analyze.md +10 -143
- package/templates/skills/apex/steps/step-02-plan.md +10 -92
- package/templates/skills/apex/steps/step-03-execute.md +45 -252
- package/templates/skills/apex/steps/step-04-examine.md +14 -78
- package/templates/skills/apex/steps/step-05-deep-review.md +2 -2
- package/templates/skills/apex/steps/step-08-run-tests.md +1 -0
- package/templates/skills/application/SKILL.md +241 -242
- package/templates/skills/application/references/backend-controller-hierarchy.md +16 -16
- package/templates/skills/application/references/backend-seeding-and-dto-output.md +83 -0
- package/templates/skills/application/references/backend-table-prefix-mapping.md +79 -0
- package/templates/skills/application/references/backend-verification.md +1 -1
- package/templates/skills/application/references/frontend-i18n-and-output.md +67 -0
- package/templates/skills/application/references/frontend-route-naming.md +117 -0
- package/templates/skills/application/references/frontend-route-wiring-app-tsx.md +107 -0
- package/templates/skills/application/references/frontend-verification.md +12 -12
- package/templates/skills/application/references/init-parameter-detection.md +121 -0
- package/templates/skills/application/references/migration-checklist-troubleshooting.md +100 -0
- package/templates/skills/application/references/nav-fallback-procedure.md +199 -200
- package/templates/skills/application/references/provider-template.md +2 -6
- package/templates/skills/application/references/roles-client-project-handling.md +55 -0
- package/templates/skills/application/references/roles-fallback-procedure.md +149 -0
- package/templates/skills/application/references/test-coverage-requirements.md +213 -0
- package/templates/skills/application/references/test-frontend.md +3 -3
- package/templates/skills/application/steps/step-00-init.md +130 -260
- package/templates/skills/application/steps/step-01-navigation.md +170 -170
- package/templates/skills/application/steps/step-02-permissions.md +196 -196
- package/templates/skills/application/steps/step-03-roles.md +182 -339
- package/templates/skills/application/steps/step-03b-provider.md +133 -134
- package/templates/skills/application/steps/step-04-backend.md +174 -265
- package/templates/skills/application/steps/step-05-frontend.md +18 -144
- package/templates/skills/application/steps/step-06-migration.md +12 -60
- package/templates/skills/application/steps/step-07-tests.md +9 -76
- package/templates/skills/application/templates-backend.md +29 -27
- package/templates/skills/application/templates-frontend.md +49 -49
- package/templates/skills/application/templates-seed.md +57 -131
- package/templates/skills/business-analyse/SKILL.md +27 -30
- package/templates/skills/business-analyse/_architecture.md +6 -6
- package/templates/skills/business-analyse/_shared.md +60 -88
- package/templates/skills/business-analyse/questionnaire/04-data.md +3 -3
- package/templates/skills/business-analyse/questionnaire/06-security.md +1 -1
- package/templates/skills/business-analyse/questionnaire/13-cross-module.md +1 -1
- package/templates/skills/business-analyse/react/application-viewer.md +12 -12
- package/templates/skills/business-analyse/react/components.md +8 -12
- package/templates/skills/business-analyse/react/schema.md +836 -836
- package/templates/skills/business-analyse/references/agent-module-prompt.md +2 -3
- package/templates/skills/business-analyse/references/analysis-semantic-checks.md +190 -0
- package/templates/skills/business-analyse/references/cache-warming-strategy.md +2 -2
- package/templates/skills/business-analyse/references/cadrage-challenge-patterns.md +41 -0
- package/templates/skills/business-analyse/references/cadrage-coverage-matrix.md +74 -0
- package/templates/skills/business-analyse/references/cadrage-shared-modules.md +69 -0
- package/templates/skills/business-analyse/references/cadrage-structure-cards.md +1 -1
- package/templates/skills/business-analyse/references/compilation-structure-cards.md +297 -0
- package/templates/skills/business-analyse/references/consolidation-structural-checks.md +2 -2
- package/templates/skills/business-analyse/references/deploy-modes.md +5 -5
- package/templates/skills/business-analyse/references/detection-strategies.md +7 -7
- package/templates/skills/business-analyse/references/handoff-file-templates.md +14 -22
- package/templates/skills/business-analyse/references/handoff-mappings.md +4 -4
- package/templates/skills/business-analyse/references/handoff-seeddata-generation.md +312 -0
- package/templates/skills/business-analyse/references/init-schema-deployment.md +3 -3
- package/templates/skills/business-analyse/references/naming-conventions.md +22 -24
- package/templates/skills/business-analyse/references/prd-generation.md +2 -2
- package/templates/skills/business-analyse/references/review-data-mapping.md +2 -2
- package/templates/skills/business-analyse/references/robustness-checks.md +1 -1
- package/templates/skills/business-analyse/references/spec-auto-inference.md +3 -3
- package/templates/skills/business-analyse/references/team-orchestration.md +49 -6
- package/templates/skills/business-analyse/references/ui-dashboard-spec.md +1 -1
- package/templates/skills/business-analyse/references/ui-resource-cards.md +18 -18
- package/templates/skills/business-analyse/references/validate-incremental-html.md +2 -2
- package/templates/skills/business-analyse/references/validation-checklist.md +2 -2
- package/templates/skills/business-analyse/schemas/application-schema.json +4 -5
- package/templates/skills/business-analyse/schemas/project-schema.json +1 -6
- package/templates/skills/business-analyse/schemas/sections/metadata-schema.json +2 -3
- package/templates/skills/business-analyse/schemas/sections/specification-schema.json +4 -4
- package/templates/skills/business-analyse/steps/step-00-init.md +8 -17
- package/templates/skills/business-analyse/steps/step-01-cadrage.md +35 -198
- package/templates/skills/business-analyse/steps/step-01b-applications.md +16 -20
- package/templates/skills/business-analyse/steps/step-02-decomposition.md +1 -1
- package/templates/skills/business-analyse/steps/step-03a1-setup.md +4 -4
- package/templates/skills/business-analyse/steps/step-03a2-analysis.md +1 -1
- package/templates/skills/business-analyse/steps/step-03b-ui.md +4 -4
- package/templates/skills/business-analyse/steps/step-03c-compile.md +66 -140
- package/templates/skills/business-analyse/steps/step-03d-validate.md +2 -2
- package/templates/skills/business-analyse/steps/step-04a-collect.md +2 -2
- package/templates/skills/business-analyse/steps/step-04b-analyze.md +42 -160
- package/templates/skills/business-analyse/steps/step-04c-decide.md +1 -1
- package/templates/skills/business-analyse/steps/step-05a-handoff.md +74 -104
- package/templates/skills/business-analyse/steps/step-05b-deploy.md +13 -11
- package/templates/skills/business-analyse/steps/step-06-review.md +3 -3
- package/templates/skills/business-analyse/templates/tpl-frd.md +13 -13
- package/templates/skills/business-analyse/templates/tpl-handoff.md +12 -12
- package/templates/skills/business-analyse/templates/tpl-progress.md +1 -1
- package/templates/skills/business-analyse/templates-frd.md +25 -25
- package/templates/skills/business-analyse/templates-react.md +15 -21
- package/templates/skills/controller/SKILL.md +1 -1
- package/templates/skills/controller/postman-templates.md +1 -1
- package/templates/skills/controller/references/controller-code-templates.md +2 -2
- package/templates/skills/controller/references/mcp-scaffold-workflow.md +209 -0
- package/templates/skills/controller/references/permission-sync-templates.md +13 -16
- package/templates/skills/controller/steps/step-00-init.md +11 -11
- package/templates/skills/controller/steps/step-03-generate.md +64 -103
- package/templates/skills/controller/templates.md +67 -71
- package/templates/skills/debug/SKILL.md +13 -218
- package/templates/skills/debug/steps/step-00-init.md +57 -0
- package/templates/skills/debug/steps/step-01-analyze.md +219 -0
- package/templates/skills/debug/steps/step-02-resolve.md +85 -0
- package/templates/skills/documentation/SKILL.md +49 -345
- package/templates/skills/documentation/data-schema.md +11 -8
- package/templates/skills/documentation/steps/step-00-init.md +70 -0
- package/templates/skills/documentation/steps/step-01-scan.md +113 -0
- package/templates/skills/documentation/steps/step-02-generate.md +231 -0
- package/templates/skills/documentation/steps/step-03-validate.md +238 -0
- package/templates/skills/documentation/templates.md +480 -322
- package/templates/skills/efcore/SKILL.md +1 -1
- package/templates/skills/efcore/references/both-contexts.md +32 -0
- package/templates/skills/efcore/references/database-operations.md +67 -0
- package/templates/skills/efcore/references/destructive-operations.md +38 -0
- package/templates/skills/efcore/references/reset-operations.md +81 -0
- package/templates/skills/efcore/references/seed-methods.md +86 -0
- package/templates/skills/efcore/references/shared-init-functions.md +250 -0
- package/templates/skills/efcore/references/sql-objects-injection.md +61 -0
- package/templates/skills/efcore/references/troubleshooting.md +81 -0
- package/templates/skills/efcore/steps/db/step-deploy.md +1 -32
- package/templates/skills/efcore/steps/db/step-reset.md +7 -103
- package/templates/skills/efcore/steps/db/step-seed.md +10 -132
- package/templates/skills/efcore/steps/db/step-status.md +5 -44
- package/templates/skills/efcore/steps/migration/step-02-create.md +1 -14
- package/templates/skills/efcore/steps/migration/step-03-validate.md +8 -62
- package/templates/skills/efcore/steps/rebase-snapshot/step-03-create.md +1 -57
- package/templates/skills/efcore/steps/shared/step-00-init.md +11 -254
- package/templates/skills/efcore/steps/squash/step-03-create.md +1 -58
- package/templates/skills/feature-full/SKILL.md +1 -1
- package/templates/skills/feature-full/steps/step-00-init.md +57 -0
- package/templates/skills/feature-full/steps/step-01-implementation.md +1 -1
- package/templates/skills/gitflow/SKILL.md +28 -5
- package/templates/skills/gitflow/_shared.md +109 -12
- package/templates/skills/gitflow/phases/abort.md +4 -0
- package/templates/skills/gitflow/phases/cleanup.md +4 -0
- package/templates/skills/gitflow/references/commit-message-generation.md +58 -0
- package/templates/skills/gitflow/references/commit-migration-validation.md +49 -0
- package/templates/skills/gitflow/references/finish-cleanup.md +55 -0
- package/templates/skills/gitflow/references/finish-version-bumping.md +45 -0
- package/templates/skills/gitflow/references/init-environment-detection.md +41 -0
- package/templates/skills/gitflow/references/init-questions.md +185 -0
- package/templates/skills/gitflow/references/init-structure-creation.md +75 -0
- package/templates/skills/gitflow/references/init-version-detection.md +21 -0
- package/templates/skills/gitflow/references/init-workspace-detection.md +43 -0
- package/templates/skills/gitflow/references/merge-ci-status.md +36 -0
- package/templates/skills/gitflow/references/merge-execution.md +62 -0
- package/templates/skills/gitflow/references/merge-pr-context.md +76 -0
- package/templates/skills/gitflow/references/pr-build-checks.md +60 -0
- package/templates/skills/gitflow/references/pr-generation.md +58 -0
- package/templates/skills/gitflow/references/start-branch-normalization.md +28 -0
- package/templates/skills/gitflow/references/start-worktree-creation.md +50 -0
- package/templates/skills/gitflow/references/sync-push-verify.md +44 -0
- package/templates/skills/gitflow/references/sync-rebase-conflicts.md +38 -0
- package/templates/skills/gitflow/steps/step-commit.md +12 -91
- package/templates/skills/gitflow/steps/step-finish.md +15 -159
- package/templates/skills/gitflow/steps/step-init.md +24 -326
- package/templates/skills/gitflow/steps/step-merge.md +17 -176
- package/templates/skills/gitflow/steps/step-pr.md +10 -116
- package/templates/skills/gitflow/steps/step-start.md +16 -109
- package/templates/skills/gitflow/steps/step-sync.md +6 -69
- package/templates/skills/ralph-loop/SKILL.md +6 -0
- package/templates/skills/ralph-loop/references/category-completeness.md +185 -0
- package/templates/skills/ralph-loop/references/compact-loop.md +1 -1
- package/templates/skills/ralph-loop/references/init-resume-recovery.md +127 -0
- package/templates/skills/ralph-loop/references/module-transition.md +151 -0
- package/templates/skills/ralph-loop/references/multi-module-queue.md +171 -0
- package/templates/skills/ralph-loop/references/parallel-execution.md +246 -0
- package/templates/skills/ralph-loop/references/task-transform-legacy.md +6 -9
- package/templates/skills/ralph-loop/references/team-orchestration.md +45 -3
- package/templates/skills/ralph-loop/steps/step-00-init.md +36 -109
- package/templates/skills/ralph-loop/steps/step-01-task.md +15 -163
- package/templates/skills/ralph-loop/steps/step-02-execute.md +8 -154
- package/templates/skills/ralph-loop/steps/step-04-check.md +20 -73
- package/templates/skills/review-code/references/owasp-api-top10.md +5 -5
- package/templates/skills/review-code/references/smartstack-conventions.md +568 -568
- package/templates/skills/validate-feature/references/api-smoke-tests.md +140 -0
- package/templates/skills/validate-feature/references/db-validation-checks.md +180 -0
- package/templates/skills/validate-feature/steps/step-01-compile.md +1 -3
- package/templates/skills/validate-feature/steps/step-04-api-smoke.md +34 -145
- package/templates/skills/validate-feature/steps/step-05-db-validation.md +74 -260
- package/templates/skills/workflow/SKILL.md +1 -1
- package/templates/skills/workflow/steps/step-00-init.md +57 -0
|
@@ -1,568 +1,568 @@
|
|
|
1
|
-
<overview>
|
|
2
|
-
SmartStack-specific conventions and patterns. This reference is used when reviewing SmartStack projects to ensure compliance with the architecture and security standards.
|
|
3
|
-
|
|
4
|
-
**IMPORTANT**: All convention validation MUST be delegated to the MCP SmartStack tools. This file documents what to look for; the MCP validates automatically.
|
|
5
|
-
</overview>
|
|
6
|
-
|
|
7
|
-
<mcp_tools>
|
|
8
|
-
## MCP SmartStack Tools for Code Review
|
|
9
|
-
|
|
10
|
-
### Primary Tool - Unified Code Review
|
|
11
|
-
|
|
12
|
-
| Tool | Purpose | When to use |
|
|
13
|
-
|------|---------|-------------|
|
|
14
|
-
| `mcp__smartstack__review_code` | **Unified code review** covering 9 categories | Always use first |
|
|
15
|
-
|
|
16
|
-
**Parameters:**
|
|
17
|
-
```
|
|
18
|
-
scope: "all" | "changed" | "staged" # Which files to review
|
|
19
|
-
checks: ["all"] | ["security", ...] # Categories to check
|
|
20
|
-
severity: "all" | "blocking" # Filter by severity
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
**Categories covered:**
|
|
24
|
-
| Category | ID Prefix | Severity | What it detects |
|
|
25
|
-
|----------|-----------|----------|-----------------|
|
|
26
|
-
| Security | SEC-xxx | blocking | Secrets, SQL injection, XSS, missing [Authorize] |
|
|
27
|
-
| Architecture | ARCH-xxx | critical | Layer violations, DI bypass |
|
|
28
|
-
| Hardcoded Values | HARD-xxx | warning | Magic numbers, URLs, feature flags |
|
|
29
|
-
| Tests | TEST-xxx | critical | Missing tests, useless assertions |
|
|
30
|
-
| AI Hallucinations | AI-xxx | blocking | Phantom imports, non-existent methods |
|
|
31
|
-
| Performance | PERF-xxx | warning | N+1 queries, over-fetching |
|
|
32
|
-
| Dead Code | DEAD-xxx | warning | Unused imports, commented code, TODOs |
|
|
33
|
-
| i18n | I18N-xxx | info | Hardcoded UI text, missing translations |
|
|
34
|
-
| Accessibility | A11Y-xxx | info | Missing alt, ARIA, focus issues |
|
|
35
|
-
|
|
36
|
-
### Additional Tools (Optional)
|
|
37
|
-
|
|
38
|
-
| Tool | Purpose | When to use |
|
|
39
|
-
|------|---------|-------------|
|
|
40
|
-
| `mcp__smartstack__validate_conventions` | Detailed conventions validation | Deep convention checks |
|
|
41
|
-
| `mcp__smartstack__validate_test_conventions` | Test patterns validation | Test structure review |
|
|
42
|
-
| `mcp__smartstack__check_migrations` | EF Core migration conflicts | Migration changes |
|
|
43
|
-
</mcp_tools>
|
|
44
|
-
|
|
45
|
-
<architecture>
|
|
46
|
-
## SmartStack Architecture (Clean Architecture)
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
SmartStack/
|
|
50
|
-
├── SmartStack.Domain/ # Entities, Value Objects, Domain Events
|
|
51
|
-
├── SmartStack.Application/ # Services, DTOs, Commands/Queries
|
|
52
|
-
├── SmartStack.Infrastructure/ # EF Core, External services
|
|
53
|
-
├── SmartStack.Api/ # Controllers, Middleware
|
|
54
|
-
└── SmartStack.Web/ # React frontend
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
**Dependency rule**: Dependencies point inward only (Api → Application → Domain).
|
|
58
|
-
</architecture>
|
|
59
|
-
|
|
60
|
-
<entities>
|
|
61
|
-
## Entity Conventions
|
|
62
|
-
|
|
63
|
-
<tenant_aware>
|
|
64
|
-
**Tenant-aware entities** (most business entities):
|
|
65
|
-
```csharp
|
|
66
|
-
public class Order : BaseEntity, ITenantEntity
|
|
67
|
-
{
|
|
68
|
-
public Guid TenantId { get; private set; }
|
|
69
|
-
|
|
70
|
-
private Order() { } // EF Core constructor
|
|
71
|
-
|
|
72
|
-
public static Order Create(Guid tenantId, ...)
|
|
73
|
-
{
|
|
74
|
-
return new Order { TenantId = tenantId, ... };
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
**Requirements:**
|
|
80
|
-
- [ ] Implements `ITenantEntity`
|
|
81
|
-
- [ ] Has `TenantId` property
|
|
82
|
-
- [ ] Private parameterless constructor
|
|
83
|
-
- [ ] Static `Create()` factory method with `tenantId` as first parameter
|
|
84
|
-
</tenant_aware>
|
|
85
|
-
|
|
86
|
-
<system_entity>
|
|
87
|
-
**System entities** (platform-level, no tenant):
|
|
88
|
-
```csharp
|
|
89
|
-
public class Permission : SystemEntity
|
|
90
|
-
{
|
|
91
|
-
private Permission() { }
|
|
92
|
-
|
|
93
|
-
public static Permission Create(...)
|
|
94
|
-
{
|
|
95
|
-
return new Permission { ... };
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
**Requirements:**
|
|
101
|
-
- [ ] Inherits from `SystemEntity`
|
|
102
|
-
- [ ] NO `TenantId` property
|
|
103
|
-
- [ ] Private parameterless constructor
|
|
104
|
-
- [ ] Static `Create()` factory method
|
|
105
|
-
</system_entity>
|
|
106
|
-
</entities>
|
|
107
|
-
|
|
108
|
-
<value_objects>
|
|
109
|
-
## Value Objects (DDD Pattern)
|
|
110
|
-
|
|
111
|
-
Value Objects are immutable types defined by their attributes rather than identity. Use them to replace primitive types that carry domain meaning and validation.
|
|
112
|
-
|
|
113
|
-
**When to use a Value Object:**
|
|
114
|
-
| Instead of | Use | Why |
|
|
115
|
-
|------------|-----|-----|
|
|
116
|
-
| `string Email` | `Email` record | Self-validating, prevents invalid state |
|
|
117
|
-
| `decimal Amount` + `string Currency` | `Money` record | Always consistent pair |
|
|
118
|
-
| `string Street` + `string City` + ... | `Address` record | Cohesive group |
|
|
119
|
-
| `DateTime Start` + `DateTime End` | `DateRange` record | Enforces Start < End invariant |
|
|
120
|
-
|
|
121
|
-
**Structure (C# record):**
|
|
122
|
-
```csharp
|
|
123
|
-
// Domain/ValueObjects/Email.cs
|
|
124
|
-
public sealed record Email
|
|
125
|
-
{
|
|
126
|
-
public string Value { get; }
|
|
127
|
-
|
|
128
|
-
public Email(string value)
|
|
129
|
-
{
|
|
130
|
-
if (string.IsNullOrWhiteSpace(value))
|
|
131
|
-
throw new DomainException("Email is required");
|
|
132
|
-
if (!value.Contains('@'))
|
|
133
|
-
throw new DomainException("Invalid email format");
|
|
134
|
-
|
|
135
|
-
Value = value.Trim().ToLowerInvariant();
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
public static implicit operator string(Email email) => email.Value;
|
|
139
|
-
public override string ToString() => Value;
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
**EF Core mapping:**
|
|
144
|
-
```csharp
|
|
145
|
-
// Option 1: Owned type (separate columns)
|
|
146
|
-
builder.OwnsOne(e => e.Email, email =>
|
|
147
|
-
{
|
|
148
|
-
email.Property(v => v.Value).HasColumnName("Email").HasMaxLength(256);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
// Option 2: Value conversion (single column)
|
|
152
|
-
builder.Property(e => e.Email)
|
|
153
|
-
.HasConversion(
|
|
154
|
-
v => v.Value,
|
|
155
|
-
v => new Email(v))
|
|
156
|
-
.HasMaxLength(256);
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
**Entity vs Value Object:**
|
|
160
|
-
| Criteria | Entity | Value Object |
|
|
161
|
-
|----------|--------|-------------|
|
|
162
|
-
| Identity | Has `Id` (Guid) | No identity |
|
|
163
|
-
| Equality | By Id | By all properties |
|
|
164
|
-
| Mutability | Mutable (behavior methods) | Immutable (records) |
|
|
165
|
-
| Lifecycle | Independent | Owned by entity |
|
|
166
|
-
| Example | `User`, `Order` | `Email`, `Money`, `Address` |
|
|
167
|
-
|
|
168
|
-
**Code review detection:** If an entity has `string Email`, `string Phone`, `decimal Amount` + `string Currency` as separate primitives, suggest replacing with Value Objects.
|
|
169
|
-
</value_objects>
|
|
170
|
-
|
|
171
|
-
<domain_events>
|
|
172
|
-
## Domain Events
|
|
173
|
-
|
|
174
|
-
Domain Events capture something that happened in the domain. They enable decoupled communication between aggregates and complement the existing Workflow trigger system.
|
|
175
|
-
|
|
176
|
-
**Relationship with Workflow Triggers:**
|
|
177
|
-
| Mechanism | Scope | Use case |
|
|
178
|
-
|-----------|-------|----------|
|
|
179
|
-
| Domain Events (MediatR) | In-process, synchronous | Cache invalidation, audit logging, read-model updates |
|
|
180
|
-
| Workflow Triggers (`TriggerAsync`) | Cross-process, async | Emails, webhooks, multi-step business processes |
|
|
181
|
-
| **Combined** | Domain Event handler calls `TriggerAsync()` | Best of both worlds |
|
|
182
|
-
|
|
183
|
-
**Structure:**
|
|
184
|
-
```csharp
|
|
185
|
-
// Domain/Events/OrderCreatedEvent.cs
|
|
186
|
-
public sealed record OrderCreatedEvent(
|
|
187
|
-
Guid OrderId,
|
|
188
|
-
Guid TenantId,
|
|
189
|
-
Guid CreatedById,
|
|
190
|
-
DateTime OccurredAt) : IDomainEvent;
|
|
191
|
-
|
|
192
|
-
// Domain/Common/IDomainEvent.cs
|
|
193
|
-
public interface IDomainEvent : INotification { } // MediatR marker
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
**Publishing from entities:**
|
|
197
|
-
```csharp
|
|
198
|
-
public class Order : BaseEntity, ITenantEntity
|
|
199
|
-
{
|
|
200
|
-
private readonly List<IDomainEvent> _domainEvents = new();
|
|
201
|
-
public IReadOnlyList<IDomainEvent> DomainEvents => _domainEvents.AsReadOnly();
|
|
202
|
-
|
|
203
|
-
public static Order Create(Guid tenantId, string description, Guid createdById)
|
|
204
|
-
{
|
|
205
|
-
var order = new Order
|
|
206
|
-
{
|
|
207
|
-
Id = Guid.NewGuid(),
|
|
208
|
-
TenantId = tenantId,
|
|
209
|
-
Description = description
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
order._domainEvents.Add(new OrderCreatedEvent(
|
|
213
|
-
order.Id, tenantId, createdById, DateTime.UtcNow));
|
|
214
|
-
|
|
215
|
-
return order;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
public void ClearDomainEvents() => _domainEvents.Clear();
|
|
219
|
-
}
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
**Handling events:**
|
|
223
|
-
```csharp
|
|
224
|
-
// Application/EventHandlers/OrderCreatedEventHandler.cs
|
|
225
|
-
public class OrderCreatedEventHandler : INotificationHandler<OrderCreatedEvent>
|
|
226
|
-
{
|
|
227
|
-
private readonly IWorkflowService _workflowService;
|
|
228
|
-
private readonly ILogger<OrderCreatedEventHandler> _logger;
|
|
229
|
-
|
|
230
|
-
public async Task Handle(OrderCreatedEvent notification, CancellationToken ct)
|
|
231
|
-
{
|
|
232
|
-
_logger.LogInformation("Order {OrderId} created", notification.OrderId);
|
|
233
|
-
|
|
234
|
-
// Bridge to Workflow triggers for cross-process actions
|
|
235
|
-
await _workflowService.TriggerAsync("order.created",
|
|
236
|
-
new Dictionary<string, object>
|
|
237
|
-
{
|
|
238
|
-
["orderId"] = notification.OrderId,
|
|
239
|
-
["tenantId"] = notification.TenantId
|
|
240
|
-
}, ct: ct);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
**Dispatching (in DbContext):**
|
|
246
|
-
```csharp
|
|
247
|
-
// Infrastructure/Persistence/ApplicationDbContext.cs
|
|
248
|
-
public override async Task<int> SaveChangesAsync(CancellationToken ct = default)
|
|
249
|
-
{
|
|
250
|
-
var entities = ChangeTracker.Entries<BaseEntity>()
|
|
251
|
-
.Where(e => e.Entity.DomainEvents.Any())
|
|
252
|
-
.ToList();
|
|
253
|
-
|
|
254
|
-
var events = entities.SelectMany(e => e.Entity.DomainEvents).ToList();
|
|
255
|
-
|
|
256
|
-
var result = await base.SaveChangesAsync(ct);
|
|
257
|
-
|
|
258
|
-
foreach (var @event in events)
|
|
259
|
-
await _mediator.Publish(@event, ct);
|
|
260
|
-
|
|
261
|
-
foreach (var entity in entities)
|
|
262
|
-
entity.Entity.ClearDomainEvents();
|
|
263
|
-
|
|
264
|
-
return result;
|
|
265
|
-
}
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
**When to add Domain Events (code review check):**
|
|
269
|
-
- Entity has side effects in `Create()` or behavior methods → Domain Event candidate
|
|
270
|
-
- Service calls `TriggerAsync()` right after `SaveChangesAsync()` → Should be Domain Event
|
|
271
|
-
- Multiple services react to the same entity change → Domain Event decouples them
|
|
272
|
-
</domain_events>
|
|
273
|
-
|
|
274
|
-
<tables>
|
|
275
|
-
## Table Naming Conventions
|
|
276
|
-
|
|
277
|
-
**Schema**: All tables MUST specify schema explicitly.
|
|
278
|
-
```csharp
|
|
279
|
-
builder.ToTable("auth_users", SchemaConstants.Core);
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
**Prefixes by domain:**
|
|
283
|
-
| Prefix | Domain | Examples |
|
|
284
|
-
|--------|--------|----------|
|
|
285
|
-
| `auth_` | Authentication | auth_users, auth_roles |
|
|
286
|
-
| `nav_` | Navigation | nav_menus, nav_routes |
|
|
287
|
-
| `cfg_` | Configuration | cfg_settings, cfg_features |
|
|
288
|
-
| `ai_` | AI/Prompts | ai_prompts, ai_models |
|
|
289
|
-
| `ntf_` | Notifications | ntf_templates, ntf_logs |
|
|
290
|
-
| `wkf_` | Workflows | wkf_definitions, wkf_instances |
|
|
291
|
-
| `doc_` | Documents | doc_files, doc_versions |
|
|
292
|
-
| `tkt_` | Tickets/Support | tkt_tickets, tkt_comments |
|
|
293
|
-
|
|
294
|
-
**Custom Application Prefixes:**
|
|
295
|
-
|
|
296
|
-
Business applications define their own table prefix during `/business-analyse` cadrage phase.
|
|
297
|
-
Format: `{2-5 lowercase letters}_` — stored in `feature.json` → `metadata.tablePrefix`.
|
|
298
|
-
|
|
299
|
-
| Application | Prefix | Examples |
|
|
300
|
-
|-------------|--------|----------|
|
|
301
|
-
| Human Resources | `rh_` | rh_Employees, rh_Contracts |
|
|
302
|
-
| Finance | `fi_` | fi_Invoices, fi_Payments |
|
|
303
|
-
| CRM | `crm_` | crm_Contacts, crm_Opportunities |
|
|
304
|
-
|
|
305
|
-
Rules:
|
|
306
|
-
- Must not collide with platform prefixes
|
|
307
|
-
- Registered in MCP config via `conventions.customTablePrefixes`
|
|
308
|
-
- All entities in the same application share the same prefix
|
|
309
|
-
|
|
310
|
-
**Schemas:**
|
|
311
|
-
- `core` (SchemaConstants.Core): SmartStack platform tables
|
|
312
|
-
- `extensions` (SchemaConstants.Extensions): Client-specific tables
|
|
313
|
-
</tables>
|
|
314
|
-
|
|
315
|
-
<migrations>
|
|
316
|
-
## Migration Naming
|
|
317
|
-
|
|
318
|
-
**Format**: `{context}_v{version}_{sequence}_{Description}.cs`
|
|
319
|
-
|
|
320
|
-
**Examples:**
|
|
321
|
-
- `core_v1.0.0_001_CreateAuthUsers.cs`
|
|
322
|
-
- `core_v1.2.0_001_AddUserProfiles.cs`
|
|
323
|
-
- `extensions_v1.0.0_001_CreateClientOrders.cs`
|
|
324
|
-
|
|
325
|
-
**Rules:**
|
|
326
|
-
- [ ] Context: `core` or `extensions`
|
|
327
|
-
- [ ] Version: semver format (1.0.0)
|
|
328
|
-
- [ ] Sequence: 3-digit padded (001, 002)
|
|
329
|
-
- [ ] Description: PascalCase, descriptive
|
|
330
|
-
</migrations>
|
|
331
|
-
|
|
332
|
-
<controllers>
|
|
333
|
-
## Controller Conventions
|
|
334
|
-
|
|
335
|
-
**NavRoute attribute** (preferred):
|
|
336
|
-
```csharp
|
|
337
|
-
[ApiController]
|
|
338
|
-
[NavRoute("
|
|
339
|
-
public class UsersController : ControllerBase // MUST be ControllerBase, NOT Controller
|
|
340
|
-
{
|
|
341
|
-
// Routes generated from NavRoute: /api/
|
|
342
|
-
}
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
**CRITICAL: Controller Inheritance (S6934)**
|
|
346
|
-
|
|
347
|
-
```csharp
|
|
348
|
-
// ❌ BAD - Inheriting from Controller
|
|
349
|
-
public class UsersController : Controller
|
|
350
|
-
{
|
|
351
|
-
// Brings in MVC View support (Razor, ViewData, ViewBag)
|
|
352
|
-
// Unnecessary for API controllers
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// ✅ GOOD - Inheriting from ControllerBase
|
|
356
|
-
public class UsersController : ControllerBase
|
|
357
|
-
{
|
|
358
|
-
// Lightweight, API-only base class
|
|
359
|
-
// No MVC View support (cleaner, more appropriate)
|
|
360
|
-
}
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
**Why ControllerBase?**
|
|
364
|
-
- API controllers don't need MVC View support
|
|
365
|
-
- `Controller` adds unnecessary dependencies (Razor, ViewData, etc.)
|
|
366
|
-
- `ControllerBase` is lighter and more focused on APIs
|
|
367
|
-
- Better performance and smaller footprint
|
|
368
|
-
|
|
369
|
-
**NavRoute format:**
|
|
370
|
-
- Lowercase only
|
|
371
|
-
- Dot-separated hierarchy
|
|
372
|
-
- Minimum
|
|
373
|
-
- Full path: `
|
|
374
|
-
|
|
375
|
-
**Examples:**
|
|
376
|
-
- `
|
|
377
|
-
- `
|
|
378
|
-
- `
|
|
379
|
-
- `
|
|
380
|
-
</controllers>
|
|
381
|
-
|
|
382
|
-
<services>
|
|
383
|
-
## Service Conventions
|
|
384
|
-
|
|
385
|
-
**Interface pattern:**
|
|
386
|
-
```csharp
|
|
387
|
-
// Interface
|
|
388
|
-
public interface IUserService
|
|
389
|
-
{
|
|
390
|
-
Task<UserDto> GetByIdAsync(Guid id, CancellationToken ct);
|
|
391
|
-
Task<UserDto> CreateAsync(CreateUserDto dto, CancellationToken ct);
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
// Implementation
|
|
395
|
-
public class UserService : IUserService
|
|
396
|
-
{
|
|
397
|
-
// ...
|
|
398
|
-
}
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
**Requirements:**
|
|
402
|
-
- [ ] Interface named `I{Name}Service`
|
|
403
|
-
- [ ] Implementation named `{Name}Service`
|
|
404
|
-
- [ ] All methods async with CancellationToken
|
|
405
|
-
- [ ] Return DTOs, not entities
|
|
406
|
-
</services>
|
|
407
|
-
|
|
408
|
-
<security>
|
|
409
|
-
## SmartStack Security Patterns
|
|
410
|
-
|
|
411
|
-
<multi_tenant>
|
|
412
|
-
**Multi-tenant isolation:**
|
|
413
|
-
- ALL queries MUST filter by TenantId (automatic via EF Core global filters)
|
|
414
|
-
- NEVER expose TenantId in URLs
|
|
415
|
-
- NEVER allow cross-tenant data access
|
|
416
|
-
- Create methods MUST require tenantId parameter
|
|
417
|
-
|
|
418
|
-
**Check for violations:**
|
|
419
|
-
```csharp
|
|
420
|
-
// BAD: No tenant filter
|
|
421
|
-
var users = await _context.Users.ToListAsync();
|
|
422
|
-
|
|
423
|
-
// GOOD: Tenant filter applied (via global filter or explicit)
|
|
424
|
-
var users = await _context.Users
|
|
425
|
-
.Where(u => u.TenantId == _tenantId)
|
|
426
|
-
.ToListAsync();
|
|
427
|
-
```
|
|
428
|
-
</multi_tenant>
|
|
429
|
-
|
|
430
|
-
<authorization>
|
|
431
|
-
**RBAC with NavRoute:**
|
|
432
|
-
- Controllers use `[NavRoute]` for automatic permission mapping
|
|
433
|
-
- Permissions follow NavRoute pattern: `{navroute}.{action}`
|
|
434
|
-
- Actions: `read`, `create`, `update`, `delete`, `*` (wildcard)
|
|
435
|
-
|
|
436
|
-
**Example permissions:**
|
|
437
|
-
- `
|
|
438
|
-
- `
|
|
439
|
-
- `
|
|
440
|
-
</authorization>
|
|
441
|
-
|
|
442
|
-
<input_validation>
|
|
443
|
-
**FluentValidation:**
|
|
444
|
-
```csharp
|
|
445
|
-
public class CreateUserDtoValidator : AbstractValidator<CreateUserDto>
|
|
446
|
-
{
|
|
447
|
-
public CreateUserDtoValidator()
|
|
448
|
-
{
|
|
449
|
-
RuleFor(x => x.Email)
|
|
450
|
-
.NotEmpty()
|
|
451
|
-
.EmailAddress()
|
|
452
|
-
.MaximumLength(256);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
```
|
|
456
|
-
</input_validation>
|
|
457
|
-
</security>
|
|
458
|
-
|
|
459
|
-
<tests>
|
|
460
|
-
## Test Conventions
|
|
461
|
-
|
|
462
|
-
**Naming pattern:** `{Method}_When{Condition}_Should{Result}`
|
|
463
|
-
```csharp
|
|
464
|
-
public class UserServiceTests
|
|
465
|
-
{
|
|
466
|
-
[Fact]
|
|
467
|
-
public async Task GetById_WhenUserExists_ShouldReturnUser() { }
|
|
468
|
-
|
|
469
|
-
[Fact]
|
|
470
|
-
public async Task GetById_WhenUserNotFound_ShouldThrowNotFoundException() { }
|
|
471
|
-
|
|
472
|
-
[Fact]
|
|
473
|
-
public async Task Create_WhenValidDto_ShouldCreateAndReturnUser() { }
|
|
474
|
-
}
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
**Structure:**
|
|
478
|
-
```
|
|
479
|
-
Tests/
|
|
480
|
-
├── Unit/
|
|
481
|
-
│ ├── Services/
|
|
482
|
-
│ └── Validators/
|
|
483
|
-
└── Integration/
|
|
484
|
-
└── Controllers/
|
|
485
|
-
```
|
|
486
|
-
|
|
487
|
-
**Patterns:**
|
|
488
|
-
- [ ] AAA pattern (Arrange, Act, Assert)
|
|
489
|
-
- [ ] FluentAssertions for assertions
|
|
490
|
-
- [ ] Moq for mocking
|
|
491
|
-
- [ ] Tenant isolation tests for all tenant-aware services
|
|
492
|
-
</tests>
|
|
493
|
-
|
|
494
|
-
<review_checklist>
|
|
495
|
-
## SmartStack Code Review Checklist
|
|
496
|
-
|
|
497
|
-
**Run unified code review first:**
|
|
498
|
-
```
|
|
499
|
-
mcp__smartstack__review_code
|
|
500
|
-
scope: "changed" # or "all" or "staged"
|
|
501
|
-
checks: ["all"] # 9 categories
|
|
502
|
-
severity: "all"
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
**The tool automatically checks:**
|
|
506
|
-
|
|
507
|
-
<blocking_checks>
|
|
508
|
-
### Blocking Issues (Must fix before merge)
|
|
509
|
-
**Security (SEC-xxx):**
|
|
510
|
-
- Hardcoded credentials or secrets
|
|
511
|
-
- SQL injection patterns
|
|
512
|
-
- XSS vulnerabilities
|
|
513
|
-
- Missing [Authorize] attributes
|
|
514
|
-
|
|
515
|
-
**AI Hallucinations (AI-xxx):**
|
|
516
|
-
- Non-existent imports/namespaces
|
|
517
|
-
- Phantom method calls
|
|
518
|
-
- Undefined types
|
|
519
|
-
</blocking_checks>
|
|
520
|
-
|
|
521
|
-
<critical_checks>
|
|
522
|
-
### Critical Issues (Should fix ASAP)
|
|
523
|
-
**Architecture (ARCH-xxx):**
|
|
524
|
-
- Layer violations (Web → Infrastructure)
|
|
525
|
-
- Direct DbContext usage in controllers
|
|
526
|
-
- Service instantiation instead of DI
|
|
527
|
-
|
|
528
|
-
**Tests (TEST-xxx):**
|
|
529
|
-
- Missing tests for new entities/services
|
|
530
|
-
- Tests without real assertions
|
|
531
|
-
</critical_checks>
|
|
532
|
-
|
|
533
|
-
<warning_checks>
|
|
534
|
-
### Warnings (Recommended fixes)
|
|
535
|
-
**Hardcoded Values (HARD-xxx):**
|
|
536
|
-
- Magic numbers
|
|
537
|
-
- Hardcoded URLs
|
|
538
|
-
- Feature flags in code
|
|
539
|
-
|
|
540
|
-
**Performance (PERF-xxx):**
|
|
541
|
-
- N+1 queries
|
|
542
|
-
- ToList() before Where()
|
|
543
|
-
- Multiple API calls per page
|
|
544
|
-
|
|
545
|
-
**Dead Code (DEAD-xxx):**
|
|
546
|
-
- Unused imports
|
|
547
|
-
- Commented code
|
|
548
|
-
- Old TODOs
|
|
549
|
-
</warning_checks>
|
|
550
|
-
|
|
551
|
-
<info_checks>
|
|
552
|
-
### Info (Nice to have)
|
|
553
|
-
**i18n (I18N-xxx):**
|
|
554
|
-
- Hardcoded UI text
|
|
555
|
-
- Missing translations
|
|
556
|
-
|
|
557
|
-
**Accessibility (A11Y-xxx):**
|
|
558
|
-
- Missing alt attributes
|
|
559
|
-
- Missing ARIA labels
|
|
560
|
-
- Non-interactive click handlers
|
|
561
|
-
</info_checks>
|
|
562
|
-
</review_checklist>
|
|
563
|
-
|
|
564
|
-
<sources>
|
|
565
|
-
- SmartStack Architecture Documentation
|
|
566
|
-
- SmartStack.mcp validation tools
|
|
567
|
-
- Clean Architecture by Robert C. Martin
|
|
568
|
-
</sources>
|
|
1
|
+
<overview>
|
|
2
|
+
SmartStack-specific conventions and patterns. This reference is used when reviewing SmartStack projects to ensure compliance with the architecture and security standards.
|
|
3
|
+
|
|
4
|
+
**IMPORTANT**: All convention validation MUST be delegated to the MCP SmartStack tools. This file documents what to look for; the MCP validates automatically.
|
|
5
|
+
</overview>
|
|
6
|
+
|
|
7
|
+
<mcp_tools>
|
|
8
|
+
## MCP SmartStack Tools for Code Review
|
|
9
|
+
|
|
10
|
+
### Primary Tool - Unified Code Review
|
|
11
|
+
|
|
12
|
+
| Tool | Purpose | When to use |
|
|
13
|
+
|------|---------|-------------|
|
|
14
|
+
| `mcp__smartstack__review_code` | **Unified code review** covering 9 categories | Always use first |
|
|
15
|
+
|
|
16
|
+
**Parameters:**
|
|
17
|
+
```
|
|
18
|
+
scope: "all" | "changed" | "staged" # Which files to review
|
|
19
|
+
checks: ["all"] | ["security", ...] # Categories to check
|
|
20
|
+
severity: "all" | "blocking" # Filter by severity
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Categories covered:**
|
|
24
|
+
| Category | ID Prefix | Severity | What it detects |
|
|
25
|
+
|----------|-----------|----------|-----------------|
|
|
26
|
+
| Security | SEC-xxx | blocking | Secrets, SQL injection, XSS, missing [Authorize] |
|
|
27
|
+
| Architecture | ARCH-xxx | critical | Layer violations, DI bypass |
|
|
28
|
+
| Hardcoded Values | HARD-xxx | warning | Magic numbers, URLs, feature flags |
|
|
29
|
+
| Tests | TEST-xxx | critical | Missing tests, useless assertions |
|
|
30
|
+
| AI Hallucinations | AI-xxx | blocking | Phantom imports, non-existent methods |
|
|
31
|
+
| Performance | PERF-xxx | warning | N+1 queries, over-fetching |
|
|
32
|
+
| Dead Code | DEAD-xxx | warning | Unused imports, commented code, TODOs |
|
|
33
|
+
| i18n | I18N-xxx | info | Hardcoded UI text, missing translations |
|
|
34
|
+
| Accessibility | A11Y-xxx | info | Missing alt, ARIA, focus issues |
|
|
35
|
+
|
|
36
|
+
### Additional Tools (Optional)
|
|
37
|
+
|
|
38
|
+
| Tool | Purpose | When to use |
|
|
39
|
+
|------|---------|-------------|
|
|
40
|
+
| `mcp__smartstack__validate_conventions` | Detailed conventions validation | Deep convention checks |
|
|
41
|
+
| `mcp__smartstack__validate_test_conventions` | Test patterns validation | Test structure review |
|
|
42
|
+
| `mcp__smartstack__check_migrations` | EF Core migration conflicts | Migration changes |
|
|
43
|
+
</mcp_tools>
|
|
44
|
+
|
|
45
|
+
<architecture>
|
|
46
|
+
## SmartStack Architecture (Clean Architecture)
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
SmartStack/
|
|
50
|
+
├── SmartStack.Domain/ # Entities, Value Objects, Domain Events
|
|
51
|
+
├── SmartStack.Application/ # Services, DTOs, Commands/Queries
|
|
52
|
+
├── SmartStack.Infrastructure/ # EF Core, External services
|
|
53
|
+
├── SmartStack.Api/ # Controllers, Middleware
|
|
54
|
+
└── SmartStack.Web/ # React frontend
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Dependency rule**: Dependencies point inward only (Api → Application → Domain).
|
|
58
|
+
</architecture>
|
|
59
|
+
|
|
60
|
+
<entities>
|
|
61
|
+
## Entity Conventions
|
|
62
|
+
|
|
63
|
+
<tenant_aware>
|
|
64
|
+
**Tenant-aware entities** (most business entities):
|
|
65
|
+
```csharp
|
|
66
|
+
public class Order : BaseEntity, ITenantEntity
|
|
67
|
+
{
|
|
68
|
+
public Guid TenantId { get; private set; }
|
|
69
|
+
|
|
70
|
+
private Order() { } // EF Core constructor
|
|
71
|
+
|
|
72
|
+
public static Order Create(Guid tenantId, ...)
|
|
73
|
+
{
|
|
74
|
+
return new Order { TenantId = tenantId, ... };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Requirements:**
|
|
80
|
+
- [ ] Implements `ITenantEntity`
|
|
81
|
+
- [ ] Has `TenantId` property
|
|
82
|
+
- [ ] Private parameterless constructor
|
|
83
|
+
- [ ] Static `Create()` factory method with `tenantId` as first parameter
|
|
84
|
+
</tenant_aware>
|
|
85
|
+
|
|
86
|
+
<system_entity>
|
|
87
|
+
**System entities** (platform-level, no tenant):
|
|
88
|
+
```csharp
|
|
89
|
+
public class Permission : SystemEntity
|
|
90
|
+
{
|
|
91
|
+
private Permission() { }
|
|
92
|
+
|
|
93
|
+
public static Permission Create(...)
|
|
94
|
+
{
|
|
95
|
+
return new Permission { ... };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Requirements:**
|
|
101
|
+
- [ ] Inherits from `SystemEntity`
|
|
102
|
+
- [ ] NO `TenantId` property
|
|
103
|
+
- [ ] Private parameterless constructor
|
|
104
|
+
- [ ] Static `Create()` factory method
|
|
105
|
+
</system_entity>
|
|
106
|
+
</entities>
|
|
107
|
+
|
|
108
|
+
<value_objects>
|
|
109
|
+
## Value Objects (DDD Pattern)
|
|
110
|
+
|
|
111
|
+
Value Objects are immutable types defined by their attributes rather than identity. Use them to replace primitive types that carry domain meaning and validation.
|
|
112
|
+
|
|
113
|
+
**When to use a Value Object:**
|
|
114
|
+
| Instead of | Use | Why |
|
|
115
|
+
|------------|-----|-----|
|
|
116
|
+
| `string Email` | `Email` record | Self-validating, prevents invalid state |
|
|
117
|
+
| `decimal Amount` + `string Currency` | `Money` record | Always consistent pair |
|
|
118
|
+
| `string Street` + `string City` + ... | `Address` record | Cohesive group |
|
|
119
|
+
| `DateTime Start` + `DateTime End` | `DateRange` record | Enforces Start < End invariant |
|
|
120
|
+
|
|
121
|
+
**Structure (C# record):**
|
|
122
|
+
```csharp
|
|
123
|
+
// Domain/ValueObjects/Email.cs
|
|
124
|
+
public sealed record Email
|
|
125
|
+
{
|
|
126
|
+
public string Value { get; }
|
|
127
|
+
|
|
128
|
+
public Email(string value)
|
|
129
|
+
{
|
|
130
|
+
if (string.IsNullOrWhiteSpace(value))
|
|
131
|
+
throw new DomainException("Email is required");
|
|
132
|
+
if (!value.Contains('@'))
|
|
133
|
+
throw new DomainException("Invalid email format");
|
|
134
|
+
|
|
135
|
+
Value = value.Trim().ToLowerInvariant();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
public static implicit operator string(Email email) => email.Value;
|
|
139
|
+
public override string ToString() => Value;
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**EF Core mapping:**
|
|
144
|
+
```csharp
|
|
145
|
+
// Option 1: Owned type (separate columns)
|
|
146
|
+
builder.OwnsOne(e => e.Email, email =>
|
|
147
|
+
{
|
|
148
|
+
email.Property(v => v.Value).HasColumnName("Email").HasMaxLength(256);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Option 2: Value conversion (single column)
|
|
152
|
+
builder.Property(e => e.Email)
|
|
153
|
+
.HasConversion(
|
|
154
|
+
v => v.Value,
|
|
155
|
+
v => new Email(v))
|
|
156
|
+
.HasMaxLength(256);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Entity vs Value Object:**
|
|
160
|
+
| Criteria | Entity | Value Object |
|
|
161
|
+
|----------|--------|-------------|
|
|
162
|
+
| Identity | Has `Id` (Guid) | No identity |
|
|
163
|
+
| Equality | By Id | By all properties |
|
|
164
|
+
| Mutability | Mutable (behavior methods) | Immutable (records) |
|
|
165
|
+
| Lifecycle | Independent | Owned by entity |
|
|
166
|
+
| Example | `User`, `Order` | `Email`, `Money`, `Address` |
|
|
167
|
+
|
|
168
|
+
**Code review detection:** If an entity has `string Email`, `string Phone`, `decimal Amount` + `string Currency` as separate primitives, suggest replacing with Value Objects.
|
|
169
|
+
</value_objects>
|
|
170
|
+
|
|
171
|
+
<domain_events>
|
|
172
|
+
## Domain Events
|
|
173
|
+
|
|
174
|
+
Domain Events capture something that happened in the domain. They enable decoupled communication between aggregates and complement the existing Workflow trigger system.
|
|
175
|
+
|
|
176
|
+
**Relationship with Workflow Triggers:**
|
|
177
|
+
| Mechanism | Scope | Use case |
|
|
178
|
+
|-----------|-------|----------|
|
|
179
|
+
| Domain Events (MediatR) | In-process, synchronous | Cache invalidation, audit logging, read-model updates |
|
|
180
|
+
| Workflow Triggers (`TriggerAsync`) | Cross-process, async | Emails, webhooks, multi-step business processes |
|
|
181
|
+
| **Combined** | Domain Event handler calls `TriggerAsync()` | Best of both worlds |
|
|
182
|
+
|
|
183
|
+
**Structure:**
|
|
184
|
+
```csharp
|
|
185
|
+
// Domain/Events/OrderCreatedEvent.cs
|
|
186
|
+
public sealed record OrderCreatedEvent(
|
|
187
|
+
Guid OrderId,
|
|
188
|
+
Guid TenantId,
|
|
189
|
+
Guid CreatedById,
|
|
190
|
+
DateTime OccurredAt) : IDomainEvent;
|
|
191
|
+
|
|
192
|
+
// Domain/Common/IDomainEvent.cs
|
|
193
|
+
public interface IDomainEvent : INotification { } // MediatR marker
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Publishing from entities:**
|
|
197
|
+
```csharp
|
|
198
|
+
public class Order : BaseEntity, ITenantEntity
|
|
199
|
+
{
|
|
200
|
+
private readonly List<IDomainEvent> _domainEvents = new();
|
|
201
|
+
public IReadOnlyList<IDomainEvent> DomainEvents => _domainEvents.AsReadOnly();
|
|
202
|
+
|
|
203
|
+
public static Order Create(Guid tenantId, string description, Guid createdById)
|
|
204
|
+
{
|
|
205
|
+
var order = new Order
|
|
206
|
+
{
|
|
207
|
+
Id = Guid.NewGuid(),
|
|
208
|
+
TenantId = tenantId,
|
|
209
|
+
Description = description
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
order._domainEvents.Add(new OrderCreatedEvent(
|
|
213
|
+
order.Id, tenantId, createdById, DateTime.UtcNow));
|
|
214
|
+
|
|
215
|
+
return order;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
public void ClearDomainEvents() => _domainEvents.Clear();
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Handling events:**
|
|
223
|
+
```csharp
|
|
224
|
+
// Application/EventHandlers/OrderCreatedEventHandler.cs
|
|
225
|
+
public class OrderCreatedEventHandler : INotificationHandler<OrderCreatedEvent>
|
|
226
|
+
{
|
|
227
|
+
private readonly IWorkflowService _workflowService;
|
|
228
|
+
private readonly ILogger<OrderCreatedEventHandler> _logger;
|
|
229
|
+
|
|
230
|
+
public async Task Handle(OrderCreatedEvent notification, CancellationToken ct)
|
|
231
|
+
{
|
|
232
|
+
_logger.LogInformation("Order {OrderId} created", notification.OrderId);
|
|
233
|
+
|
|
234
|
+
// Bridge to Workflow triggers for cross-process actions
|
|
235
|
+
await _workflowService.TriggerAsync("order.created",
|
|
236
|
+
new Dictionary<string, object>
|
|
237
|
+
{
|
|
238
|
+
["orderId"] = notification.OrderId,
|
|
239
|
+
["tenantId"] = notification.TenantId
|
|
240
|
+
}, ct: ct);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**Dispatching (in DbContext):**
|
|
246
|
+
```csharp
|
|
247
|
+
// Infrastructure/Persistence/ApplicationDbContext.cs
|
|
248
|
+
public override async Task<int> SaveChangesAsync(CancellationToken ct = default)
|
|
249
|
+
{
|
|
250
|
+
var entities = ChangeTracker.Entries<BaseEntity>()
|
|
251
|
+
.Where(e => e.Entity.DomainEvents.Any())
|
|
252
|
+
.ToList();
|
|
253
|
+
|
|
254
|
+
var events = entities.SelectMany(e => e.Entity.DomainEvents).ToList();
|
|
255
|
+
|
|
256
|
+
var result = await base.SaveChangesAsync(ct);
|
|
257
|
+
|
|
258
|
+
foreach (var @event in events)
|
|
259
|
+
await _mediator.Publish(@event, ct);
|
|
260
|
+
|
|
261
|
+
foreach (var entity in entities)
|
|
262
|
+
entity.Entity.ClearDomainEvents();
|
|
263
|
+
|
|
264
|
+
return result;
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**When to add Domain Events (code review check):**
|
|
269
|
+
- Entity has side effects in `Create()` or behavior methods → Domain Event candidate
|
|
270
|
+
- Service calls `TriggerAsync()` right after `SaveChangesAsync()` → Should be Domain Event
|
|
271
|
+
- Multiple services react to the same entity change → Domain Event decouples them
|
|
272
|
+
</domain_events>
|
|
273
|
+
|
|
274
|
+
<tables>
|
|
275
|
+
## Table Naming Conventions
|
|
276
|
+
|
|
277
|
+
**Schema**: All tables MUST specify schema explicitly.
|
|
278
|
+
```csharp
|
|
279
|
+
builder.ToTable("auth_users", SchemaConstants.Core);
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**Prefixes by domain:**
|
|
283
|
+
| Prefix | Domain | Examples |
|
|
284
|
+
|--------|--------|----------|
|
|
285
|
+
| `auth_` | Authentication | auth_users, auth_roles |
|
|
286
|
+
| `nav_` | Navigation | nav_menus, nav_routes |
|
|
287
|
+
| `cfg_` | Configuration | cfg_settings, cfg_features |
|
|
288
|
+
| `ai_` | AI/Prompts | ai_prompts, ai_models |
|
|
289
|
+
| `ntf_` | Notifications | ntf_templates, ntf_logs |
|
|
290
|
+
| `wkf_` | Workflows | wkf_definitions, wkf_instances |
|
|
291
|
+
| `doc_` | Documents | doc_files, doc_versions |
|
|
292
|
+
| `tkt_` | Tickets/Support | tkt_tickets, tkt_comments |
|
|
293
|
+
|
|
294
|
+
**Custom Application Prefixes:**
|
|
295
|
+
|
|
296
|
+
Business applications define their own table prefix during `/business-analyse` cadrage phase.
|
|
297
|
+
Format: `{2-5 lowercase letters}_` — stored in `feature.json` → `metadata.tablePrefix`.
|
|
298
|
+
|
|
299
|
+
| Application | Prefix | Examples |
|
|
300
|
+
|-------------|--------|----------|
|
|
301
|
+
| Human Resources | `rh_` | rh_Employees, rh_Contracts |
|
|
302
|
+
| Finance | `fi_` | fi_Invoices, fi_Payments |
|
|
303
|
+
| CRM | `crm_` | crm_Contacts, crm_Opportunities |
|
|
304
|
+
|
|
305
|
+
Rules:
|
|
306
|
+
- Must not collide with platform prefixes
|
|
307
|
+
- Registered in MCP config via `conventions.customTablePrefixes`
|
|
308
|
+
- All entities in the same application share the same prefix
|
|
309
|
+
|
|
310
|
+
**Schemas:**
|
|
311
|
+
- `core` (SchemaConstants.Core): SmartStack platform tables
|
|
312
|
+
- `extensions` (SchemaConstants.Extensions): Client-specific tables
|
|
313
|
+
</tables>
|
|
314
|
+
|
|
315
|
+
<migrations>
|
|
316
|
+
## Migration Naming
|
|
317
|
+
|
|
318
|
+
**Format**: `{context}_v{version}_{sequence}_{Description}.cs`
|
|
319
|
+
|
|
320
|
+
**Examples:**
|
|
321
|
+
- `core_v1.0.0_001_CreateAuthUsers.cs`
|
|
322
|
+
- `core_v1.2.0_001_AddUserProfiles.cs`
|
|
323
|
+
- `extensions_v1.0.0_001_CreateClientOrders.cs`
|
|
324
|
+
|
|
325
|
+
**Rules:**
|
|
326
|
+
- [ ] Context: `core` or `extensions`
|
|
327
|
+
- [ ] Version: semver format (1.0.0)
|
|
328
|
+
- [ ] Sequence: 3-digit padded (001, 002)
|
|
329
|
+
- [ ] Description: PascalCase, descriptive
|
|
330
|
+
</migrations>
|
|
331
|
+
|
|
332
|
+
<controllers>
|
|
333
|
+
## Controller Conventions
|
|
334
|
+
|
|
335
|
+
**NavRoute attribute** (preferred):
|
|
336
|
+
```csharp
|
|
337
|
+
[ApiController]
|
|
338
|
+
[NavRoute("administration.users")]
|
|
339
|
+
public class UsersController : ControllerBase // MUST be ControllerBase, NOT Controller
|
|
340
|
+
{
|
|
341
|
+
// Routes generated from NavRoute: /api/administration/users
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
**CRITICAL: Controller Inheritance (S6934)**
|
|
346
|
+
|
|
347
|
+
```csharp
|
|
348
|
+
// ❌ BAD - Inheriting from Controller
|
|
349
|
+
public class UsersController : Controller
|
|
350
|
+
{
|
|
351
|
+
// Brings in MVC View support (Razor, ViewData, ViewBag)
|
|
352
|
+
// Unnecessary for API controllers
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// ✅ GOOD - Inheriting from ControllerBase
|
|
356
|
+
public class UsersController : ControllerBase
|
|
357
|
+
{
|
|
358
|
+
// Lightweight, API-only base class
|
|
359
|
+
// No MVC View support (cleaner, more appropriate)
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
**Why ControllerBase?**
|
|
364
|
+
- API controllers don't need MVC View support
|
|
365
|
+
- `Controller` adds unnecessary dependencies (Razor, ViewData, etc.)
|
|
366
|
+
- `ControllerBase` is lighter and more focused on APIs
|
|
367
|
+
- Better performance and smaller footprint
|
|
368
|
+
|
|
369
|
+
**NavRoute format:**
|
|
370
|
+
- Lowercase only
|
|
371
|
+
- Dot-separated hierarchy
|
|
372
|
+
- Minimum 3 levels: `application.module.section`
|
|
373
|
+
- Full path: `application.module.section[.resource]`
|
|
374
|
+
|
|
375
|
+
**Examples:**
|
|
376
|
+
- `administration.users.management`
|
|
377
|
+
- `administration.roles.list`
|
|
378
|
+
- `crm.contacts.details`
|
|
379
|
+
- `crm.contacts.details.notes` (with resource)
|
|
380
|
+
</controllers>
|
|
381
|
+
|
|
382
|
+
<services>
|
|
383
|
+
## Service Conventions
|
|
384
|
+
|
|
385
|
+
**Interface pattern:**
|
|
386
|
+
```csharp
|
|
387
|
+
// Interface
|
|
388
|
+
public interface IUserService
|
|
389
|
+
{
|
|
390
|
+
Task<UserDto> GetByIdAsync(Guid id, CancellationToken ct);
|
|
391
|
+
Task<UserDto> CreateAsync(CreateUserDto dto, CancellationToken ct);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Implementation
|
|
395
|
+
public class UserService : IUserService
|
|
396
|
+
{
|
|
397
|
+
// ...
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
**Requirements:**
|
|
402
|
+
- [ ] Interface named `I{Name}Service`
|
|
403
|
+
- [ ] Implementation named `{Name}Service`
|
|
404
|
+
- [ ] All methods async with CancellationToken
|
|
405
|
+
- [ ] Return DTOs, not entities
|
|
406
|
+
</services>
|
|
407
|
+
|
|
408
|
+
<security>
|
|
409
|
+
## SmartStack Security Patterns
|
|
410
|
+
|
|
411
|
+
<multi_tenant>
|
|
412
|
+
**Multi-tenant isolation:**
|
|
413
|
+
- ALL queries MUST filter by TenantId (automatic via EF Core global filters)
|
|
414
|
+
- NEVER expose TenantId in URLs
|
|
415
|
+
- NEVER allow cross-tenant data access
|
|
416
|
+
- Create methods MUST require tenantId parameter
|
|
417
|
+
|
|
418
|
+
**Check for violations:**
|
|
419
|
+
```csharp
|
|
420
|
+
// BAD: No tenant filter
|
|
421
|
+
var users = await _context.Users.ToListAsync();
|
|
422
|
+
|
|
423
|
+
// GOOD: Tenant filter applied (via global filter or explicit)
|
|
424
|
+
var users = await _context.Users
|
|
425
|
+
.Where(u => u.TenantId == _tenantId)
|
|
426
|
+
.ToListAsync();
|
|
427
|
+
```
|
|
428
|
+
</multi_tenant>
|
|
429
|
+
|
|
430
|
+
<authorization>
|
|
431
|
+
**RBAC with NavRoute:**
|
|
432
|
+
- Controllers use `[NavRoute]` for automatic permission mapping
|
|
433
|
+
- Permissions follow NavRoute pattern: `{navroute}.{action}`
|
|
434
|
+
- Actions: `read`, `create`, `update`, `delete`, `*` (wildcard)
|
|
435
|
+
|
|
436
|
+
**Example permissions:**
|
|
437
|
+
- `administration.users.read`
|
|
438
|
+
- `administration.users.create`
|
|
439
|
+
- `administration.users.*` (all actions)
|
|
440
|
+
</authorization>
|
|
441
|
+
|
|
442
|
+
<input_validation>
|
|
443
|
+
**FluentValidation:**
|
|
444
|
+
```csharp
|
|
445
|
+
public class CreateUserDtoValidator : AbstractValidator<CreateUserDto>
|
|
446
|
+
{
|
|
447
|
+
public CreateUserDtoValidator()
|
|
448
|
+
{
|
|
449
|
+
RuleFor(x => x.Email)
|
|
450
|
+
.NotEmpty()
|
|
451
|
+
.EmailAddress()
|
|
452
|
+
.MaximumLength(256);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
</input_validation>
|
|
457
|
+
</security>
|
|
458
|
+
|
|
459
|
+
<tests>
|
|
460
|
+
## Test Conventions
|
|
461
|
+
|
|
462
|
+
**Naming pattern:** `{Method}_When{Condition}_Should{Result}`
|
|
463
|
+
```csharp
|
|
464
|
+
public class UserServiceTests
|
|
465
|
+
{
|
|
466
|
+
[Fact]
|
|
467
|
+
public async Task GetById_WhenUserExists_ShouldReturnUser() { }
|
|
468
|
+
|
|
469
|
+
[Fact]
|
|
470
|
+
public async Task GetById_WhenUserNotFound_ShouldThrowNotFoundException() { }
|
|
471
|
+
|
|
472
|
+
[Fact]
|
|
473
|
+
public async Task Create_WhenValidDto_ShouldCreateAndReturnUser() { }
|
|
474
|
+
}
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
**Structure:**
|
|
478
|
+
```
|
|
479
|
+
Tests/
|
|
480
|
+
├── Unit/
|
|
481
|
+
│ ├── Services/
|
|
482
|
+
│ └── Validators/
|
|
483
|
+
└── Integration/
|
|
484
|
+
└── Controllers/
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
**Patterns:**
|
|
488
|
+
- [ ] AAA pattern (Arrange, Act, Assert)
|
|
489
|
+
- [ ] FluentAssertions for assertions
|
|
490
|
+
- [ ] Moq for mocking
|
|
491
|
+
- [ ] Tenant isolation tests for all tenant-aware services
|
|
492
|
+
</tests>
|
|
493
|
+
|
|
494
|
+
<review_checklist>
|
|
495
|
+
## SmartStack Code Review Checklist
|
|
496
|
+
|
|
497
|
+
**Run unified code review first:**
|
|
498
|
+
```
|
|
499
|
+
mcp__smartstack__review_code
|
|
500
|
+
scope: "changed" # or "all" or "staged"
|
|
501
|
+
checks: ["all"] # 9 categories
|
|
502
|
+
severity: "all"
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
**The tool automatically checks:**
|
|
506
|
+
|
|
507
|
+
<blocking_checks>
|
|
508
|
+
### Blocking Issues (Must fix before merge)
|
|
509
|
+
**Security (SEC-xxx):**
|
|
510
|
+
- Hardcoded credentials or secrets
|
|
511
|
+
- SQL injection patterns
|
|
512
|
+
- XSS vulnerabilities
|
|
513
|
+
- Missing [Authorize] attributes
|
|
514
|
+
|
|
515
|
+
**AI Hallucinations (AI-xxx):**
|
|
516
|
+
- Non-existent imports/namespaces
|
|
517
|
+
- Phantom method calls
|
|
518
|
+
- Undefined types
|
|
519
|
+
</blocking_checks>
|
|
520
|
+
|
|
521
|
+
<critical_checks>
|
|
522
|
+
### Critical Issues (Should fix ASAP)
|
|
523
|
+
**Architecture (ARCH-xxx):**
|
|
524
|
+
- Layer violations (Web → Infrastructure)
|
|
525
|
+
- Direct DbContext usage in controllers
|
|
526
|
+
- Service instantiation instead of DI
|
|
527
|
+
|
|
528
|
+
**Tests (TEST-xxx):**
|
|
529
|
+
- Missing tests for new entities/services
|
|
530
|
+
- Tests without real assertions
|
|
531
|
+
</critical_checks>
|
|
532
|
+
|
|
533
|
+
<warning_checks>
|
|
534
|
+
### Warnings (Recommended fixes)
|
|
535
|
+
**Hardcoded Values (HARD-xxx):**
|
|
536
|
+
- Magic numbers
|
|
537
|
+
- Hardcoded URLs
|
|
538
|
+
- Feature flags in code
|
|
539
|
+
|
|
540
|
+
**Performance (PERF-xxx):**
|
|
541
|
+
- N+1 queries
|
|
542
|
+
- ToList() before Where()
|
|
543
|
+
- Multiple API calls per page
|
|
544
|
+
|
|
545
|
+
**Dead Code (DEAD-xxx):**
|
|
546
|
+
- Unused imports
|
|
547
|
+
- Commented code
|
|
548
|
+
- Old TODOs
|
|
549
|
+
</warning_checks>
|
|
550
|
+
|
|
551
|
+
<info_checks>
|
|
552
|
+
### Info (Nice to have)
|
|
553
|
+
**i18n (I18N-xxx):**
|
|
554
|
+
- Hardcoded UI text
|
|
555
|
+
- Missing translations
|
|
556
|
+
|
|
557
|
+
**Accessibility (A11Y-xxx):**
|
|
558
|
+
- Missing alt attributes
|
|
559
|
+
- Missing ARIA labels
|
|
560
|
+
- Non-interactive click handlers
|
|
561
|
+
</info_checks>
|
|
562
|
+
</review_checklist>
|
|
563
|
+
|
|
564
|
+
<sources>
|
|
565
|
+
- SmartStack Architecture Documentation
|
|
566
|
+
- SmartStack.mcp validation tools
|
|
567
|
+
- Clean Architecture by Robert C. Martin
|
|
568
|
+
</sources>
|