@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.
Files changed (251) hide show
  1. package/CLAUDE.md +314 -1673
  2. package/LICENSE +72 -72
  3. package/README.md +515 -516
  4. package/bin/detect-agents.js +225 -225
  5. package/bin/morph-spec.js +358 -173
  6. package/bin/render-template.js +302 -302
  7. package/bin/semantic-detect-agents.js +246 -246
  8. package/bin/task-manager.js +429 -0
  9. package/bin/validate-agents-skills.js +251 -251
  10. package/bin/validate-agents.js +69 -69
  11. package/bin/validate-phase.js +263 -263
  12. package/bin/validate.js +369 -0
  13. package/content/.azure/README.md +293 -293
  14. package/content/.azure/docs/azure-devops-setup.md +454 -454
  15. package/content/.azure/docs/branch-strategy.md +398 -398
  16. package/content/.azure/docs/local-development.md +515 -515
  17. package/content/.azure/pipelines/pipeline-variables.yml +34 -34
  18. package/content/.azure/pipelines/prod-pipeline.yml +319 -319
  19. package/content/.azure/pipelines/staging-pipeline.yml +234 -234
  20. package/content/.azure/pipelines/templates/build-dotnet.yml +75 -75
  21. package/content/.azure/pipelines/templates/deploy-app-service.yml +94 -94
  22. package/content/.azure/pipelines/templates/deploy-container-app.yml +120 -120
  23. package/content/.azure/pipelines/templates/infra-deploy.yml +90 -90
  24. package/content/.claude/commands/morph-apply.md +221 -158
  25. package/content/.claude/commands/morph-archive.md +79 -79
  26. package/content/.claude/commands/morph-infra.md +209 -209
  27. package/content/.claude/commands/morph-preflight.md +227 -0
  28. package/content/.claude/commands/morph-proposal.md +122 -101
  29. package/content/.claude/commands/morph-status.md +86 -86
  30. package/content/.claude/commands/morph-troubleshoot.md +122 -0
  31. package/content/.claude/settings.local.json +15 -15
  32. package/content/.claude/skills/checklists/code-review.md +226 -0
  33. package/content/.claude/skills/checklists/morph-checklist.md +117 -0
  34. package/content/.claude/skills/checklists/simulation-checklist.md +77 -0
  35. package/content/.claude/skills/infra/bicep-architect.md +126 -419
  36. package/content/.claude/skills/infra/container-specialist.md +131 -437
  37. package/content/.claude/skills/infra/devops-engineer.md +119 -405
  38. package/content/.claude/skills/integrations/asaas-financial.md +130 -333
  39. package/content/.claude/skills/integrations/azure-identity.md +142 -309
  40. package/content/.claude/skills/integrations/clerk-auth.md +108 -290
  41. package/content/.claude/skills/integrations/resend-email.md +119 -0
  42. package/content/.claude/skills/specialists/ai-system-architect.md +192 -604
  43. package/content/.claude/skills/specialists/azure-architect.md +142 -142
  44. package/content/.claude/skills/specialists/code-analyzer.md +235 -0
  45. package/content/.claude/skills/specialists/dotnet-senior.md +287 -0
  46. package/content/.claude/skills/specialists/ef-modeler.md +113 -200
  47. package/content/.claude/skills/specialists/hangfire-orchestrator.md +126 -245
  48. package/content/.claude/skills/specialists/ms-agent-expert.md +109 -263
  49. package/content/.claude/skills/specialists/po-pm-advisor.md +197 -197
  50. package/content/.claude/skills/specialists/standards-architect.md +156 -78
  51. package/content/.claude/skills/specialists/testing-specialist.md +126 -0
  52. package/content/.claude/skills/specialists/ui-ux-designer.md +191 -1060
  53. package/content/.claude/skills/stacks/dotnet-blazor.md +210 -588
  54. package/content/.claude/skills/stacks/dotnet-nextjs.md +154 -402
  55. package/content/.claude/skills/workflows/morph-replicate.md +213 -0
  56. package/content/.claude/{commands/morph-clarify.md → skills/workflows/phase-clarify.md} +5 -58
  57. package/content/.claude/{commands/morph-design.md → skills/workflows/phase-design.md} +16 -86
  58. package/content/.claude/{commands/morph-setup.md → skills/workflows/phase-setup.md} +9 -17
  59. package/content/.claude/skills/workflows/phase-tasks.md +164 -0
  60. package/content/.claude/{commands/morph-uiux.md → skills/workflows/phase-uiux.md} +15 -88
  61. package/content/.morph/.morphversion +5 -5
  62. package/content/.morph/archive/.gitkeep +25 -25
  63. package/content/.morph/config/agents.json +378 -242
  64. package/content/.morph/config/config.template.json +89 -108
  65. package/content/.morph/docs/STORY-DRIVEN-DEVELOPMENT.md +392 -392
  66. package/content/.morph/docs/workflows/design-impl.md +37 -0
  67. package/content/.morph/docs/workflows/fast-track.md +29 -0
  68. package/content/.morph/docs/workflows/full-morph.md +76 -0
  69. package/content/.morph/docs/workflows/standard.md +44 -0
  70. package/content/.morph/docs/workflows/ui-refresh.md +39 -0
  71. package/content/.morph/examples/api-nextjs/README.md +241 -241
  72. package/content/.morph/examples/api-nextjs/contracts.ts +307 -307
  73. package/content/.morph/examples/api-nextjs/spec.md +399 -399
  74. package/content/.morph/examples/api-nextjs/tasks.md +168 -168
  75. package/content/.morph/examples/micro-saas/README.md +125 -125
  76. package/content/.morph/examples/micro-saas/contracts.cs +358 -358
  77. package/content/.morph/examples/micro-saas/decisions.md +246 -246
  78. package/content/.morph/examples/micro-saas/spec.md +236 -236
  79. package/content/.morph/examples/micro-saas/tasks.md +150 -150
  80. package/content/.morph/examples/multi-agent/README.md +309 -309
  81. package/content/.morph/examples/multi-agent/contracts.cs +433 -433
  82. package/content/.morph/examples/multi-agent/spec.md +479 -479
  83. package/content/.morph/examples/multi-agent/tasks.md +185 -185
  84. package/content/.morph/examples/scheduled-reports/decisions.md +158 -0
  85. package/content/.morph/examples/scheduled-reports/proposal.md +95 -0
  86. package/content/.morph/examples/scheduled-reports/spec.md +267 -0
  87. package/content/.morph/examples/state-v3.json +188 -0
  88. package/content/.morph/features/.gitkeep +25 -25
  89. package/content/.morph/hooks/README.md +190 -239
  90. package/content/.morph/hooks/pre-commit-agents.sh +24 -24
  91. package/content/.morph/hooks/pre-commit-all.sh +48 -48
  92. package/content/.morph/hooks/pre-commit-specs.sh +49 -49
  93. package/content/.morph/hooks/pre-commit-tests.sh +60 -60
  94. package/content/.morph/project.md +160 -160
  95. package/content/.morph/schemas/agent.schema.json +296 -296
  96. package/content/.morph/schemas/tasks.schema.json +220 -0
  97. package/content/.morph/specs/.gitkeep +20 -20
  98. package/content/.morph/standards/agent-framework-blazor-ui.md +359 -0
  99. package/content/.morph/standards/agent-framework-production.md +410 -0
  100. package/content/.morph/standards/agent-framework-setup.md +413 -453
  101. package/content/.morph/standards/agent-framework-workflows.md +349 -0
  102. package/content/.morph/standards/architecture.md +325 -325
  103. package/content/.morph/standards/azure.md +605 -379
  104. package/content/.morph/standards/coding.md +377 -377
  105. package/content/.morph/standards/dotnet10-migration.md +520 -494
  106. package/content/.morph/standards/fluent-ui-setup.md +590 -590
  107. package/content/.morph/standards/migration-guide.md +514 -514
  108. package/content/.morph/standards/passkeys-auth.md +423 -423
  109. package/content/.morph/standards/vector-search-rag.md +536 -536
  110. package/content/.morph/state.json +17 -17
  111. package/content/.morph/templates/FluentDesignTheme.cs +149 -149
  112. package/content/.morph/templates/MudTheme.cs +281 -281
  113. package/content/.morph/templates/agent.cs +163 -172
  114. package/content/.morph/templates/clarify-questions.md +159 -0
  115. package/content/.morph/templates/component.razor +239 -239
  116. package/content/.morph/templates/contracts/Commands.cs +74 -0
  117. package/content/.morph/templates/contracts/Entities.cs +25 -0
  118. package/content/.morph/templates/contracts/Queries.cs +74 -0
  119. package/content/.morph/templates/contracts/README.md +74 -0
  120. package/content/.morph/templates/contracts.cs +217 -217
  121. package/content/.morph/templates/decisions.md +123 -106
  122. package/content/.morph/templates/design-system.css +226 -226
  123. package/content/.morph/templates/infra/.dockerignore.example +89 -89
  124. package/content/.morph/templates/infra/Dockerfile.example +82 -82
  125. package/content/.morph/templates/infra/README.md +286 -286
  126. package/content/.morph/templates/infra/app-insights.bicep +63 -63
  127. package/content/.morph/templates/infra/app-service.bicep +164 -164
  128. package/content/.morph/templates/infra/container-app-env.bicep +49 -49
  129. package/content/.morph/templates/infra/container-app.bicep +156 -156
  130. package/content/.morph/templates/infra/deploy-checklist.md +426 -0
  131. package/content/.morph/templates/infra/deploy.ps1 +229 -229
  132. package/content/.morph/templates/infra/deploy.sh +208 -208
  133. package/content/.morph/templates/infra/key-vault.bicep +91 -91
  134. package/content/.morph/templates/infra/main.bicep +189 -189
  135. package/content/.morph/templates/infra/parameters.dev.json +29 -29
  136. package/content/.morph/templates/infra/parameters.prod.json +29 -29
  137. package/content/.morph/templates/infra/parameters.staging.json +29 -29
  138. package/content/.morph/templates/infra/sql-database.bicep +103 -103
  139. package/content/.morph/templates/infra/storage.bicep +106 -106
  140. package/content/.morph/templates/integrations/asaas-client.cs +387 -387
  141. package/content/.morph/templates/integrations/asaas-webhook.cs +351 -351
  142. package/content/.morph/templates/integrations/azure-identity-config.cs +288 -288
  143. package/content/.morph/templates/integrations/clerk-config.cs +258 -258
  144. package/content/.morph/templates/job.cs +171 -171
  145. package/content/.morph/templates/migration.cs +83 -83
  146. package/content/.morph/templates/proposal.md +141 -155
  147. package/content/.morph/templates/recap.md +94 -105
  148. package/content/.morph/templates/repository.cs +141 -141
  149. package/content/.morph/templates/saas/subscription.cs +347 -347
  150. package/content/.morph/templates/saas/tenant.cs +338 -338
  151. package/content/.morph/templates/service.cs +139 -139
  152. package/content/.morph/templates/simulation.md +353 -0
  153. package/content/.morph/templates/spec.md +149 -148
  154. package/content/.morph/templates/sprint-status.yaml +68 -68
  155. package/content/.morph/templates/state.template.json +222 -222
  156. package/content/.morph/templates/story.md +143 -143
  157. package/content/.morph/templates/tasks.md +257 -235
  158. package/content/.morph/templates/test.cs +239 -239
  159. package/content/.morph/templates/ui-components.md +362 -276
  160. package/content/.morph/templates/ui-design-system.md +286 -286
  161. package/content/.morph/templates/ui-flows.md +336 -336
  162. package/content/.morph/templates/ui-mockups.md +133 -133
  163. package/content/.morph/test-infra/example.bicep +59 -59
  164. package/content/CLAUDE.md +150 -442
  165. package/content/README.md +79 -79
  166. package/detectors/config-detector.js +223 -223
  167. package/detectors/conversation-analyzer.js +163 -163
  168. package/detectors/index.js +84 -84
  169. package/detectors/standards-generator.js +275 -275
  170. package/detectors/structure-detector.js +245 -250
  171. package/docs/README.md +144 -149
  172. package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +977 -977
  173. package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1048 -1048
  174. package/docs/api/scripts/collapse.js +38 -38
  175. package/docs/api/scripts/commonNav.js +28 -28
  176. package/docs/api/scripts/linenumber.js +25 -25
  177. package/docs/api/scripts/nav.js +12 -12
  178. package/docs/api/scripts/polyfill.js +3 -3
  179. package/docs/api/scripts/prettify/Apache-License-2.0.txt +202 -202
  180. package/docs/api/scripts/prettify/lang-css.js +2 -2
  181. package/docs/api/scripts/prettify/prettify.js +28 -28
  182. package/docs/api/scripts/search.js +98 -98
  183. package/docs/api/styles/jsdoc.css +776 -776
  184. package/docs/api/styles/prettify.css +80 -80
  185. package/docs/examples.md +328 -328
  186. package/docs/getting-started.md +301 -302
  187. package/docs/installation.md +361 -361
  188. package/docs/templates.md +418 -418
  189. package/docs/validation-checklist.md +265 -266
  190. package/package.json +80 -80
  191. package/scripts/postinstall.js +132 -132
  192. package/src/commands/advance-phase.js +183 -0
  193. package/src/commands/analyze-blazor-concurrency.js +193 -0
  194. package/src/commands/create-story.js +351 -351
  195. package/src/commands/detect-agents.js +139 -0
  196. package/src/commands/detect.js +104 -104
  197. package/src/commands/doctor.js +356 -280
  198. package/src/commands/generate.js +149 -149
  199. package/src/commands/init.js +258 -245
  200. package/src/commands/lint-fluent.js +352 -0
  201. package/src/commands/rollback-phase.js +185 -0
  202. package/src/commands/session-summary.js +291 -0
  203. package/src/commands/shard-spec.js +224 -224
  204. package/src/commands/sprint-status.js +250 -250
  205. package/src/commands/state.js +333 -333
  206. package/src/commands/sync.js +167 -167
  207. package/src/commands/task.js +78 -0
  208. package/src/commands/troubleshoot.js +222 -0
  209. package/src/commands/update.js +192 -159
  210. package/src/commands/validate-blazor-state.js +210 -0
  211. package/src/commands/validate-blazor.js +156 -0
  212. package/src/commands/validate-css.js +84 -0
  213. package/src/commands/validate-phase.js +221 -0
  214. package/src/lib/blazor-concurrency-analyzer.js +288 -0
  215. package/src/lib/blazor-state-validator.js +291 -0
  216. package/src/lib/blazor-validator.js +374 -0
  217. package/src/lib/complexity-analyzer.js +441 -292
  218. package/src/lib/continuous-validator.js +421 -0
  219. package/src/lib/css-validator.js +352 -0
  220. package/src/lib/decision-constraint-loader.js +109 -0
  221. package/src/lib/design-system-generator.js +298 -298
  222. package/src/lib/learning-system.js +520 -0
  223. package/src/lib/mockup-generator.js +366 -0
  224. package/src/lib/recap-generator.js +205 -0
  225. package/src/lib/state-manager.js +397 -340
  226. package/src/lib/troubleshoot-grep.js +194 -0
  227. package/src/lib/troubleshoot-index.js +144 -0
  228. package/src/lib/ui-detector.js +350 -0
  229. package/src/lib/validation-runner.js +231 -0
  230. package/src/lib/validators/architecture-validator.js +387 -0
  231. package/src/lib/validators/contract-compliance-validator.js +273 -0
  232. package/src/lib/validators/package-validator.js +360 -0
  233. package/src/lib/validators/ui-contrast-validator.js +422 -0
  234. package/src/utils/file-copier.js +179 -139
  235. package/src/utils/logger.js +32 -32
  236. package/src/utils/version-checker.js +175 -175
  237. package/content/.claude/commands/morph-costs.md +0 -206
  238. package/content/.claude/commands/morph-tasks.md +0 -319
  239. package/content/.claude/skills/specialists/cost-guardian.md +0 -110
  240. package/content/.claude/skills/stacks/shopify.md +0 -445
  241. package/content/.morph/config/azure-pricing.json +0 -70
  242. package/content/.morph/config/azure-pricing.schema.json +0 -50
  243. package/content/.morph/hooks/pre-commit-costs.sh +0 -91
  244. package/docs/api/cost-calculator.js.html +0 -513
  245. package/docs/api/design-system-generator.js.html +0 -382
  246. package/docs/api/global.html +0 -5263
  247. package/docs/api/index.html +0 -96
  248. package/docs/api/state-manager.js.html +0 -423
  249. package/src/commands/cost.js +0 -181
  250. package/src/commands/update-pricing.js +0 -206
  251. package/src/lib/cost-calculator.js +0 -429
@@ -1,377 +1,377 @@
1
- # Padrões de Código - MORPH Framework
2
-
3
- ## 📝 Nomenclatura
4
-
5
- ### Classes e Interfaces
6
- ```csharp
7
- // Interfaces: sempre com prefixo I
8
- public interface IReportService { }
9
- public interface IReportRepository { }
10
-
11
- // Classes: PascalCase, sufixo indica tipo
12
- public class ReportService : IReportService { }
13
- public class ReportRepository : IReportRepository { }
14
- public class ReportController : ControllerBase { }
15
- public class ReportGeneratorJob { } // Hangfire job
16
- public class ReportAnalyzerAgent { } // AI Agent
17
- ```
18
-
19
- ### Métodos
20
- ```csharp
21
- // Async sempre com sufixo Async
22
- public async Task<Report> GetByIdAsync(int id) { }
23
- public async Task CreateAsync(Report report) { }
24
-
25
- // Métodos síncronos sem sufixo
26
- public Report GetById(int id) { }
27
- public void Validate(Report report) { }
28
- ```
29
-
30
- ### Variáveis e Parâmetros
31
- ```csharp
32
- // camelCase para variáveis locais e parâmetros
33
- public async Task ProcessAsync(string reportId, CancellationToken cancellationToken)
34
- {
35
- var report = await _repository.GetByIdAsync(reportId);
36
- var analysisResult = await _analyzer.AnalyzeAsync(report);
37
- }
38
-
39
- // _camelCase para campos privados
40
- private readonly IReportRepository _repository;
41
- private readonly ILogger<ReportService> _logger;
42
- ```
43
-
44
- ---
45
-
46
- ## 📁 Estrutura de Projeto
47
-
48
- ```
49
- src/
50
- ├── MyProject.Web/ # Blazor Server
51
- │ ├── Components/
52
- │ │ ├── Pages/ # Páginas (rotas)
53
- │ │ ├── Shared/ # Componentes compartilhados
54
- │ │ └── Layout/ # Layouts
55
- │ └── Program.cs
56
-
57
- ├── MyProject.Application/ # Casos de uso
58
- │ ├── Features/
59
- │ │ └── Reports/
60
- │ │ ├── Commands/
61
- │ │ ├── Queries/
62
- │ │ └── Services/
63
- │ └── Common/
64
-
65
- ├── MyProject.Domain/ # Entidades e regras
66
- │ ├── Entities/
67
- │ ├── ValueObjects/
68
- │ └── Enums/
69
-
70
- ├── MyProject.Infrastructure/ # Implementações
71
- │ ├── Data/
72
- │ │ ├── Configurations/
73
- │ │ ├── Migrations/
74
- │ │ └── AppDbContext.cs
75
- │ └── Services/
76
-
77
- └── MyProject.Agents/ # MS Agent Framework
78
- └── ReportAnalyzer/
79
- ```
80
-
81
- ---
82
-
83
- ## 💉 Dependency Injection
84
-
85
- ```csharp
86
- // Usar primary constructor (C# 12+)
87
- public class ReportService(
88
- IReportRepository repository,
89
- ILogger<ReportService> logger) : IReportService
90
- {
91
- public async Task<Report> GetByIdAsync(int id)
92
- {
93
- logger.LogInformation("Getting report {ReportId}", id);
94
- return await repository.GetByIdAsync(id);
95
- }
96
- }
97
- ```
98
-
99
- ---
100
-
101
- ## 🗄️ Entity Framework Core
102
-
103
- ### Entidades
104
- ```csharp
105
- public class ReportSchedule
106
- {
107
- public int Id { get; private set; }
108
- public string Name { get; private set; } = string.Empty;
109
- public ReportType ReportType { get; private set; }
110
- public string CronExpression { get; private set; } = string.Empty;
111
- public List<string> Recipients { get; private set; } = [];
112
- public bool IsActive { get; private set; }
113
- public DateTime CreatedAt { get; private set; }
114
-
115
- // Factory method para criação
116
- public static ReportSchedule Create(string name, ReportType reportType,
117
- string cronExpression, List<string> recipients)
118
- {
119
- return new ReportSchedule
120
- {
121
- Name = name,
122
- ReportType = reportType,
123
- CronExpression = cronExpression,
124
- Recipients = recipients,
125
- IsActive = true,
126
- CreatedAt = DateTime.UtcNow
127
- };
128
- }
129
-
130
- // Métodos de domínio
131
- public void Activate() => IsActive = true;
132
- public void Deactivate() => IsActive = false;
133
- }
134
- ```
135
-
136
- ### Configuração Fluent API
137
- ```csharp
138
- public class ReportScheduleConfiguration : IEntityTypeConfiguration<ReportSchedule>
139
- {
140
- public void Configure(EntityTypeBuilder<ReportSchedule> builder)
141
- {
142
- builder.ToTable("ReportSchedules");
143
- builder.HasKey(x => x.Id);
144
-
145
- builder.Property(x => x.Name)
146
- .IsRequired()
147
- .HasMaxLength(200);
148
-
149
- // JSON column para lista
150
- builder.Property(x => x.Recipients)
151
- .HasConversion(
152
- v => JsonSerializer.Serialize(v, (JsonSerializerOptions?)null),
153
- v => JsonSerializer.Deserialize<List<string>>(v, (JsonSerializerOptions?)null) ?? [])
154
- .HasColumnType("nvarchar(max)");
155
- }
156
- }
157
- ```
158
-
159
- ---
160
-
161
- ## 🔥 Componentes Blazor
162
-
163
- ```razor
164
- @page "/reports/schedules"
165
- @attribute [Authorize(Policy = "CanManageReports")]
166
- @inject IReportScheduleService ReportService
167
- @inject ILogger<ReportScheduleList> Logger
168
-
169
- <PageTitle>Report Schedules</PageTitle>
170
-
171
- @if (_isLoading)
172
- {
173
- <LoadingSpinner />
174
- }
175
- else if (_schedules is null || !_schedules.Any())
176
- {
177
- <EmptyState Message="No schedules configured" />
178
- }
179
- else
180
- {
181
- <div class="schedule-list">
182
- @foreach (var schedule in _schedules)
183
- {
184
- <ScheduleCard Schedule="schedule" OnToggle="HandleToggleAsync" />
185
- }
186
- </div>
187
- }
188
-
189
- @code {
190
- private List<ReportScheduleDto>? _schedules;
191
- private bool _isLoading = true;
192
-
193
- protected override async Task OnInitializedAsync()
194
- {
195
- try
196
- {
197
- _schedules = await ReportService.GetAllAsync();
198
- }
199
- catch (Exception ex)
200
- {
201
- Logger.LogError(ex, "Failed to load schedules");
202
- }
203
- finally
204
- {
205
- _isLoading = false;
206
- }
207
- }
208
- }
209
- ```
210
-
211
- ### Padrões Obrigatórios
212
- - ✅ Loading state em toda página
213
- - ✅ Empty state quando lista vazia
214
- - ✅ Error handling com try/catch
215
- - ✅ `@inject` para DI (não construtor)
216
- - ✅ `@attribute [Authorize]` quando necessário
217
-
218
- ---
219
-
220
- ## 🤖 AI Agents - Padrão Obrigatório (.NET 10)
221
-
222
- > **CRÍTICO:** Use **exclusivamente** Microsoft Agent Framework.
223
- > Semantic Kernel foi descontinuado no MORPH-SPEC.
224
-
225
- ### Pattern Obrigatório
226
-
227
- ```csharp
228
- using Microsoft.Agents.AI;
229
- using Microsoft.Extensions.AI;
230
-
231
- public class ReportAnalyzerAgent(
232
- IChatClient chatClient,
233
- ILogger<ReportAnalyzerAgent> logger) : IReportAnalyzerAgent
234
- {
235
- public async Task<AnalysisResult> AnalyzeAsync(
236
- ReportData reportData,
237
- CancellationToken cancellationToken = default)
238
- {
239
- var agent = chatClient.CreateAgent(
240
- instructions: """
241
- Você é um especialista em análise de relatórios.
242
- Analise os dados fornecidos e retorne em JSON:
243
- {
244
- "summary": "resumo",
245
- "insights": ["top 3 insights"],
246
- "recommendations": ["recomendações"]
247
- }
248
- """,
249
- name: "ReportAnalyzer"
250
- );
251
-
252
- var prompt = $"Analise este relatório:\n{reportData.ToJson()}";
253
-
254
- try
255
- {
256
- var response = await agent.RunAsync(prompt, cancellationToken: cancellationToken);
257
- return ParseResponse(response.Content);
258
- }
259
- catch (Exception ex)
260
- {
261
- logger.LogError(ex, "Analysis failed for report {ReportId}", reportData.Id);
262
- throw new ReportAnalysisException("Failed to analyze", ex);
263
- }
264
- }
265
- }
266
- ```
267
-
268
- ### Configuração (Program.cs)
269
-
270
- ```csharp
271
- // Registrar ChatClient
272
- builder.Services.AddSingleton<IChatClient>(sp =>
273
- {
274
- var config = sp.GetRequiredService<IConfiguration>();
275
- return new ChatClient(
276
- model: "gpt-4o-mini",
277
- credential: new ApiKeyCredential(config["AzureOpenAI:ApiKey"]!),
278
- endpoint: new Uri(config["AzureOpenAI:Endpoint"]!)
279
- );
280
- });
281
-
282
- // Registrar agent
283
- builder.Services.AddScoped<IReportAnalyzerAgent, ReportAnalyzerAgent>();
284
- ```
285
-
286
- **Referência:** [Agent Framework Setup](./agent-framework-setup.md)
287
-
288
- ---
289
-
290
- ## ⏰ Hangfire Jobs
291
-
292
- ```csharp
293
- public class ReportGeneratorJob(
294
- IReportScheduleService scheduleService,
295
- IReportAnalyzerAgent analyzer,
296
- ILogger<ReportGeneratorJob> logger) : IReportGeneratorJob
297
- {
298
- [AutomaticRetry(Attempts = 3, DelaysInSeconds = new[] { 60, 300, 900 })]
299
- [Queue("reports")]
300
- public async Task ExecuteAsync(int scheduleId, CancellationToken cancellationToken)
301
- {
302
- logger.LogInformation("Starting report generation for {ScheduleId}", scheduleId);
303
-
304
- var schedule = await scheduleService.GetByIdAsync(scheduleId);
305
- if (schedule is null || !schedule.IsActive)
306
- {
307
- logger.LogWarning("Schedule {ScheduleId} not found or inactive", scheduleId);
308
- return;
309
- }
310
-
311
- // ... implementação
312
- }
313
- }
314
- ```
315
-
316
- ---
317
-
318
- ## 🧪 Testes
319
-
320
- ### Nomenclatura
321
- ```csharp
322
- // Classe: {ClasseTestada}Tests
323
- public class ReportServiceTests
324
- {
325
- // Método: {Método}_{Cenário}_{ResultadoEsperado}
326
- [Fact]
327
- public async Task GetByIdAsync_WithValidId_ReturnsReport() { }
328
-
329
- [Fact]
330
- public async Task GetByIdAsync_WithInvalidId_ThrowsNotFoundException() { }
331
- }
332
- ```
333
-
334
- ### Estrutura AAA
335
- ```csharp
336
- [Fact]
337
- public async Task CreateAsync_WithValidData_CreatesSchedule()
338
- {
339
- // Arrange
340
- var request = new CreateReportScheduleRequest("Daily Sales", ReportType.Sales);
341
-
342
- // Act
343
- var result = await _service.CreateAsync(request);
344
-
345
- // Assert
346
- Assert.NotNull(result);
347
- Assert.Equal(request.Name, result.Name);
348
- }
349
- ```
350
-
351
- ---
352
-
353
- ## 🚫 Anti-Patterns a Evitar
354
-
355
- ```csharp
356
- // ❌ Service Locator
357
- var service = serviceProvider.GetService<IReportService>();
358
-
359
- // ✅ Constructor Injection
360
- public class MyClass(IReportService reportService) { }
361
-
362
- // ❌ Async void
363
- public async void ProcessReport() { }
364
-
365
- // ✅ Async Task
366
- public async Task ProcessReportAsync() { }
367
-
368
- // ❌ Catching generic Exception sem log
369
- catch (Exception) { }
370
-
371
- // ✅ Log and handle
372
- catch (Exception ex)
373
- {
374
- _logger.LogError(ex, "Operation failed");
375
- throw;
376
- }
377
- ```
1
+ # Padrões de Código - MORPH Framework
2
+
3
+ ## 📝 Nomenclatura
4
+
5
+ ### Classes e Interfaces
6
+ ```csharp
7
+ // Interfaces: sempre com prefixo I
8
+ public interface IReportService { }
9
+ public interface IReportRepository { }
10
+
11
+ // Classes: PascalCase, sufixo indica tipo
12
+ public class ReportService : IReportService { }
13
+ public class ReportRepository : IReportRepository { }
14
+ public class ReportController : ControllerBase { }
15
+ public class ReportGeneratorJob { } // Hangfire job
16
+ public class ReportAnalyzerAgent { } // AI Agent
17
+ ```
18
+
19
+ ### Métodos
20
+ ```csharp
21
+ // Async sempre com sufixo Async
22
+ public async Task<Report> GetByIdAsync(int id) { }
23
+ public async Task CreateAsync(Report report) { }
24
+
25
+ // Métodos síncronos sem sufixo
26
+ public Report GetById(int id) { }
27
+ public void Validate(Report report) { }
28
+ ```
29
+
30
+ ### Variáveis e Parâmetros
31
+ ```csharp
32
+ // camelCase para variáveis locais e parâmetros
33
+ public async Task ProcessAsync(string reportId, CancellationToken cancellationToken)
34
+ {
35
+ var report = await _repository.GetByIdAsync(reportId);
36
+ var analysisResult = await _analyzer.AnalyzeAsync(report);
37
+ }
38
+
39
+ // _camelCase para campos privados
40
+ private readonly IReportRepository _repository;
41
+ private readonly ILogger<ReportService> _logger;
42
+ ```
43
+
44
+ ---
45
+
46
+ ## 📁 Estrutura de Projeto
47
+
48
+ ```
49
+ src/
50
+ ├── MyProject.Web/ # Blazor Server
51
+ │ ├── Components/
52
+ │ │ ├── Pages/ # Páginas (rotas)
53
+ │ │ ├── Shared/ # Componentes compartilhados
54
+ │ │ └── Layout/ # Layouts
55
+ │ └── Program.cs
56
+
57
+ ├── MyProject.Application/ # Casos de uso
58
+ │ ├── Features/
59
+ │ │ └── Reports/
60
+ │ │ ├── Commands/
61
+ │ │ ├── Queries/
62
+ │ │ └── Services/
63
+ │ └── Common/
64
+
65
+ ├── MyProject.Domain/ # Entidades e regras
66
+ │ ├── Entities/
67
+ │ ├── ValueObjects/
68
+ │ └── Enums/
69
+
70
+ ├── MyProject.Infrastructure/ # Implementações
71
+ │ ├── Data/
72
+ │ │ ├── Configurations/
73
+ │ │ ├── Migrations/
74
+ │ │ └── AppDbContext.cs
75
+ │ └── Services/
76
+
77
+ └── MyProject.Agents/ # MS Agent Framework
78
+ └── ReportAnalyzer/
79
+ ```
80
+
81
+ ---
82
+
83
+ ## 💉 Dependency Injection
84
+
85
+ ```csharp
86
+ // Usar primary constructor (C# 12+)
87
+ public class ReportService(
88
+ IReportRepository repository,
89
+ ILogger<ReportService> logger) : IReportService
90
+ {
91
+ public async Task<Report> GetByIdAsync(int id)
92
+ {
93
+ logger.LogInformation("Getting report {ReportId}", id);
94
+ return await repository.GetByIdAsync(id);
95
+ }
96
+ }
97
+ ```
98
+
99
+ ---
100
+
101
+ ## 🗄️ Entity Framework Core
102
+
103
+ ### Entidades
104
+ ```csharp
105
+ public class ReportSchedule
106
+ {
107
+ public int Id { get; private set; }
108
+ public string Name { get; private set; } = string.Empty;
109
+ public ReportType ReportType { get; private set; }
110
+ public string CronExpression { get; private set; } = string.Empty;
111
+ public List<string> Recipients { get; private set; } = [];
112
+ public bool IsActive { get; private set; }
113
+ public DateTime CreatedAt { get; private set; }
114
+
115
+ // Factory method para criação
116
+ public static ReportSchedule Create(string name, ReportType reportType,
117
+ string cronExpression, List<string> recipients)
118
+ {
119
+ return new ReportSchedule
120
+ {
121
+ Name = name,
122
+ ReportType = reportType,
123
+ CronExpression = cronExpression,
124
+ Recipients = recipients,
125
+ IsActive = true,
126
+ CreatedAt = DateTime.UtcNow
127
+ };
128
+ }
129
+
130
+ // Métodos de domínio
131
+ public void Activate() => IsActive = true;
132
+ public void Deactivate() => IsActive = false;
133
+ }
134
+ ```
135
+
136
+ ### Configuração Fluent API
137
+ ```csharp
138
+ public class ReportScheduleConfiguration : IEntityTypeConfiguration<ReportSchedule>
139
+ {
140
+ public void Configure(EntityTypeBuilder<ReportSchedule> builder)
141
+ {
142
+ builder.ToTable("ReportSchedules");
143
+ builder.HasKey(x => x.Id);
144
+
145
+ builder.Property(x => x.Name)
146
+ .IsRequired()
147
+ .HasMaxLength(200);
148
+
149
+ // JSON column para lista
150
+ builder.Property(x => x.Recipients)
151
+ .HasConversion(
152
+ v => JsonSerializer.Serialize(v, (JsonSerializerOptions?)null),
153
+ v => JsonSerializer.Deserialize<List<string>>(v, (JsonSerializerOptions?)null) ?? [])
154
+ .HasColumnType("nvarchar(max)");
155
+ }
156
+ }
157
+ ```
158
+
159
+ ---
160
+
161
+ ## 🔥 Componentes Blazor
162
+
163
+ ```razor
164
+ @page "/reports/schedules"
165
+ @attribute [Authorize(Policy = "CanManageReports")]
166
+ @inject IReportScheduleService ReportService
167
+ @inject ILogger<ReportScheduleList> Logger
168
+
169
+ <PageTitle>Report Schedules</PageTitle>
170
+
171
+ @if (_isLoading)
172
+ {
173
+ <LoadingSpinner />
174
+ }
175
+ else if (_schedules is null || !_schedules.Any())
176
+ {
177
+ <EmptyState Message="No schedules configured" />
178
+ }
179
+ else
180
+ {
181
+ <div class="schedule-list">
182
+ @foreach (var schedule in _schedules)
183
+ {
184
+ <ScheduleCard Schedule="schedule" OnToggle="HandleToggleAsync" />
185
+ }
186
+ </div>
187
+ }
188
+
189
+ @code {
190
+ private List<ReportScheduleDto>? _schedules;
191
+ private bool _isLoading = true;
192
+
193
+ protected override async Task OnInitializedAsync()
194
+ {
195
+ try
196
+ {
197
+ _schedules = await ReportService.GetAllAsync();
198
+ }
199
+ catch (Exception ex)
200
+ {
201
+ Logger.LogError(ex, "Failed to load schedules");
202
+ }
203
+ finally
204
+ {
205
+ _isLoading = false;
206
+ }
207
+ }
208
+ }
209
+ ```
210
+
211
+ ### Padrões Obrigatórios
212
+ - ✅ Loading state em toda página
213
+ - ✅ Empty state quando lista vazia
214
+ - ✅ Error handling com try/catch
215
+ - ✅ `@inject` para DI (não construtor)
216
+ - ✅ `@attribute [Authorize]` quando necessário
217
+
218
+ ---
219
+
220
+ ## 🤖 AI Agents - Padrão Obrigatório (.NET 10)
221
+
222
+ > **CRÍTICO:** Use **exclusivamente** Microsoft Agent Framework.
223
+ > Semantic Kernel foi descontinuado no MORPH-SPEC.
224
+
225
+ ### Pattern Obrigatório
226
+
227
+ ```csharp
228
+ using Microsoft.Agents.AI;
229
+ using Microsoft.Extensions.AI;
230
+
231
+ public class ReportAnalyzerAgent(
232
+ IChatClient chatClient,
233
+ ILogger<ReportAnalyzerAgent> logger) : IReportAnalyzerAgent
234
+ {
235
+ public async Task<AnalysisResult> AnalyzeAsync(
236
+ ReportData reportData,
237
+ CancellationToken cancellationToken = default)
238
+ {
239
+ var agent = chatClient.CreateAgent(
240
+ instructions: """
241
+ Você é um especialista em análise de relatórios.
242
+ Analise os dados fornecidos e retorne em JSON:
243
+ {
244
+ "summary": "resumo",
245
+ "insights": ["top 3 insights"],
246
+ "recommendations": ["recomendações"]
247
+ }
248
+ """,
249
+ name: "ReportAnalyzer"
250
+ );
251
+
252
+ var prompt = $"Analise este relatório:\n{reportData.ToJson()}";
253
+
254
+ try
255
+ {
256
+ var response = await agent.RunAsync(prompt, cancellationToken: cancellationToken);
257
+ return ParseResponse(response.Content);
258
+ }
259
+ catch (Exception ex)
260
+ {
261
+ logger.LogError(ex, "Analysis failed for report {ReportId}", reportData.Id);
262
+ throw new ReportAnalysisException("Failed to analyze", ex);
263
+ }
264
+ }
265
+ }
266
+ ```
267
+
268
+ ### Configuração (Program.cs)
269
+
270
+ ```csharp
271
+ // Registrar ChatClient
272
+ builder.Services.AddSingleton<IChatClient>(sp =>
273
+ {
274
+ var config = sp.GetRequiredService<IConfiguration>();
275
+ return new ChatClient(
276
+ model: "gpt-4o-mini",
277
+ credential: new ApiKeyCredential(config["AzureOpenAI:ApiKey"]!),
278
+ endpoint: new Uri(config["AzureOpenAI:Endpoint"]!)
279
+ );
280
+ });
281
+
282
+ // Registrar agent
283
+ builder.Services.AddScoped<IReportAnalyzerAgent, ReportAnalyzerAgent>();
284
+ ```
285
+
286
+ **Referência:** [Agent Framework Setup](./agent-framework-setup.md)
287
+
288
+ ---
289
+
290
+ ## ⏰ Hangfire Jobs
291
+
292
+ ```csharp
293
+ public class ReportGeneratorJob(
294
+ IReportScheduleService scheduleService,
295
+ IReportAnalyzerAgent analyzer,
296
+ ILogger<ReportGeneratorJob> logger) : IReportGeneratorJob
297
+ {
298
+ [AutomaticRetry(Attempts = 3, DelaysInSeconds = new[] { 60, 300, 900 })]
299
+ [Queue("reports")]
300
+ public async Task ExecuteAsync(int scheduleId, CancellationToken cancellationToken)
301
+ {
302
+ logger.LogInformation("Starting report generation for {ScheduleId}", scheduleId);
303
+
304
+ var schedule = await scheduleService.GetByIdAsync(scheduleId);
305
+ if (schedule is null || !schedule.IsActive)
306
+ {
307
+ logger.LogWarning("Schedule {ScheduleId} not found or inactive", scheduleId);
308
+ return;
309
+ }
310
+
311
+ // ... implementação
312
+ }
313
+ }
314
+ ```
315
+
316
+ ---
317
+
318
+ ## 🧪 Testes
319
+
320
+ ### Nomenclatura
321
+ ```csharp
322
+ // Classe: {ClasseTestada}Tests
323
+ public class ReportServiceTests
324
+ {
325
+ // Método: {Método}_{Cenário}_{ResultadoEsperado}
326
+ [Fact]
327
+ public async Task GetByIdAsync_WithValidId_ReturnsReport() { }
328
+
329
+ [Fact]
330
+ public async Task GetByIdAsync_WithInvalidId_ThrowsNotFoundException() { }
331
+ }
332
+ ```
333
+
334
+ ### Estrutura AAA
335
+ ```csharp
336
+ [Fact]
337
+ public async Task CreateAsync_WithValidData_CreatesSchedule()
338
+ {
339
+ // Arrange
340
+ var request = new CreateReportScheduleRequest("Daily Sales", ReportType.Sales);
341
+
342
+ // Act
343
+ var result = await _service.CreateAsync(request);
344
+
345
+ // Assert
346
+ Assert.NotNull(result);
347
+ Assert.Equal(request.Name, result.Name);
348
+ }
349
+ ```
350
+
351
+ ---
352
+
353
+ ## 🚫 Anti-Patterns a Evitar
354
+
355
+ ```csharp
356
+ // ❌ Service Locator
357
+ var service = serviceProvider.GetService<IReportService>();
358
+
359
+ // ✅ Constructor Injection
360
+ public class MyClass(IReportService reportService) { }
361
+
362
+ // ❌ Async void
363
+ public async void ProcessReport() { }
364
+
365
+ // ✅ Async Task
366
+ public async Task ProcessReportAsync() { }
367
+
368
+ // ❌ Catching generic Exception sem log
369
+ catch (Exception) { }
370
+
371
+ // ✅ Log and handle
372
+ catch (Exception ex)
373
+ {
374
+ _logger.LogError(ex, "Operation failed");
375
+ throw;
376
+ }
377
+ ```