@polymorphism-tech/morph-spec 2.3.0 → 3.0.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 +446 -1730
- package/README.md +515 -516
- package/bin/morph-spec.js +366 -294
- package/bin/task-manager.js +429 -368
- package/bin/validate.js +369 -268
- package/content/.claude/commands/morph-apply.md +221 -158
- package/content/.claude/commands/morph-deploy.md +529 -0
- 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/skills/infra/azure-deploy-specialist.md +699 -0
- package/content/.claude/skills/level-0-meta/README.md +7 -0
- package/content/.claude/skills/level-0-meta/code-review.md +226 -0
- package/content/.claude/skills/level-0-meta/morph-checklist.md +117 -0
- package/content/.claude/skills/level-0-meta/simulation-checklist.md +77 -0
- package/content/.claude/skills/level-1-workflows/README.md +7 -0
- package/content/.claude/skills/level-1-workflows/morph-replicate.md +213 -0
- package/content/.claude/{commands/morph-clarify.md → skills/level-1-workflows/phase-clarify.md} +131 -184
- package/content/.claude/{commands/morph-design.md → skills/level-1-workflows/phase-design.md} +213 -275
- package/content/.claude/skills/level-1-workflows/phase-setup.md +106 -0
- package/content/.claude/skills/level-1-workflows/phase-tasks.md +164 -0
- package/content/.claude/{commands/morph-uiux.md → skills/level-1-workflows/phase-uiux.md} +169 -211
- package/content/.claude/skills/level-2-domains/README.md +14 -0
- package/content/.claude/skills/level-2-domains/ai-agents/ai-system-architect.md +192 -0
- package/content/.claude/skills/{specialists → level-2-domains/architecture}/po-pm-advisor.md +197 -197
- package/content/.claude/skills/level-2-domains/architecture/standards-architect.md +156 -0
- package/content/.claude/skills/level-2-domains/backend/dotnet-senior.md +287 -0
- package/content/.claude/skills/level-2-domains/backend/ef-modeler.md +113 -0
- package/content/.claude/skills/level-2-domains/backend/hangfire-orchestrator.md +126 -0
- package/content/.claude/skills/level-2-domains/backend/ms-agent-expert.md +109 -0
- package/content/.claude/skills/level-2-domains/frontend/blazor-builder.md +210 -0
- package/content/.claude/skills/level-2-domains/frontend/nextjs-expert.md +154 -0
- package/content/.claude/skills/level-2-domains/frontend/ui-ux-designer.md +191 -0
- package/content/.claude/skills/{specialists → level-2-domains/infrastructure}/azure-architect.md +142 -142
- package/content/.claude/skills/level-2-domains/infrastructure/bicep-architect.md +126 -0
- package/content/.claude/skills/level-2-domains/infrastructure/container-specialist.md +131 -0
- package/content/.claude/skills/level-2-domains/infrastructure/devops-engineer.md +119 -0
- package/content/.claude/skills/level-2-domains/integrations/asaas-financial.md +130 -0
- package/content/.claude/skills/level-2-domains/integrations/azure-identity.md +142 -0
- package/content/.claude/skills/level-2-domains/integrations/clerk-auth.md +108 -0
- package/content/.claude/skills/level-2-domains/integrations/resend-email.md +119 -0
- package/content/.claude/skills/level-2-domains/quality/code-analyzer.md +235 -0
- package/content/.claude/skills/level-2-domains/quality/testing-specialist.md +126 -0
- package/content/.claude/skills/level-3-technologies/README.md +7 -0
- package/content/.claude/skills/level-4-patterns/README.md +7 -0
- package/content/.claude/skills/specialists/prompt-engineer.md +189 -0
- package/content/.claude/skills/specialists/seo-growth-hacker.md +320 -0
- package/content/.morph/config/agents.json +762 -242
- package/content/.morph/config/config.template.json +122 -108
- package/content/.morph/docs/workflows/design-impl.md +37 -0
- package/content/.morph/docs/workflows/enforcement-pipeline.md +668 -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/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/hooks/README.md +348 -239
- package/content/.morph/hooks/pre-commit-agents.sh +24 -24
- package/content/.morph/hooks/task-completed.js +73 -0
- package/content/.morph/hooks/teammate-idle.js +68 -0
- package/content/.morph/schemas/tasks.schema.json +220 -0
- 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/agent-teams-workflow.md +474 -0
- package/content/.morph/standards/architecture.md +325 -325
- package/content/.morph/standards/azure.md +605 -379
- package/content/.morph/standards/dotnet10-migration.md +520 -494
- package/content/.morph/templates/CONTEXT-FEATURE.md +276 -0
- package/content/.morph/templates/CONTEXT.md +170 -0
- package/content/.morph/templates/agent.cs +163 -172
- package/content/.morph/templates/clarify-questions.md +159 -0
- 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/decisions.md +123 -106
- package/content/.morph/templates/infra/azure-pipelines-deploy.yml +480 -0
- package/content/.morph/templates/infra/deploy-checklist.md +426 -0
- package/content/.morph/templates/proposal.md +141 -155
- package/content/.morph/templates/recap.md +94 -105
- package/content/.morph/templates/simulation.md +353 -0
- package/content/.morph/templates/spec.md +149 -148
- package/content/.morph/templates/state.template.json +222 -222
- package/content/.morph/templates/tasks.md +257 -235
- package/content/.morph/templates/ui-components.md +362 -276
- package/content/CLAUDE.md +150 -442
- package/detectors/structure-detector.js +245 -250
- package/docs/README.md +144 -149
- package/docs/getting-started.md +301 -302
- package/docs/installation.md +361 -361
- package/docs/validation-checklist.md +265 -266
- package/package.json +80 -80
- package/src/commands/advance-phase.js +266 -0
- package/src/commands/analyze-blazor-concurrency.js +193 -0
- package/src/commands/deploy.js +780 -0
- package/src/commands/detect-agents.js +167 -0
- package/src/commands/doctor.js +356 -280
- package/src/commands/generate-context.js +40 -0
- 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/task.js +78 -75
- 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/context-generator.js +513 -0
- package/src/lib/continuous-validator.js +421 -440
- package/src/lib/css-validator.js +352 -0
- package/src/lib/decision-constraint-loader.js +109 -0
- package/src/lib/design-system-detector.js +187 -0
- package/src/lib/design-system-scaffolder.js +299 -0
- package/src/lib/hook-executor.js +256 -0
- package/src/lib/recap-generator.js +205 -0
- package/src/lib/spec-validator.js +258 -0
- package/src/lib/standards-context-injector.js +287 -0
- package/src/lib/state-manager.js +397 -340
- package/src/lib/team-orchestrator.js +322 -0
- package/src/lib/troubleshoot-grep.js +194 -0
- package/src/lib/troubleshoot-index.js +144 -0
- package/src/lib/validation-runner.js +283 -0
- package/src/lib/validators/contract-compliance-validator.js +273 -0
- package/src/lib/validators/design-system-validator.js +231 -0
- package/src/utils/file-copier.js +187 -139
- package/content/.claude/commands/morph-costs.md +0 -206
- package/content/.claude/commands/morph-setup.md +0 -100
- package/content/.claude/commands/morph-tasks.md +0 -319
- package/content/.claude/skills/infra/bicep-architect.md +0 -419
- package/content/.claude/skills/infra/container-specialist.md +0 -437
- package/content/.claude/skills/infra/devops-engineer.md +0 -405
- package/content/.claude/skills/integrations/asaas-financial.md +0 -333
- package/content/.claude/skills/integrations/azure-identity.md +0 -309
- package/content/.claude/skills/integrations/clerk-auth.md +0 -290
- package/content/.claude/skills/specialists/ai-system-architect.md +0 -604
- package/content/.claude/skills/specialists/cost-guardian.md +0 -110
- package/content/.claude/skills/specialists/ef-modeler.md +0 -211
- package/content/.claude/skills/specialists/hangfire-orchestrator.md +0 -255
- package/content/.claude/skills/specialists/ms-agent-expert.md +0 -263
- package/content/.claude/skills/specialists/standards-architect.md +0 -78
- package/content/.claude/skills/specialists/ui-ux-designer.md +0 -1100
- package/content/.claude/skills/stacks/dotnet-blazor.md +0 -606
- package/content/.claude/skills/stacks/dotnet-nextjs.md +0 -402
- 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,606 +0,0 @@
|
|
|
1
|
-
# .NET + Blazor Stack
|
|
2
|
-
|
|
3
|
-
Stack principal para desenvolvimento de aplicações web com .NET e Blazor Server.
|
|
4
|
-
|
|
5
|
-
## Visão Geral
|
|
6
|
-
|
|
7
|
-
| Aspecto | Tecnologia |
|
|
8
|
-
|---------|------------|
|
|
9
|
-
| **Backend** | .NET 10 / C# 14 |
|
|
10
|
-
| **Frontend** | Blazor Server |
|
|
11
|
-
| **Database** | Entity Framework Core 10 + Azure SQL |
|
|
12
|
-
| **Hosting** | Azure Container Apps |
|
|
13
|
-
| **Background** | Hangfire |
|
|
14
|
-
| **AI** | Microsoft Agent Framework (exclusivo) |
|
|
15
|
-
|
|
16
|
-
## Triggers
|
|
17
|
-
|
|
18
|
-
Keywords: `blazor`, `razor`, `server-side`, `.net`, `csharp`, `dotnet`
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## ⚠️ CRITICAL PITFALLS (Read FIRST!)
|
|
23
|
-
|
|
24
|
-
**ALWAYS consult framework standards before implementing:**
|
|
25
|
-
- `framework/standards/blazor-pitfalls.md` - Common issues & solutions
|
|
26
|
-
- `framework/standards/blazor-lifecycle.md` - Lifecycle patterns
|
|
27
|
-
- `framework/standards/program-cs-checklist.md` - Required Program.cs setup
|
|
28
|
-
- `framework/standards/dotnet10-compatibility.md` - Package compatibility
|
|
29
|
-
|
|
30
|
-
**Quick Checklist:**
|
|
31
|
-
- [ ] DI Pattern: Use HttpClient, NOT direct Application layer injection
|
|
32
|
-
- [ ] Lifecycle: JSRuntime ONLY in OnAfterRenderAsync(firstRender)
|
|
33
|
-
- [ ] Program.cs: app.UseStaticFiles() BEFORE app.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
|
-
## Estrutura de Projeto
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
src/
|
|
42
|
-
├── {App}.Domain/ # Entidades, Value Objects, Enums
|
|
43
|
-
│ ├── Entities/
|
|
44
|
-
│ ├── ValueObjects/
|
|
45
|
-
│ ├── Enums/
|
|
46
|
-
│ └── Exceptions/
|
|
47
|
-
│
|
|
48
|
-
├── {App}.Application/ # Serviços, DTOs, Interfaces
|
|
49
|
-
│ ├── Services/
|
|
50
|
-
│ ├── DTOs/
|
|
51
|
-
│ ├── Interfaces/
|
|
52
|
-
│ └── Validators/
|
|
53
|
-
│
|
|
54
|
-
├── {App}.Infrastructure/ # EF Core, External Services
|
|
55
|
-
│ ├── Data/
|
|
56
|
-
│ │ ├── AppDbContext.cs
|
|
57
|
-
│ │ ├── Configurations/
|
|
58
|
-
│ │ └── Migrations/
|
|
59
|
-
│ ├── Services/
|
|
60
|
-
│ └── Extensions/
|
|
61
|
-
│
|
|
62
|
-
├── {App}.Web/ # Blazor Server
|
|
63
|
-
│ ├── Program.cs
|
|
64
|
-
│ ├── Components/
|
|
65
|
-
│ │ ├── Layout/
|
|
66
|
-
│ │ ├── Pages/
|
|
67
|
-
│ │ └── Shared/
|
|
68
|
-
│ ├── wwwroot/
|
|
69
|
-
│ └── appsettings.json
|
|
70
|
-
│
|
|
71
|
-
└── tests/
|
|
72
|
-
├── {App}.UnitTests/
|
|
73
|
-
└── {App}.IntegrationTests/
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
## Configuração do Projeto
|
|
77
|
-
|
|
78
|
-
### csproj principal
|
|
79
|
-
|
|
80
|
-
```xml
|
|
81
|
-
<!-- {App}.Web.csproj -->
|
|
82
|
-
<Project Sdk="Microsoft.NET.Sdk.Web">
|
|
83
|
-
<PropertyGroup>
|
|
84
|
-
<TargetFramework>net10.0</TargetFramework>
|
|
85
|
-
<Nullable>enable</Nullable>
|
|
86
|
-
<ImplicitUsings>enable</ImplicitUsings>
|
|
87
|
-
</PropertyGroup>
|
|
88
|
-
|
|
89
|
-
<ItemGroup>
|
|
90
|
-
<ProjectReference Include="..\{App}.Application\{App}.Application.csproj" />
|
|
91
|
-
<ProjectReference Include="..\{App}.Infrastructure\{App}.Infrastructure.csproj" />
|
|
92
|
-
</ItemGroup>
|
|
93
|
-
</Project>
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### Program.cs
|
|
97
|
-
|
|
98
|
-
```csharp
|
|
99
|
-
var builder = WebApplication.CreateBuilder(args);
|
|
100
|
-
|
|
101
|
-
// Services
|
|
102
|
-
builder.Services.AddRazorComponents()
|
|
103
|
-
.AddInteractiveServerComponents();
|
|
104
|
-
|
|
105
|
-
// Database
|
|
106
|
-
builder.Services.AddDbContext<AppDbContext>(options =>
|
|
107
|
-
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
|
|
108
|
-
|
|
109
|
-
// Application Services
|
|
110
|
-
builder.Services.AddScoped<IOrderService, OrderService>();
|
|
111
|
-
builder.Services.AddScoped<ICustomerService, CustomerService>();
|
|
112
|
-
|
|
113
|
-
// Hangfire
|
|
114
|
-
builder.Services.AddHangfire(config => config
|
|
115
|
-
.UseSqlServerStorage(builder.Configuration.GetConnectionString("HangfireConnection")));
|
|
116
|
-
builder.Services.AddHangfireServer();
|
|
117
|
-
|
|
118
|
-
var app = builder.Build();
|
|
119
|
-
|
|
120
|
-
// Pipeline
|
|
121
|
-
if (!app.Environment.IsDevelopment())
|
|
122
|
-
{
|
|
123
|
-
app.UseExceptionHandler("/Error");
|
|
124
|
-
app.UseHsts();
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
app.UseHttpsRedirection();
|
|
128
|
-
app.UseStaticFiles();
|
|
129
|
-
app.UseAntiforgery();
|
|
130
|
-
|
|
131
|
-
app.MapRazorComponents<App>()
|
|
132
|
-
.AddInteractiveServerRenderMode();
|
|
133
|
-
|
|
134
|
-
app.MapHangfireDashboard("/hangfire");
|
|
135
|
-
|
|
136
|
-
app.Run();
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
## Componentes Blazor
|
|
140
|
-
|
|
141
|
-
### Padrões de Componente
|
|
142
|
-
|
|
143
|
-
```razor
|
|
144
|
-
@* Components/Pages/Orders/OrderList.razor *@
|
|
145
|
-
@page "/orders"
|
|
146
|
-
@inject IOrderService OrderService
|
|
147
|
-
@inject NavigationManager Navigation
|
|
148
|
-
|
|
149
|
-
<PageTitle>Pedidos</PageTitle>
|
|
150
|
-
|
|
151
|
-
<div class="container mx-auto p-4">
|
|
152
|
-
<div class="flex justify-between items-center mb-6">
|
|
153
|
-
<h1 class="text-2xl font-bold">Pedidos</h1>
|
|
154
|
-
<button @onclick="CreateNew" class="btn btn-primary">
|
|
155
|
-
Novo Pedido
|
|
156
|
-
</button>
|
|
157
|
-
</div>
|
|
158
|
-
|
|
159
|
-
@if (_orders is null)
|
|
160
|
-
{
|
|
161
|
-
<Loading />
|
|
162
|
-
}
|
|
163
|
-
else if (!_orders.Any())
|
|
164
|
-
{
|
|
165
|
-
<EmptyState Message="Nenhum pedido encontrado" />
|
|
166
|
-
}
|
|
167
|
-
else
|
|
168
|
-
{
|
|
169
|
-
<DataTable Items="_orders">
|
|
170
|
-
<HeaderTemplate>
|
|
171
|
-
<th>Número</th>
|
|
172
|
-
<th>Cliente</th>
|
|
173
|
-
<th>Total</th>
|
|
174
|
-
<th>Status</th>
|
|
175
|
-
<th>Ações</th>
|
|
176
|
-
</HeaderTemplate>
|
|
177
|
-
<RowTemplate Context="order">
|
|
178
|
-
<td>@order.OrderNumber</td>
|
|
179
|
-
<td>@order.CustomerName</td>
|
|
180
|
-
<td>@order.Total.ToString("C")</td>
|
|
181
|
-
<td><StatusBadge Status="@order.Status" /></td>
|
|
182
|
-
<td>
|
|
183
|
-
<button @onclick="() => ViewOrder(order.Id)" class="btn btn-sm">
|
|
184
|
-
Ver
|
|
185
|
-
</button>
|
|
186
|
-
</td>
|
|
187
|
-
</RowTemplate>
|
|
188
|
-
</DataTable>
|
|
189
|
-
}
|
|
190
|
-
</div>
|
|
191
|
-
|
|
192
|
-
@code {
|
|
193
|
-
private List<OrderDto>? _orders;
|
|
194
|
-
|
|
195
|
-
protected override async Task OnInitializedAsync()
|
|
196
|
-
{
|
|
197
|
-
_orders = await OrderService.GetAllAsync();
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
private void CreateNew() => Navigation.NavigateTo("/orders/new");
|
|
201
|
-
|
|
202
|
-
private void ViewOrder(int id) => Navigation.NavigateTo($"/orders/{id}");
|
|
203
|
-
}
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
### Formulários
|
|
207
|
-
|
|
208
|
-
```razor
|
|
209
|
-
@* Components/Pages/Orders/OrderForm.razor *@
|
|
210
|
-
@page "/orders/new"
|
|
211
|
-
@page "/orders/{Id:int}/edit"
|
|
212
|
-
@inject IOrderService OrderService
|
|
213
|
-
@inject NavigationManager Navigation
|
|
214
|
-
|
|
215
|
-
<PageTitle>@(_isEdit ? "Editar" : "Novo") Pedido</PageTitle>
|
|
216
|
-
|
|
217
|
-
<EditForm Model="_model" OnValidSubmit="HandleSubmit">
|
|
218
|
-
<DataAnnotationsValidator />
|
|
219
|
-
|
|
220
|
-
<div class="space-y-4">
|
|
221
|
-
<div>
|
|
222
|
-
<label for="customerId">Cliente</label>
|
|
223
|
-
<InputSelect @bind-Value="_model.CustomerId" id="customerId" class="input">
|
|
224
|
-
<option value="">Selecione...</option>
|
|
225
|
-
@foreach (var customer in _customers)
|
|
226
|
-
{
|
|
227
|
-
<option value="@customer.Id">@customer.Name</option>
|
|
228
|
-
}
|
|
229
|
-
</InputSelect>
|
|
230
|
-
<ValidationMessage For="() => _model.CustomerId" />
|
|
231
|
-
</div>
|
|
232
|
-
|
|
233
|
-
<div>
|
|
234
|
-
<label for="notes">Observações</label>
|
|
235
|
-
<InputTextArea @bind-Value="_model.Notes" id="notes" class="input" />
|
|
236
|
-
</div>
|
|
237
|
-
|
|
238
|
-
<div class="flex gap-2">
|
|
239
|
-
<button type="submit" class="btn btn-primary" disabled="@_isSubmitting">
|
|
240
|
-
@if (_isSubmitting)
|
|
241
|
-
{
|
|
242
|
-
<span class="loading"></span>
|
|
243
|
-
}
|
|
244
|
-
Salvar
|
|
245
|
-
</button>
|
|
246
|
-
<button type="button" @onclick="Cancel" class="btn">Cancelar</button>
|
|
247
|
-
</div>
|
|
248
|
-
</div>
|
|
249
|
-
</EditForm>
|
|
250
|
-
|
|
251
|
-
@code {
|
|
252
|
-
[Parameter] public int? Id { get; set; }
|
|
253
|
-
|
|
254
|
-
private OrderFormModel _model = new();
|
|
255
|
-
private List<CustomerDto> _customers = new();
|
|
256
|
-
private bool _isEdit => Id.HasValue;
|
|
257
|
-
private bool _isSubmitting;
|
|
258
|
-
|
|
259
|
-
protected override async Task OnInitializedAsync()
|
|
260
|
-
{
|
|
261
|
-
_customers = await CustomerService.GetAllAsync();
|
|
262
|
-
|
|
263
|
-
if (_isEdit)
|
|
264
|
-
{
|
|
265
|
-
var order = await OrderService.GetByIdAsync(Id!.Value);
|
|
266
|
-
_model = new OrderFormModel
|
|
267
|
-
{
|
|
268
|
-
CustomerId = order.CustomerId,
|
|
269
|
-
Notes = order.Notes
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
private async Task HandleSubmit()
|
|
275
|
-
{
|
|
276
|
-
_isSubmitting = true;
|
|
277
|
-
|
|
278
|
-
try
|
|
279
|
-
{
|
|
280
|
-
if (_isEdit)
|
|
281
|
-
await OrderService.UpdateAsync(Id!.Value, _model);
|
|
282
|
-
else
|
|
283
|
-
await OrderService.CreateAsync(_model);
|
|
284
|
-
|
|
285
|
-
Navigation.NavigateTo("/orders");
|
|
286
|
-
}
|
|
287
|
-
finally
|
|
288
|
-
{
|
|
289
|
-
_isSubmitting = false;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
private void Cancel() => Navigation.NavigateTo("/orders");
|
|
294
|
-
}
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
## Services
|
|
298
|
-
|
|
299
|
-
```csharp
|
|
300
|
-
// Application/Services/OrderService.cs
|
|
301
|
-
public interface IOrderService
|
|
302
|
-
{
|
|
303
|
-
Task<List<OrderDto>> GetAllAsync(CancellationToken ct = default);
|
|
304
|
-
Task<OrderDto> GetByIdAsync(int id, CancellationToken ct = default);
|
|
305
|
-
Task<OrderDto> CreateAsync(CreateOrderRequest request, CancellationToken ct = default);
|
|
306
|
-
Task UpdateAsync(int id, UpdateOrderRequest request, CancellationToken ct = default);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
public class OrderService : IOrderService
|
|
310
|
-
{
|
|
311
|
-
private readonly AppDbContext _context;
|
|
312
|
-
private readonly ILogger<OrderService> _logger;
|
|
313
|
-
|
|
314
|
-
public OrderService(AppDbContext context, ILogger<OrderService> logger)
|
|
315
|
-
{
|
|
316
|
-
_context = context;
|
|
317
|
-
_logger = logger;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
public async Task<List<OrderDto>> GetAllAsync(CancellationToken ct = default)
|
|
321
|
-
{
|
|
322
|
-
return await _context.Orders
|
|
323
|
-
.Include(o => o.Customer)
|
|
324
|
-
.OrderByDescending(o => o.CreatedAt)
|
|
325
|
-
.Select(o => new OrderDto
|
|
326
|
-
{
|
|
327
|
-
Id = o.Id,
|
|
328
|
-
OrderNumber = o.OrderNumber,
|
|
329
|
-
CustomerName = o.Customer.Name,
|
|
330
|
-
Total = o.Total,
|
|
331
|
-
Status = o.Status.ToString()
|
|
332
|
-
})
|
|
333
|
-
.ToListAsync(ct);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
public async Task<OrderDto> CreateAsync(CreateOrderRequest request, CancellationToken ct = default)
|
|
337
|
-
{
|
|
338
|
-
var order = Order.Create(request.CustomerId, request.Items);
|
|
339
|
-
|
|
340
|
-
_context.Orders.Add(order);
|
|
341
|
-
await _context.SaveChangesAsync(ct);
|
|
342
|
-
|
|
343
|
-
_logger.LogInformation("Order {OrderNumber} created", order.OrderNumber);
|
|
344
|
-
|
|
345
|
-
return new OrderDto { /* map */ };
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
---
|
|
351
|
-
|
|
352
|
-
## 🎨 UI Component Libraries
|
|
353
|
-
|
|
354
|
-
### Recomendação para Projetos AI-First
|
|
355
|
-
|
|
356
|
-
| Biblioteca | Quando Usar | Vantagens | Desvantagens |
|
|
357
|
-
|------------|-------------|-----------|--------------|
|
|
358
|
-
| **Fluent UI** ⭐ | Projetos AI-first, Micro-SaaS | Componentes AI nativos, Microsoft integration, Performance (~200KB) | Menos componentes prontos |
|
|
359
|
-
| **MudBlazor** | SaaS tradicional, Analytics pesados | 140+ componentes, Charts nativos, Templates prontos | Mais pesado (~500KB), Sem componentes AI |
|
|
360
|
-
| **Híbrido** | SaaS complexo com AI | Melhor dos dois mundos | Maior bundle size (~350KB) |
|
|
361
|
-
|
|
362
|
-
### Fluent UI Blazor (Recomendado)
|
|
363
|
-
|
|
364
|
-
**Para:**
|
|
365
|
-
- Projetos com AI agents/chat
|
|
366
|
-
- Integração com Microsoft Agent Framework
|
|
367
|
-
- Produtos com UX Copilot-like
|
|
368
|
-
- Micro-SaaS que priorizam performance
|
|
369
|
-
|
|
370
|
-
**Setup rápido:**
|
|
371
|
-
```bash
|
|
372
|
-
dotnet add package Microsoft.FluentUI.AspNetCore.Components
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
```csharp
|
|
376
|
-
// Program.cs
|
|
377
|
-
builder.Services.AddFluentUIComponents();
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
**Exemplo de Chat AI:**
|
|
381
|
-
```razor
|
|
382
|
-
<FluentMessageBar Intent="MessageIntent.Success">
|
|
383
|
-
<FluentLabel Weight="FontWeight.Bold">AI Assistant</FluentLabel>
|
|
384
|
-
<FluentLabel>@_aiResponse</FluentLabel>
|
|
385
|
-
</FluentMessageBar>
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
**Guia completo:** [Fluent UI Setup](../../.morph/standards/fluent-ui-setup.md)
|
|
389
|
-
|
|
390
|
-
### MudBlazor (Complemento)
|
|
391
|
-
|
|
392
|
-
**Para:**
|
|
393
|
-
- Grids complexos com filtros avançados
|
|
394
|
-
- Charts e dashboards analytics
|
|
395
|
-
- Componentes que Fluent UI não tem
|
|
396
|
-
|
|
397
|
-
**Setup:**
|
|
398
|
-
```bash
|
|
399
|
-
dotnet add package MudBlazor
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
**Exemplo de Grid Avançado:**
|
|
403
|
-
```razor
|
|
404
|
-
<MudDataGrid T="Order" Items="@_orders"
|
|
405
|
-
Filterable="true"
|
|
406
|
-
Groupable="true"
|
|
407
|
-
Dense="true">
|
|
408
|
-
<Columns>
|
|
409
|
-
<PropertyColumn Property="x => x.OrderNumber" />
|
|
410
|
-
<PropertyColumn Property="x => x.Total" Format="C2" />
|
|
411
|
-
</Columns>
|
|
412
|
-
</MudDataGrid>
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
### Abordagem Híbrida
|
|
416
|
-
|
|
417
|
-
**Quando usar:**
|
|
418
|
-
- SaaS com AI + analytics complexos
|
|
419
|
-
- Dashboards com charts + chat AI
|
|
420
|
-
- Aplicações enterprise completas
|
|
421
|
-
|
|
422
|
-
**Pattern:**
|
|
423
|
-
- **Base:** Fluent UI (layout, navegação, AI)
|
|
424
|
-
- **Complemento:** MudBlazor (grids, charts)
|
|
425
|
-
|
|
426
|
-
```razor
|
|
427
|
-
<FluentLayout>
|
|
428
|
-
<FluentHeader>...</FluentHeader>
|
|
429
|
-
<FluentMain>
|
|
430
|
-
@* Grid complexo *@
|
|
431
|
-
<MudDataGrid ... />
|
|
432
|
-
|
|
433
|
-
@* Chat AI *@
|
|
434
|
-
<FluentMessageBar>AI response</FluentMessageBar>
|
|
435
|
-
</FluentMain>
|
|
436
|
-
</FluentLayout>
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
---
|
|
440
|
-
|
|
441
|
-
## 🎯 Novas Features .NET 10
|
|
442
|
-
|
|
443
|
-
### State Persistence
|
|
444
|
-
|
|
445
|
-
**Novo:** Propriedades com `[PersistentState]` são persist idas automaticamente.
|
|
446
|
-
|
|
447
|
-
```razor
|
|
448
|
-
@page "/counter"
|
|
449
|
-
|
|
450
|
-
<button @onclick="Increment">Count: @Count</button>
|
|
451
|
-
|
|
452
|
-
@code {
|
|
453
|
-
// Persiste automaticamente em pre-rendering e circuit disconnections
|
|
454
|
-
[PersistentState]
|
|
455
|
-
private int Count { get; set; } = 0;
|
|
456
|
-
|
|
457
|
-
private void Increment() => Count++;
|
|
458
|
-
}
|
|
459
|
-
```
|
|
460
|
-
|
|
461
|
-
**Quando usar:**
|
|
462
|
-
- Componentes com estado que precisam sobreviver a pre-rendering
|
|
463
|
-
- Aplicações com circuit disconnections frequentes
|
|
464
|
-
- Formulários multi-step
|
|
465
|
-
|
|
466
|
-
**Não usar para:**
|
|
467
|
-
- Dados sensíveis (passwords, tokens)
|
|
468
|
-
- Estado que deve ser recalculado (derived state)
|
|
469
|
-
|
|
470
|
-
### Circuit Pause/Resume
|
|
471
|
-
|
|
472
|
-
**Novo:** APIs JavaScript para pausar/resumir circuits.
|
|
473
|
-
|
|
474
|
-
```razor
|
|
475
|
-
@inject IJSRuntime JS
|
|
476
|
-
|
|
477
|
-
@code {
|
|
478
|
-
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
479
|
-
{
|
|
480
|
-
if (firstRender)
|
|
481
|
-
{
|
|
482
|
-
await JS.InvokeVoidAsync("setupCircuitManagement");
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
```javascript
|
|
489
|
-
// wwwroot/app.js
|
|
490
|
-
function setupCircuitManagement() {
|
|
491
|
-
// Pausar quando usuário minimiza/troca de aba
|
|
492
|
-
document.addEventListener('visibilitychange', () => {
|
|
493
|
-
if (document.hidden) {
|
|
494
|
-
Blazor.pauseCircuit(); // Libera recursos do servidor
|
|
495
|
-
} else {
|
|
496
|
-
Blazor.resumeCircuit(); // Restaura estado
|
|
497
|
-
}
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
```
|
|
501
|
-
|
|
502
|
-
**Benefícios:**
|
|
503
|
-
- Reduz uso de memória do servidor
|
|
504
|
-
- Melhora escalabilidade
|
|
505
|
-
- Estado mantido durante pausa
|
|
506
|
-
|
|
507
|
-
### Blazor Metrics & Observability
|
|
508
|
-
|
|
509
|
-
**Novo:** Métricas específicas de Blazor Server.
|
|
510
|
-
|
|
511
|
-
```csharp
|
|
512
|
-
// Program.cs
|
|
513
|
-
builder.Services.AddOpenTelemetry()
|
|
514
|
-
.WithTracing(tracing =>
|
|
515
|
-
{
|
|
516
|
-
tracing.AddSource("Microsoft.AspNetCore.Components.Server");
|
|
517
|
-
tracing.AddAspireTracing();
|
|
518
|
-
})
|
|
519
|
-
.WithMetrics(metrics =>
|
|
520
|
-
{
|
|
521
|
-
metrics.AddMeter("Microsoft.AspNetCore.Components.Server");
|
|
522
|
-
metrics.AddAspireMetrics();
|
|
523
|
-
});
|
|
524
|
-
```
|
|
525
|
-
|
|
526
|
-
**Métricas disponíveis:**
|
|
527
|
-
- Page navigations (por rota/componente)
|
|
528
|
-
- UI events (eventos e duração)
|
|
529
|
-
- Component lifecycle (render diff sizes)
|
|
530
|
-
- Active circuits (usuários simultâneos)
|
|
531
|
-
- Circuit state (connected/disconnected)
|
|
532
|
-
|
|
533
|
-
**Visualização:** Aspire Dashboard integrado.
|
|
534
|
-
|
|
535
|
-
### Hot Reload Aprimorado
|
|
536
|
-
|
|
537
|
-
**Automático:** 10x mais rápido no Visual Studio 2026.
|
|
538
|
-
|
|
539
|
-
**Nada a fazer:** Apenas use VS 2026 Preview ou `dotnet watch`.
|
|
540
|
-
|
|
541
|
-
### Formulários com Validação Aninhada
|
|
542
|
-
|
|
543
|
-
**Novo:** Validação automática de modelos aninhados.
|
|
544
|
-
|
|
545
|
-
```csharp
|
|
546
|
-
public class Order
|
|
547
|
-
{
|
|
548
|
-
[Required]
|
|
549
|
-
public string OrderNumber { get; set; } = null!;
|
|
550
|
-
|
|
551
|
-
// Modelo aninhado - validado automaticamente
|
|
552
|
-
public Customer Customer { get; set; } = new();
|
|
553
|
-
public List<OrderItem> Items { get; set; } = new();
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
public class Customer
|
|
557
|
-
{
|
|
558
|
-
[Required]
|
|
559
|
-
public string Name { get; set; } = null!;
|
|
560
|
-
|
|
561
|
-
[EmailAddress]
|
|
562
|
-
public string Email { get; set; } = null!;
|
|
563
|
-
|
|
564
|
-
// Aninhamento profundo - também validado
|
|
565
|
-
public Address ShippingAddress { get; set; } = new();
|
|
566
|
-
}
|
|
567
|
-
```
|
|
568
|
-
|
|
569
|
-
```razor
|
|
570
|
-
<EditForm Model="@_order" OnValidSubmit="HandleSubmit">
|
|
571
|
-
<DataAnnotationsValidator />
|
|
572
|
-
<ValidationSummary />
|
|
573
|
-
<!-- Campos... -->
|
|
574
|
-
</EditForm>
|
|
575
|
-
```
|
|
576
|
-
|
|
577
|
-
**Configuração (Program.cs):**
|
|
578
|
-
```csharp
|
|
579
|
-
builder.Services.AddValidation(); // Habilita validação aninhada
|
|
580
|
-
```
|
|
581
|
-
|
|
582
|
-
---
|
|
583
|
-
|
|
584
|
-
## 📚 Documentação de Referência
|
|
585
|
-
|
|
586
|
-
- [Blazor Documentation](https://learn.microsoft.com/aspnet/core/blazor/)
|
|
587
|
-
- [Entity Framework Core 10](https://learn.microsoft.com/ef/core/)
|
|
588
|
-
- [ASP.NET Core 10](https://learn.microsoft.com/aspnet/core/)
|
|
589
|
-
- [Hangfire](https://docs.hangfire.io/)
|
|
590
|
-
- **[Passkeys/WebAuthn](../../.morph/standards/passkeys-auth.md)**
|
|
591
|
-
- **[Agent Framework](../../.morph/standards/agent-framework-setup.md)**
|
|
592
|
-
|
|
593
|
-
## Checklist de Projeto
|
|
594
|
-
|
|
595
|
-
- [ ] Estrutura de camadas (Domain, Application, Infrastructure, Web)
|
|
596
|
-
- [ ] EF Core configurado com migrations
|
|
597
|
-
- [ ] Blazor Server com componentes reutilizáveis
|
|
598
|
-
- [ ] Services com injeção de dependência
|
|
599
|
-
- [ ] Logging estruturado
|
|
600
|
-
- [ ] Validação com FluentValidation ou DataAnnotations
|
|
601
|
-
- [ ] Hangfire para background jobs
|
|
602
|
-
- [ ] Dockerfile para containerização
|
|
603
|
-
|
|
604
|
-
---
|
|
605
|
-
|
|
606
|
-
*MORPH-SPEC by Polymorphism Tech*
|