@polymorphism-tech/morph-spec 2.2.0 → 2.4.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/CLAUDE.md +314 -1673
- package/LICENSE +72 -72
- package/README.md +515 -516
- package/bin/detect-agents.js +225 -225
- package/bin/morph-spec.js +358 -173
- package/bin/render-template.js +302 -302
- package/bin/semantic-detect-agents.js +246 -246
- package/bin/task-manager.js +429 -0
- package/bin/validate-agents-skills.js +251 -251
- package/bin/validate-agents.js +69 -69
- package/bin/validate-phase.js +263 -263
- package/bin/validate.js +369 -0
- package/content/.azure/README.md +293 -293
- package/content/.azure/docs/azure-devops-setup.md +454 -454
- package/content/.azure/docs/branch-strategy.md +398 -398
- package/content/.azure/docs/local-development.md +515 -515
- package/content/.azure/pipelines/pipeline-variables.yml +34 -34
- package/content/.azure/pipelines/prod-pipeline.yml +319 -319
- package/content/.azure/pipelines/staging-pipeline.yml +234 -234
- package/content/.azure/pipelines/templates/build-dotnet.yml +75 -75
- package/content/.azure/pipelines/templates/deploy-app-service.yml +94 -94
- package/content/.azure/pipelines/templates/deploy-container-app.yml +120 -120
- package/content/.azure/pipelines/templates/infra-deploy.yml +90 -90
- package/content/.claude/commands/morph-apply.md +221 -158
- package/content/.claude/commands/morph-archive.md +79 -79
- package/content/.claude/commands/morph-infra.md +209 -209
- package/content/.claude/commands/morph-preflight.md +227 -0
- package/content/.claude/commands/morph-proposal.md +122 -101
- package/content/.claude/commands/morph-status.md +86 -86
- package/content/.claude/commands/morph-troubleshoot.md +122 -0
- package/content/.claude/settings.local.json +15 -15
- package/content/.claude/skills/checklists/code-review.md +226 -0
- package/content/.claude/skills/checklists/morph-checklist.md +117 -0
- package/content/.claude/skills/checklists/simulation-checklist.md +77 -0
- package/content/.claude/skills/infra/bicep-architect.md +126 -419
- package/content/.claude/skills/infra/container-specialist.md +131 -437
- package/content/.claude/skills/infra/devops-engineer.md +119 -405
- package/content/.claude/skills/integrations/asaas-financial.md +130 -333
- package/content/.claude/skills/integrations/azure-identity.md +142 -309
- package/content/.claude/skills/integrations/clerk-auth.md +108 -290
- package/content/.claude/skills/integrations/resend-email.md +119 -0
- package/content/.claude/skills/specialists/ai-system-architect.md +192 -604
- package/content/.claude/skills/specialists/azure-architect.md +142 -142
- package/content/.claude/skills/specialists/code-analyzer.md +235 -0
- package/content/.claude/skills/specialists/dotnet-senior.md +287 -0
- package/content/.claude/skills/specialists/ef-modeler.md +113 -200
- package/content/.claude/skills/specialists/hangfire-orchestrator.md +126 -245
- package/content/.claude/skills/specialists/ms-agent-expert.md +109 -263
- package/content/.claude/skills/specialists/po-pm-advisor.md +197 -197
- package/content/.claude/skills/specialists/standards-architect.md +156 -78
- package/content/.claude/skills/specialists/testing-specialist.md +126 -0
- package/content/.claude/skills/specialists/ui-ux-designer.md +191 -1060
- package/content/.claude/skills/stacks/dotnet-blazor.md +210 -588
- package/content/.claude/skills/stacks/dotnet-nextjs.md +154 -402
- package/content/.claude/skills/workflows/morph-replicate.md +213 -0
- package/content/.claude/{commands/morph-clarify.md → skills/workflows/phase-clarify.md} +5 -58
- package/content/.claude/{commands/morph-design.md → skills/workflows/phase-design.md} +16 -86
- package/content/.claude/{commands/morph-setup.md → skills/workflows/phase-setup.md} +9 -17
- package/content/.claude/skills/workflows/phase-tasks.md +164 -0
- package/content/.claude/{commands/morph-uiux.md → skills/workflows/phase-uiux.md} +15 -88
- package/content/.morph/.morphversion +5 -5
- package/content/.morph/archive/.gitkeep +25 -25
- package/content/.morph/config/agents.json +378 -242
- package/content/.morph/config/config.template.json +89 -108
- package/content/.morph/docs/STORY-DRIVEN-DEVELOPMENT.md +392 -392
- package/content/.morph/docs/workflows/design-impl.md +37 -0
- package/content/.morph/docs/workflows/fast-track.md +29 -0
- package/content/.morph/docs/workflows/full-morph.md +76 -0
- package/content/.morph/docs/workflows/standard.md +44 -0
- package/content/.morph/docs/workflows/ui-refresh.md +39 -0
- package/content/.morph/examples/api-nextjs/README.md +241 -241
- package/content/.morph/examples/api-nextjs/contracts.ts +307 -307
- package/content/.morph/examples/api-nextjs/spec.md +399 -399
- package/content/.morph/examples/api-nextjs/tasks.md +168 -168
- package/content/.morph/examples/micro-saas/README.md +125 -125
- package/content/.morph/examples/micro-saas/contracts.cs +358 -358
- package/content/.morph/examples/micro-saas/decisions.md +246 -246
- package/content/.morph/examples/micro-saas/spec.md +236 -236
- package/content/.morph/examples/micro-saas/tasks.md +150 -150
- package/content/.morph/examples/multi-agent/README.md +309 -309
- package/content/.morph/examples/multi-agent/contracts.cs +433 -433
- package/content/.morph/examples/multi-agent/spec.md +479 -479
- package/content/.morph/examples/multi-agent/tasks.md +185 -185
- package/content/.morph/examples/scheduled-reports/decisions.md +158 -0
- package/content/.morph/examples/scheduled-reports/proposal.md +95 -0
- package/content/.morph/examples/scheduled-reports/spec.md +267 -0
- package/content/.morph/examples/state-v3.json +188 -0
- package/content/.morph/features/.gitkeep +25 -25
- package/content/.morph/hooks/README.md +190 -239
- package/content/.morph/hooks/pre-commit-agents.sh +24 -24
- package/content/.morph/hooks/pre-commit-all.sh +48 -48
- package/content/.morph/hooks/pre-commit-specs.sh +49 -49
- package/content/.morph/hooks/pre-commit-tests.sh +60 -60
- package/content/.morph/project.md +160 -160
- package/content/.morph/schemas/agent.schema.json +296 -296
- package/content/.morph/schemas/tasks.schema.json +220 -0
- package/content/.morph/specs/.gitkeep +20 -20
- package/content/.morph/standards/agent-framework-blazor-ui.md +359 -0
- package/content/.morph/standards/agent-framework-production.md +410 -0
- package/content/.morph/standards/agent-framework-setup.md +413 -453
- package/content/.morph/standards/agent-framework-workflows.md +349 -0
- package/content/.morph/standards/architecture.md +325 -325
- package/content/.morph/standards/azure.md +605 -379
- package/content/.morph/standards/coding.md +377 -377
- package/content/.morph/standards/dotnet10-migration.md +520 -494
- package/content/.morph/standards/fluent-ui-setup.md +590 -590
- package/content/.morph/standards/migration-guide.md +514 -514
- package/content/.morph/standards/passkeys-auth.md +423 -423
- package/content/.morph/standards/vector-search-rag.md +536 -536
- package/content/.morph/state.json +17 -17
- package/content/.morph/templates/FluentDesignTheme.cs +149 -149
- package/content/.morph/templates/MudTheme.cs +281 -281
- package/content/.morph/templates/agent.cs +163 -172
- package/content/.morph/templates/clarify-questions.md +159 -0
- package/content/.morph/templates/component.razor +239 -239
- package/content/.morph/templates/contracts/Commands.cs +74 -0
- package/content/.morph/templates/contracts/Entities.cs +25 -0
- package/content/.morph/templates/contracts/Queries.cs +74 -0
- package/content/.morph/templates/contracts/README.md +74 -0
- package/content/.morph/templates/contracts.cs +217 -217
- package/content/.morph/templates/decisions.md +123 -106
- package/content/.morph/templates/design-system.css +226 -226
- package/content/.morph/templates/infra/.dockerignore.example +89 -89
- package/content/.morph/templates/infra/Dockerfile.example +82 -82
- package/content/.morph/templates/infra/README.md +286 -286
- package/content/.morph/templates/infra/app-insights.bicep +63 -63
- package/content/.morph/templates/infra/app-service.bicep +164 -164
- package/content/.morph/templates/infra/container-app-env.bicep +49 -49
- package/content/.morph/templates/infra/container-app.bicep +156 -156
- package/content/.morph/templates/infra/deploy-checklist.md +426 -0
- package/content/.morph/templates/infra/deploy.ps1 +229 -229
- package/content/.morph/templates/infra/deploy.sh +208 -208
- package/content/.morph/templates/infra/key-vault.bicep +91 -91
- package/content/.morph/templates/infra/main.bicep +189 -189
- package/content/.morph/templates/infra/parameters.dev.json +29 -29
- package/content/.morph/templates/infra/parameters.prod.json +29 -29
- package/content/.morph/templates/infra/parameters.staging.json +29 -29
- package/content/.morph/templates/infra/sql-database.bicep +103 -103
- package/content/.morph/templates/infra/storage.bicep +106 -106
- package/content/.morph/templates/integrations/asaas-client.cs +387 -387
- package/content/.morph/templates/integrations/asaas-webhook.cs +351 -351
- package/content/.morph/templates/integrations/azure-identity-config.cs +288 -288
- package/content/.morph/templates/integrations/clerk-config.cs +258 -258
- package/content/.morph/templates/job.cs +171 -171
- package/content/.morph/templates/migration.cs +83 -83
- package/content/.morph/templates/proposal.md +141 -155
- package/content/.morph/templates/recap.md +94 -105
- package/content/.morph/templates/repository.cs +141 -141
- package/content/.morph/templates/saas/subscription.cs +347 -347
- package/content/.morph/templates/saas/tenant.cs +338 -338
- package/content/.morph/templates/service.cs +139 -139
- package/content/.morph/templates/simulation.md +353 -0
- package/content/.morph/templates/spec.md +149 -148
- package/content/.morph/templates/sprint-status.yaml +68 -68
- package/content/.morph/templates/state.template.json +222 -222
- package/content/.morph/templates/story.md +143 -143
- package/content/.morph/templates/tasks.md +257 -235
- package/content/.morph/templates/test.cs +239 -239
- package/content/.morph/templates/ui-components.md +362 -276
- package/content/.morph/templates/ui-design-system.md +286 -286
- package/content/.morph/templates/ui-flows.md +336 -336
- package/content/.morph/templates/ui-mockups.md +133 -133
- package/content/.morph/test-infra/example.bicep +59 -59
- package/content/CLAUDE.md +150 -442
- package/content/README.md +79 -79
- package/detectors/config-detector.js +223 -223
- package/detectors/conversation-analyzer.js +163 -163
- package/detectors/index.js +84 -84
- package/detectors/standards-generator.js +275 -275
- package/detectors/structure-detector.js +245 -250
- package/docs/README.md +144 -149
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +977 -977
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1048 -1048
- package/docs/api/scripts/collapse.js +38 -38
- package/docs/api/scripts/commonNav.js +28 -28
- package/docs/api/scripts/linenumber.js +25 -25
- package/docs/api/scripts/nav.js +12 -12
- package/docs/api/scripts/polyfill.js +3 -3
- package/docs/api/scripts/prettify/Apache-License-2.0.txt +202 -202
- package/docs/api/scripts/prettify/lang-css.js +2 -2
- package/docs/api/scripts/prettify/prettify.js +28 -28
- package/docs/api/scripts/search.js +98 -98
- package/docs/api/styles/jsdoc.css +776 -776
- package/docs/api/styles/prettify.css +80 -80
- package/docs/examples.md +328 -328
- package/docs/getting-started.md +301 -302
- package/docs/installation.md +361 -361
- package/docs/templates.md +418 -418
- package/docs/validation-checklist.md +265 -266
- package/package.json +80 -80
- package/scripts/postinstall.js +132 -132
- package/src/commands/advance-phase.js +183 -0
- package/src/commands/analyze-blazor-concurrency.js +193 -0
- package/src/commands/create-story.js +351 -351
- package/src/commands/detect-agents.js +139 -0
- package/src/commands/detect.js +104 -104
- package/src/commands/doctor.js +356 -280
- package/src/commands/generate.js +149 -149
- package/src/commands/init.js +258 -245
- package/src/commands/lint-fluent.js +352 -0
- package/src/commands/rollback-phase.js +185 -0
- package/src/commands/session-summary.js +291 -0
- package/src/commands/shard-spec.js +224 -224
- package/src/commands/sprint-status.js +250 -250
- package/src/commands/state.js +333 -333
- package/src/commands/sync.js +167 -167
- package/src/commands/task.js +78 -0
- package/src/commands/troubleshoot.js +222 -0
- package/src/commands/update.js +192 -159
- package/src/commands/validate-blazor-state.js +210 -0
- package/src/commands/validate-blazor.js +156 -0
- package/src/commands/validate-css.js +84 -0
- package/src/commands/validate-phase.js +221 -0
- package/src/lib/blazor-concurrency-analyzer.js +288 -0
- package/src/lib/blazor-state-validator.js +291 -0
- package/src/lib/blazor-validator.js +374 -0
- package/src/lib/complexity-analyzer.js +441 -292
- package/src/lib/continuous-validator.js +421 -0
- package/src/lib/css-validator.js +352 -0
- package/src/lib/decision-constraint-loader.js +109 -0
- package/src/lib/design-system-generator.js +298 -298
- package/src/lib/learning-system.js +520 -0
- package/src/lib/mockup-generator.js +366 -0
- package/src/lib/recap-generator.js +205 -0
- package/src/lib/state-manager.js +397 -340
- package/src/lib/troubleshoot-grep.js +194 -0
- package/src/lib/troubleshoot-index.js +144 -0
- package/src/lib/ui-detector.js +350 -0
- package/src/lib/validation-runner.js +231 -0
- package/src/lib/validators/architecture-validator.js +387 -0
- package/src/lib/validators/contract-compliance-validator.js +273 -0
- package/src/lib/validators/package-validator.js +360 -0
- package/src/lib/validators/ui-contrast-validator.js +422 -0
- package/src/utils/file-copier.js +179 -139
- package/src/utils/logger.js +32 -32
- package/src/utils/version-checker.js +175 -175
- package/content/.claude/commands/morph-costs.md +0 -206
- package/content/.claude/commands/morph-tasks.md +0 -319
- package/content/.claude/skills/specialists/cost-guardian.md +0 -110
- package/content/.claude/skills/stacks/shopify.md +0 -445
- package/content/.morph/config/azure-pricing.json +0 -70
- package/content/.morph/config/azure-pricing.schema.json +0 -50
- package/content/.morph/hooks/pre-commit-costs.sh +0 -91
- package/docs/api/cost-calculator.js.html +0 -513
- package/docs/api/design-system-generator.js.html +0 -382
- package/docs/api/global.html +0 -5263
- package/docs/api/index.html +0 -96
- package/docs/api/state-manager.js.html +0 -423
- package/src/commands/cost.js +0 -181
- package/src/commands/update-pricing.js +0 -206
- package/src/lib/cost-calculator.js +0 -429
|
@@ -1,588 +1,210 @@
|
|
|
1
|
-
# .NET + Blazor Stack
|
|
2
|
-
|
|
3
|
-
Stack principal para
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
|
8
|
-
|
|
9
|
-
| **
|
|
10
|
-
| **
|
|
11
|
-
| **
|
|
12
|
-
| **
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
app.
|
|
110
|
-
app.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
@
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
<
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
###
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
</InputSelect>
|
|
212
|
-
<ValidationMessage For="() => _model.CustomerId" />
|
|
213
|
-
</div>
|
|
214
|
-
|
|
215
|
-
<div>
|
|
216
|
-
<label for="notes">Observações</label>
|
|
217
|
-
<InputTextArea @bind-Value="_model.Notes" id="notes" class="input" />
|
|
218
|
-
</div>
|
|
219
|
-
|
|
220
|
-
<div class="flex gap-2">
|
|
221
|
-
<button type="submit" class="btn btn-primary" disabled="@_isSubmitting">
|
|
222
|
-
@if (_isSubmitting)
|
|
223
|
-
{
|
|
224
|
-
<span class="loading"></span>
|
|
225
|
-
}
|
|
226
|
-
Salvar
|
|
227
|
-
</button>
|
|
228
|
-
<button type="button" @onclick="Cancel" class="btn">Cancelar</button>
|
|
229
|
-
</div>
|
|
230
|
-
</div>
|
|
231
|
-
</EditForm>
|
|
232
|
-
|
|
233
|
-
@code {
|
|
234
|
-
[Parameter] public int? Id { get; set; }
|
|
235
|
-
|
|
236
|
-
private OrderFormModel _model = new();
|
|
237
|
-
private List<CustomerDto> _customers = new();
|
|
238
|
-
private bool _isEdit => Id.HasValue;
|
|
239
|
-
private bool _isSubmitting;
|
|
240
|
-
|
|
241
|
-
protected override async Task OnInitializedAsync()
|
|
242
|
-
{
|
|
243
|
-
_customers = await CustomerService.GetAllAsync();
|
|
244
|
-
|
|
245
|
-
if (_isEdit)
|
|
246
|
-
{
|
|
247
|
-
var order = await OrderService.GetByIdAsync(Id!.Value);
|
|
248
|
-
_model = new OrderFormModel
|
|
249
|
-
{
|
|
250
|
-
CustomerId = order.CustomerId,
|
|
251
|
-
Notes = order.Notes
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
private async Task HandleSubmit()
|
|
257
|
-
{
|
|
258
|
-
_isSubmitting = true;
|
|
259
|
-
|
|
260
|
-
try
|
|
261
|
-
{
|
|
262
|
-
if (_isEdit)
|
|
263
|
-
await OrderService.UpdateAsync(Id!.Value, _model);
|
|
264
|
-
else
|
|
265
|
-
await OrderService.CreateAsync(_model);
|
|
266
|
-
|
|
267
|
-
Navigation.NavigateTo("/orders");
|
|
268
|
-
}
|
|
269
|
-
finally
|
|
270
|
-
{
|
|
271
|
-
_isSubmitting = false;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
private void Cancel() => Navigation.NavigateTo("/orders");
|
|
276
|
-
}
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
## Services
|
|
280
|
-
|
|
281
|
-
```csharp
|
|
282
|
-
// Application/Services/OrderService.cs
|
|
283
|
-
public interface IOrderService
|
|
284
|
-
{
|
|
285
|
-
Task<List<OrderDto>> GetAllAsync(CancellationToken ct = default);
|
|
286
|
-
Task<OrderDto> GetByIdAsync(int id, CancellationToken ct = default);
|
|
287
|
-
Task<OrderDto> CreateAsync(CreateOrderRequest request, CancellationToken ct = default);
|
|
288
|
-
Task UpdateAsync(int id, UpdateOrderRequest request, CancellationToken ct = default);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
public class OrderService : IOrderService
|
|
292
|
-
{
|
|
293
|
-
private readonly AppDbContext _context;
|
|
294
|
-
private readonly ILogger<OrderService> _logger;
|
|
295
|
-
|
|
296
|
-
public OrderService(AppDbContext context, ILogger<OrderService> logger)
|
|
297
|
-
{
|
|
298
|
-
_context = context;
|
|
299
|
-
_logger = logger;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
public async Task<List<OrderDto>> GetAllAsync(CancellationToken ct = default)
|
|
303
|
-
{
|
|
304
|
-
return await _context.Orders
|
|
305
|
-
.Include(o => o.Customer)
|
|
306
|
-
.OrderByDescending(o => o.CreatedAt)
|
|
307
|
-
.Select(o => new OrderDto
|
|
308
|
-
{
|
|
309
|
-
Id = o.Id,
|
|
310
|
-
OrderNumber = o.OrderNumber,
|
|
311
|
-
CustomerName = o.Customer.Name,
|
|
312
|
-
Total = o.Total,
|
|
313
|
-
Status = o.Status.ToString()
|
|
314
|
-
})
|
|
315
|
-
.ToListAsync(ct);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
public async Task<OrderDto> CreateAsync(CreateOrderRequest request, CancellationToken ct = default)
|
|
319
|
-
{
|
|
320
|
-
var order = Order.Create(request.CustomerId, request.Items);
|
|
321
|
-
|
|
322
|
-
_context.Orders.Add(order);
|
|
323
|
-
await _context.SaveChangesAsync(ct);
|
|
324
|
-
|
|
325
|
-
_logger.LogInformation("Order {OrderNumber} created", order.OrderNumber);
|
|
326
|
-
|
|
327
|
-
return new OrderDto { /* map */ };
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
---
|
|
333
|
-
|
|
334
|
-
## 🎨 UI Component Libraries
|
|
335
|
-
|
|
336
|
-
### Recomendação para Projetos AI-First
|
|
337
|
-
|
|
338
|
-
| Biblioteca | Quando Usar | Vantagens | Desvantagens |
|
|
339
|
-
|------------|-------------|-----------|--------------|
|
|
340
|
-
| **Fluent UI** ⭐ | Projetos AI-first, Micro-SaaS | Componentes AI nativos, Microsoft integration, Performance (~200KB) | Menos componentes prontos |
|
|
341
|
-
| **MudBlazor** | SaaS tradicional, Analytics pesados | 140+ componentes, Charts nativos, Templates prontos | Mais pesado (~500KB), Sem componentes AI |
|
|
342
|
-
| **Híbrido** | SaaS complexo com AI | Melhor dos dois mundos | Maior bundle size (~350KB) |
|
|
343
|
-
|
|
344
|
-
### Fluent UI Blazor (Recomendado)
|
|
345
|
-
|
|
346
|
-
**Para:**
|
|
347
|
-
- Projetos com AI agents/chat
|
|
348
|
-
- Integração com Microsoft Agent Framework
|
|
349
|
-
- Produtos com UX Copilot-like
|
|
350
|
-
- Micro-SaaS que priorizam performance
|
|
351
|
-
|
|
352
|
-
**Setup rápido:**
|
|
353
|
-
```bash
|
|
354
|
-
dotnet add package Microsoft.FluentUI.AspNetCore.Components
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
```csharp
|
|
358
|
-
// Program.cs
|
|
359
|
-
builder.Services.AddFluentUIComponents();
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
**Exemplo de Chat AI:**
|
|
363
|
-
```razor
|
|
364
|
-
<FluentMessageBar Intent="MessageIntent.Success">
|
|
365
|
-
<FluentLabel Weight="FontWeight.Bold">AI Assistant</FluentLabel>
|
|
366
|
-
<FluentLabel>@_aiResponse</FluentLabel>
|
|
367
|
-
</FluentMessageBar>
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
**Guia completo:** [Fluent UI Setup](../../.morph/standards/fluent-ui-setup.md)
|
|
371
|
-
|
|
372
|
-
### MudBlazor (Complemento)
|
|
373
|
-
|
|
374
|
-
**Para:**
|
|
375
|
-
- Grids complexos com filtros avançados
|
|
376
|
-
- Charts e dashboards analytics
|
|
377
|
-
- Componentes que Fluent UI não tem
|
|
378
|
-
|
|
379
|
-
**Setup:**
|
|
380
|
-
```bash
|
|
381
|
-
dotnet add package MudBlazor
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
**Exemplo de Grid Avançado:**
|
|
385
|
-
```razor
|
|
386
|
-
<MudDataGrid T="Order" Items="@_orders"
|
|
387
|
-
Filterable="true"
|
|
388
|
-
Groupable="true"
|
|
389
|
-
Dense="true">
|
|
390
|
-
<Columns>
|
|
391
|
-
<PropertyColumn Property="x => x.OrderNumber" />
|
|
392
|
-
<PropertyColumn Property="x => x.Total" Format="C2" />
|
|
393
|
-
</Columns>
|
|
394
|
-
</MudDataGrid>
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
### Abordagem Híbrida
|
|
398
|
-
|
|
399
|
-
**Quando usar:**
|
|
400
|
-
- SaaS com AI + analytics complexos
|
|
401
|
-
- Dashboards com charts + chat AI
|
|
402
|
-
- Aplicações enterprise completas
|
|
403
|
-
|
|
404
|
-
**Pattern:**
|
|
405
|
-
- **Base:** Fluent UI (layout, navegação, AI)
|
|
406
|
-
- **Complemento:** MudBlazor (grids, charts)
|
|
407
|
-
|
|
408
|
-
```razor
|
|
409
|
-
<FluentLayout>
|
|
410
|
-
<FluentHeader>...</FluentHeader>
|
|
411
|
-
<FluentMain>
|
|
412
|
-
@* Grid complexo *@
|
|
413
|
-
<MudDataGrid ... />
|
|
414
|
-
|
|
415
|
-
@* Chat AI *@
|
|
416
|
-
<FluentMessageBar>AI response</FluentMessageBar>
|
|
417
|
-
</FluentMain>
|
|
418
|
-
</FluentLayout>
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
---
|
|
422
|
-
|
|
423
|
-
## 🎯 Novas Features .NET 10
|
|
424
|
-
|
|
425
|
-
### State Persistence
|
|
426
|
-
|
|
427
|
-
**Novo:** Propriedades com `[PersistentState]` são persist idas automaticamente.
|
|
428
|
-
|
|
429
|
-
```razor
|
|
430
|
-
@page "/counter"
|
|
431
|
-
|
|
432
|
-
<button @onclick="Increment">Count: @Count</button>
|
|
433
|
-
|
|
434
|
-
@code {
|
|
435
|
-
// Persiste automaticamente em pre-rendering e circuit disconnections
|
|
436
|
-
[PersistentState]
|
|
437
|
-
private int Count { get; set; } = 0;
|
|
438
|
-
|
|
439
|
-
private void Increment() => Count++;
|
|
440
|
-
}
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
**Quando usar:**
|
|
444
|
-
- Componentes com estado que precisam sobreviver a pre-rendering
|
|
445
|
-
- Aplicações com circuit disconnections frequentes
|
|
446
|
-
- Formulários multi-step
|
|
447
|
-
|
|
448
|
-
**Não usar para:**
|
|
449
|
-
- Dados sensíveis (passwords, tokens)
|
|
450
|
-
- Estado que deve ser recalculado (derived state)
|
|
451
|
-
|
|
452
|
-
### Circuit Pause/Resume
|
|
453
|
-
|
|
454
|
-
**Novo:** APIs JavaScript para pausar/resumir circuits.
|
|
455
|
-
|
|
456
|
-
```razor
|
|
457
|
-
@inject IJSRuntime JS
|
|
458
|
-
|
|
459
|
-
@code {
|
|
460
|
-
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
461
|
-
{
|
|
462
|
-
if (firstRender)
|
|
463
|
-
{
|
|
464
|
-
await JS.InvokeVoidAsync("setupCircuitManagement");
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
```
|
|
469
|
-
|
|
470
|
-
```javascript
|
|
471
|
-
// wwwroot/app.js
|
|
472
|
-
function setupCircuitManagement() {
|
|
473
|
-
// Pausar quando usuário minimiza/troca de aba
|
|
474
|
-
document.addEventListener('visibilitychange', () => {
|
|
475
|
-
if (document.hidden) {
|
|
476
|
-
Blazor.pauseCircuit(); // Libera recursos do servidor
|
|
477
|
-
} else {
|
|
478
|
-
Blazor.resumeCircuit(); // Restaura estado
|
|
479
|
-
}
|
|
480
|
-
});
|
|
481
|
-
}
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
**Benefícios:**
|
|
485
|
-
- Reduz uso de memória do servidor
|
|
486
|
-
- Melhora escalabilidade
|
|
487
|
-
- Estado mantido durante pausa
|
|
488
|
-
|
|
489
|
-
### Blazor Metrics & Observability
|
|
490
|
-
|
|
491
|
-
**Novo:** Métricas específicas de Blazor Server.
|
|
492
|
-
|
|
493
|
-
```csharp
|
|
494
|
-
// Program.cs
|
|
495
|
-
builder.Services.AddOpenTelemetry()
|
|
496
|
-
.WithTracing(tracing =>
|
|
497
|
-
{
|
|
498
|
-
tracing.AddSource("Microsoft.AspNetCore.Components.Server");
|
|
499
|
-
tracing.AddAspireTracing();
|
|
500
|
-
})
|
|
501
|
-
.WithMetrics(metrics =>
|
|
502
|
-
{
|
|
503
|
-
metrics.AddMeter("Microsoft.AspNetCore.Components.Server");
|
|
504
|
-
metrics.AddAspireMetrics();
|
|
505
|
-
});
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
**Métricas disponíveis:**
|
|
509
|
-
- Page navigations (por rota/componente)
|
|
510
|
-
- UI events (eventos e duração)
|
|
511
|
-
- Component lifecycle (render diff sizes)
|
|
512
|
-
- Active circuits (usuários simultâneos)
|
|
513
|
-
- Circuit state (connected/disconnected)
|
|
514
|
-
|
|
515
|
-
**Visualização:** Aspire Dashboard integrado.
|
|
516
|
-
|
|
517
|
-
### Hot Reload Aprimorado
|
|
518
|
-
|
|
519
|
-
**Automático:** 10x mais rápido no Visual Studio 2026.
|
|
520
|
-
|
|
521
|
-
**Nada a fazer:** Apenas use VS 2026 Preview ou `dotnet watch`.
|
|
522
|
-
|
|
523
|
-
### Formulários com Validação Aninhada
|
|
524
|
-
|
|
525
|
-
**Novo:** Validação automática de modelos aninhados.
|
|
526
|
-
|
|
527
|
-
```csharp
|
|
528
|
-
public class Order
|
|
529
|
-
{
|
|
530
|
-
[Required]
|
|
531
|
-
public string OrderNumber { get; set; } = null!;
|
|
532
|
-
|
|
533
|
-
// Modelo aninhado - validado automaticamente
|
|
534
|
-
public Customer Customer { get; set; } = new();
|
|
535
|
-
public List<OrderItem> Items { get; set; } = new();
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
public class Customer
|
|
539
|
-
{
|
|
540
|
-
[Required]
|
|
541
|
-
public string Name { get; set; } = null!;
|
|
542
|
-
|
|
543
|
-
[EmailAddress]
|
|
544
|
-
public string Email { get; set; } = null!;
|
|
545
|
-
|
|
546
|
-
// Aninhamento profundo - também validado
|
|
547
|
-
public Address ShippingAddress { get; set; } = new();
|
|
548
|
-
}
|
|
549
|
-
```
|
|
550
|
-
|
|
551
|
-
```razor
|
|
552
|
-
<EditForm Model="@_order" OnValidSubmit="HandleSubmit">
|
|
553
|
-
<DataAnnotationsValidator />
|
|
554
|
-
<ValidationSummary />
|
|
555
|
-
<!-- Campos... -->
|
|
556
|
-
</EditForm>
|
|
557
|
-
```
|
|
558
|
-
|
|
559
|
-
**Configuração (Program.cs):**
|
|
560
|
-
```csharp
|
|
561
|
-
builder.Services.AddValidation(); // Habilita validação aninhada
|
|
562
|
-
```
|
|
563
|
-
|
|
564
|
-
---
|
|
565
|
-
|
|
566
|
-
## 📚 Documentação de Referência
|
|
567
|
-
|
|
568
|
-
- [Blazor Documentation](https://learn.microsoft.com/aspnet/core/blazor/)
|
|
569
|
-
- [Entity Framework Core 10](https://learn.microsoft.com/ef/core/)
|
|
570
|
-
- [ASP.NET Core 10](https://learn.microsoft.com/aspnet/core/)
|
|
571
|
-
- [Hangfire](https://docs.hangfire.io/)
|
|
572
|
-
- **[Passkeys/WebAuthn](../../.morph/standards/passkeys-auth.md)**
|
|
573
|
-
- **[Agent Framework](../../.morph/standards/agent-framework-setup.md)**
|
|
574
|
-
|
|
575
|
-
## Checklist de Projeto
|
|
576
|
-
|
|
577
|
-
- [ ] Estrutura de camadas (Domain, Application, Infrastructure, Web)
|
|
578
|
-
- [ ] EF Core configurado com migrations
|
|
579
|
-
- [ ] Blazor Server com componentes reutilizáveis
|
|
580
|
-
- [ ] Services com injeção de dependência
|
|
581
|
-
- [ ] Logging estruturado
|
|
582
|
-
- [ ] Validação com FluentValidation ou DataAnnotations
|
|
583
|
-
- [ ] Hangfire para background jobs
|
|
584
|
-
- [ ] Dockerfile para containerização
|
|
585
|
-
|
|
586
|
-
---
|
|
587
|
-
|
|
588
|
-
*MORPH-SPEC by Polymorphism Tech*
|
|
1
|
+
# .NET + Blazor Stack
|
|
2
|
+
|
|
3
|
+
Stack principal para aplicações web com .NET e Blazor Server.
|
|
4
|
+
|
|
5
|
+
| Aspecto | Tecnologia |
|
|
6
|
+
|---------|------------|
|
|
7
|
+
| **Backend** | .NET 10 / C# 14 |
|
|
8
|
+
| **Frontend** | Blazor Server |
|
|
9
|
+
| **Database** | EF Core 10 + Azure SQL |
|
|
10
|
+
| **Hosting** | Azure Container Apps |
|
|
11
|
+
| **Background** | Hangfire |
|
|
12
|
+
| **AI** | Microsoft Agent Framework |
|
|
13
|
+
|
|
14
|
+
**Triggers:** `blazor`, `razor`, `server-side`, `.net`, `csharp`, `dotnet`
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Critical Standards (Read FIRST)
|
|
19
|
+
|
|
20
|
+
| Standard | What |
|
|
21
|
+
|----------|------|
|
|
22
|
+
| `framework/standards/coding.md` | **C# naming conventions, code style, .editorconfig template** |
|
|
23
|
+
| `framework/standards/architecture.md` | **Clean Architecture layers, SOLID, service patterns** |
|
|
24
|
+
| `framework/standards/blazor-efcore.md` | DbContext concurrency, Repository Factory, background ops, migrations |
|
|
25
|
+
| `framework/standards/blazor-pitfalls.md` | Common Blazor issues & solutions |
|
|
26
|
+
| `framework/standards/fluent-ui-blazor.md` | Fluent UI APIs, icon sizes, dialog patterns |
|
|
27
|
+
| `framework/standards/blazor-lifecycle.md` | Component lifecycle patterns |
|
|
28
|
+
| `framework/standards/program-cs-checklist.md` | Required Program.cs setup |
|
|
29
|
+
|
|
30
|
+
### Quick Checklist
|
|
31
|
+
- [ ] Background ops: Use `IDbContextFactory` / Repository Factory (ref: blazor-efcore.md)
|
|
32
|
+
- [ ] JSRuntime: ONLY in `OnAfterRenderAsync(firstRender)`
|
|
33
|
+
- [ ] Program.cs: `UseStaticFiles()` BEFORE `UseAntiforgery()`
|
|
34
|
+
- [ ] File Upload: Specify `maxAllowedSize` in `OpenReadStream()`
|
|
35
|
+
- [ ] RenderMode: NO `@rendermode` on MainLayout
|
|
36
|
+
- [ ] Package Versions: MudBlazor >= 8.15.0 for .NET 10
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Mandatory Code Patterns
|
|
41
|
+
|
|
42
|
+
### Status Validation
|
|
43
|
+
|
|
44
|
+
```csharp
|
|
45
|
+
// ✅ Validate INVALID states (allows future extensions)
|
|
46
|
+
if (order.Status >= OrderStatus.Completed || order.Status == OrderStatus.Failed)
|
|
47
|
+
throw new InvalidOperationException("Cannot process completed or failed order");
|
|
48
|
+
|
|
49
|
+
// ❌ Never assume single valid flow
|
|
50
|
+
if (order.Status != OrderStatus.PendingPayment)
|
|
51
|
+
throw new InvalidOperationException("Invalid status");
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Enums with Logical Order
|
|
55
|
+
|
|
56
|
+
```csharp
|
|
57
|
+
public enum OrderStatus
|
|
58
|
+
{
|
|
59
|
+
Created = 0, PendingPayment = 1, Processing = 2, Completed = 3, // Normal flow
|
|
60
|
+
Failed = 100, Cancelled = 101, Refunded = 102 // Error states (high values)
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Service Pattern
|
|
65
|
+
|
|
66
|
+
```csharp
|
|
67
|
+
public async Task<Result<Order>> ProcessAsync(Guid orderId, CancellationToken ct)
|
|
68
|
+
{
|
|
69
|
+
_logger.LogInformation("Processing order {OrderId}", orderId);
|
|
70
|
+
var order = await _repository.GetByIdAsync(orderId, ct);
|
|
71
|
+
if (order == null) return Result.Failure<Order>("Order not found");
|
|
72
|
+
if (order.Status >= OrderStatus.Completed)
|
|
73
|
+
return Result.Failure<Order>("Order already completed");
|
|
74
|
+
// ... process ...
|
|
75
|
+
return Result.Success(order);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Rules:** Logging at critical points, CancellationToken propagated, Result pattern for business errors, exceptions for infrastructure.
|
|
80
|
+
|
|
81
|
+
**More patterns:** See `code-review.md` for DTOs/contracts naming and service checklists.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Project Structure
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
src/
|
|
89
|
+
├── {App}.Domain/ # Entities, Value Objects, Enums, Exceptions
|
|
90
|
+
├── {App}.Application/ # Services, DTOs, Interfaces, Validators
|
|
91
|
+
├── {App}.Infrastructure/ # EF Core (DbContext, Configs, Migrations), External Services
|
|
92
|
+
├── {App}.Web/ # Blazor Server (Program.cs, Components, Pages, wwwroot)
|
|
93
|
+
└── tests/ # UnitTests, IntegrationTests
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Program.cs Essentials
|
|
97
|
+
|
|
98
|
+
```csharp
|
|
99
|
+
var builder = WebApplication.CreateBuilder(args);
|
|
100
|
+
builder.Services.AddRazorComponents().AddInteractiveServerComponents();
|
|
101
|
+
builder.Services.AddDbContext<AppDbContext>(o => o.UseSqlServer(connString));
|
|
102
|
+
builder.Services.AddDbContextFactory<AppDbContext>(o => o.UseSqlServer(connString));
|
|
103
|
+
// Register services, factories, Hangfire...
|
|
104
|
+
|
|
105
|
+
var app = builder.Build();
|
|
106
|
+
app.UseHttpsRedirection();
|
|
107
|
+
app.UseStaticFiles(); // BEFORE UseAntiforgery!
|
|
108
|
+
app.UseAntiforgery();
|
|
109
|
+
app.MapRazorComponents<App>().AddInteractiveServerRenderMode();
|
|
110
|
+
app.Run();
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Blazor Component Patterns
|
|
116
|
+
|
|
117
|
+
### Page with List
|
|
118
|
+
|
|
119
|
+
```razor
|
|
120
|
+
@page "/orders"
|
|
121
|
+
@inject IOrderService OrderService
|
|
122
|
+
|
|
123
|
+
@if (_orders is null) { <Loading /> }
|
|
124
|
+
else if (!_orders.Any()) { <EmptyState Message="No orders found" /> }
|
|
125
|
+
else
|
|
126
|
+
{
|
|
127
|
+
@foreach (var order in _orders)
|
|
128
|
+
{
|
|
129
|
+
<FluentCard>@order.OrderNumber - @order.Total.ToString("C")</FluentCard>
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
@code {
|
|
134
|
+
private List<OrderDto>? _orders;
|
|
135
|
+
protected override async Task OnInitializedAsync()
|
|
136
|
+
=> _orders = await OrderService.GetAllAsync();
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Form with Validation
|
|
141
|
+
|
|
142
|
+
```razor
|
|
143
|
+
@page "/orders/new"
|
|
144
|
+
<EditForm Model="_model" OnValidSubmit="HandleSubmit">
|
|
145
|
+
<DataAnnotationsValidator />
|
|
146
|
+
<InputSelect @bind-Value="_model.CustomerId">...</InputSelect>
|
|
147
|
+
<ValidationMessage For="() => _model.CustomerId" />
|
|
148
|
+
<button type="submit" disabled="@_isSubmitting">Save</button>
|
|
149
|
+
</EditForm>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## UI Libraries
|
|
155
|
+
|
|
156
|
+
> **Decision matrix:** See `ui-ux-designer.md` skill for full comparison.
|
|
157
|
+
|
|
158
|
+
| Library | When | Key Advantage |
|
|
159
|
+
|---------|------|---------------|
|
|
160
|
+
| **Fluent UI** | AI-first, Microsoft stack | Performance (~200KB), AI components |
|
|
161
|
+
| **MudBlazor** | Complex dashboards | 140+ components, charts |
|
|
162
|
+
| **Hybrid** | SaaS with AI + analytics | Best of both |
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## .NET 10 Features
|
|
167
|
+
|
|
168
|
+
### PersistentState (new)
|
|
169
|
+
```razor
|
|
170
|
+
@code {
|
|
171
|
+
[PersistentState]
|
|
172
|
+
private int Count { get; set; } = 0; // Survives pre-rendering & circuit disconnections
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Circuit Pause/Resume (new)
|
|
177
|
+
```javascript
|
|
178
|
+
document.addEventListener('visibilitychange', () => {
|
|
179
|
+
document.hidden ? Blazor.pauseCircuit() : Blazor.resumeCircuit();
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Nested Model Validation (new)
|
|
184
|
+
```csharp
|
|
185
|
+
builder.Services.AddValidation(); // Enables automatic nested model validation
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Blazor Metrics
|
|
189
|
+
```csharp
|
|
190
|
+
builder.Services.AddOpenTelemetry()
|
|
191
|
+
.WithTracing(t => t.AddSource("Microsoft.AspNetCore.Components.Server"))
|
|
192
|
+
.WithMetrics(m => m.AddMeter("Microsoft.AspNetCore.Components.Server"));
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Project Checklist
|
|
198
|
+
|
|
199
|
+
- [ ] Clean Architecture layers (Domain, Application, Infrastructure, Web)
|
|
200
|
+
- [ ] EF Core with migrations + IDbContextFactory
|
|
201
|
+
- [ ] Repository Factory for background ops (ref: blazor-efcore.md)
|
|
202
|
+
- [ ] Blazor Server with reusable components
|
|
203
|
+
- [ ] Services with DI + structured logging
|
|
204
|
+
- [ ] Validation (FluentValidation or DataAnnotations)
|
|
205
|
+
- [ ] Hangfire for background jobs
|
|
206
|
+
- [ ] Dockerfile for containerization
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
*MORPH-SPEC by Polymorphism Tech*
|