@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,105 +1,94 @@
|
|
|
1
|
-
# Feature Recap: {{FEATURE_NAME_TITLE}}
|
|
2
|
-
|
|
3
|
-
## 📋 Summary
|
|
4
|
-
|
|
5
|
-
| Field | Value |
|
|
6
|
-
|-------|-------|
|
|
7
|
-
| **Feature ID** | {feature-id} |
|
|
8
|
-
| **Completed** | {{DATE}} |
|
|
9
|
-
| **Total Tasks** | {X} |
|
|
10
|
-
| **Time Spent** | {X}h |
|
|
11
|
-
| **Agents Used** | {list} |
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## ✅ What Was Delivered
|
|
16
|
-
|
|
17
|
-
### Functionality
|
|
18
|
-
- {Funcionalidade 1 entregue}
|
|
19
|
-
- {Funcionalidade 2 entregue}
|
|
20
|
-
- {Funcionalidade 3 entregue}
|
|
21
|
-
|
|
22
|
-
### Files Created
|
|
23
|
-
```
|
|
24
|
-
{lista de arquivos criados}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### Files Modified
|
|
28
|
-
```
|
|
29
|
-
{lista de arquivos modificados}
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
## 🏗️ Architecture Decisions
|
|
35
|
-
|
|
36
|
-
| Decision | Rationale |
|
|
37
|
-
|----------|-----------|
|
|
38
|
-
| {Decisão 1} | {Motivo} |
|
|
39
|
-
| {Decisão 2} | {Motivo} |
|
|
40
|
-
|
|
41
|
-
See full ADRs in `decisions.md`
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
## 🧪 Test Coverage
|
|
46
|
-
|
|
47
|
-
| Type | Files | Coverage |
|
|
48
|
-
|------|-------|----------|
|
|
49
|
-
| Unit Tests | {X} | {X}% |
|
|
50
|
-
| Integration Tests | {X} | {X}% |
|
|
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
|
-
| Metric | Value |
|
|
96
|
-
|--------|-------|
|
|
97
|
-
| Tasks Completed | {X}/{X} |
|
|
98
|
-
| Checkpoints Passed | {X} |
|
|
99
|
-
| Code Reviews | {X} |
|
|
100
|
-
| Bugs Found | {X} |
|
|
101
|
-
| Bugs Fixed | {X} |
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
*Generated by MORPH Framework on {{DATE}}*
|
|
1
|
+
# Feature Recap: {{FEATURE_NAME_TITLE}}
|
|
2
|
+
|
|
3
|
+
## 📋 Summary
|
|
4
|
+
|
|
5
|
+
| Field | Value |
|
|
6
|
+
|-------|-------|
|
|
7
|
+
| **Feature ID** | {feature-id} |
|
|
8
|
+
| **Completed** | {{DATE}} |
|
|
9
|
+
| **Total Tasks** | {X} |
|
|
10
|
+
| **Time Spent** | {X}h |
|
|
11
|
+
| **Agents Used** | {list} |
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## ✅ What Was Delivered
|
|
16
|
+
|
|
17
|
+
### Functionality
|
|
18
|
+
- {Funcionalidade 1 entregue}
|
|
19
|
+
- {Funcionalidade 2 entregue}
|
|
20
|
+
- {Funcionalidade 3 entregue}
|
|
21
|
+
|
|
22
|
+
### Files Created
|
|
23
|
+
```
|
|
24
|
+
{lista de arquivos criados}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Files Modified
|
|
28
|
+
```
|
|
29
|
+
{lista de arquivos modificados}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 🏗️ Architecture Decisions
|
|
35
|
+
|
|
36
|
+
| Decision | Rationale |
|
|
37
|
+
|----------|-----------|
|
|
38
|
+
| {Decisão 1} | {Motivo} |
|
|
39
|
+
| {Decisão 2} | {Motivo} |
|
|
40
|
+
|
|
41
|
+
See full ADRs in `decisions.md`
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 🧪 Test Coverage
|
|
46
|
+
|
|
47
|
+
| Type | Files | Coverage |
|
|
48
|
+
|------|-------|----------|
|
|
49
|
+
| Unit Tests | {X} | {X}% |
|
|
50
|
+
| Integration Tests | {X} | {X}% |
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 📝 Lessons Learned
|
|
55
|
+
|
|
56
|
+
### What Went Well
|
|
57
|
+
- {Ponto positivo 1}
|
|
58
|
+
- {Ponto positivo 2}
|
|
59
|
+
|
|
60
|
+
### What Could Be Improved
|
|
61
|
+
- {Ponto de melhoria 1}
|
|
62
|
+
- {Ponto de melhoria 2}
|
|
63
|
+
|
|
64
|
+
### Recommendations for Future
|
|
65
|
+
- {Recomendação 1}
|
|
66
|
+
- {Recomendação 2}
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 🔗 Related Resources
|
|
71
|
+
|
|
72
|
+
- **Proposal:** `proposal.md`
|
|
73
|
+
- **Spec:** `spec.md`
|
|
74
|
+
- **Contracts:** `contracts.cs`
|
|
75
|
+
- **Tasks:** `tasks.md`
|
|
76
|
+
- **Decisions:** `decisions.md`
|
|
77
|
+
- **Azure DevOps Epic:** {link}
|
|
78
|
+
- **PR:** {link}
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 📊 Metrics
|
|
83
|
+
|
|
84
|
+
| Metric | Value |
|
|
85
|
+
|--------|-------|
|
|
86
|
+
| Tasks Completed | {X}/{X} |
|
|
87
|
+
| Checkpoints Passed | {X} |
|
|
88
|
+
| Code Reviews | {X} |
|
|
89
|
+
| Bugs Found | {X} |
|
|
90
|
+
| Bugs Fixed | {X} |
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
*Generated by MORPH Framework on {{DATE}}*
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
# Template: Simulacao de Servicos Externos
|
|
2
|
+
|
|
3
|
+
> Template para configurar modo de simulacao em projetos .NET
|
|
4
|
+
|
|
5
|
+
## Configuracao
|
|
6
|
+
|
|
7
|
+
### appsettings.Development.json
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"Simulation": {
|
|
12
|
+
"Enabled": true,
|
|
13
|
+
"ImageDelayMs": 500,
|
|
14
|
+
"EmailDelayMs": 100,
|
|
15
|
+
"PaymentDelayMs": 200,
|
|
16
|
+
"PlaceholderImageUrl": "https://picsum.photos/1024/1024"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### SimulationOptions.cs
|
|
22
|
+
|
|
23
|
+
```csharp
|
|
24
|
+
namespace {Namespace}.Infrastructure.Options;
|
|
25
|
+
|
|
26
|
+
public class SimulationOptions
|
|
27
|
+
{
|
|
28
|
+
public bool Enabled { get; set; }
|
|
29
|
+
public int ImageDelayMs { get; set; } = 500;
|
|
30
|
+
public int EmailDelayMs { get; set; } = 100;
|
|
31
|
+
public int PaymentDelayMs { get; set; } = 200;
|
|
32
|
+
public string PlaceholderImageUrl { get; set; } = "https://picsum.photos/1024/1024";
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## DI Condicional
|
|
39
|
+
|
|
40
|
+
### Program.cs
|
|
41
|
+
|
|
42
|
+
```csharp
|
|
43
|
+
// Configurar options
|
|
44
|
+
builder.Services.Configure<SimulationOptions>(
|
|
45
|
+
builder.Configuration.GetSection("Simulation"));
|
|
46
|
+
|
|
47
|
+
// Registrar clientes baseado em modo
|
|
48
|
+
var simulationEnabled = builder.Configuration.GetValue<bool>("Simulation:Enabled");
|
|
49
|
+
|
|
50
|
+
if (simulationEnabled)
|
|
51
|
+
{
|
|
52
|
+
builder.Services.AddSimulationClients();
|
|
53
|
+
builder.Services.AddSingleton<IStartupFilter, SimulationWarningStartupFilter>();
|
|
54
|
+
}
|
|
55
|
+
else
|
|
56
|
+
{
|
|
57
|
+
builder.Services.AddProductionClients(builder.Configuration);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### ServiceCollectionExtensions.cs
|
|
62
|
+
|
|
63
|
+
```csharp
|
|
64
|
+
namespace {Namespace}.Infrastructure.Extensions;
|
|
65
|
+
|
|
66
|
+
public static class ServiceCollectionExtensions
|
|
67
|
+
{
|
|
68
|
+
public static IServiceCollection AddSimulationClients(this IServiceCollection services)
|
|
69
|
+
{
|
|
70
|
+
// ========================================
|
|
71
|
+
// STATEFUL (mantem dados) → SINGLETON
|
|
72
|
+
// ========================================
|
|
73
|
+
services.AddSingleton<IReplicateClient, FakeReplicateClient>();
|
|
74
|
+
services.AddSingleton<IPaymentClient, FakePaymentClient>();
|
|
75
|
+
|
|
76
|
+
// ========================================
|
|
77
|
+
// STATELESS → SCOPED
|
|
78
|
+
// ========================================
|
|
79
|
+
services.AddScoped<IEmailClient, FakeEmailClient>();
|
|
80
|
+
|
|
81
|
+
// ========================================
|
|
82
|
+
// DEPENDENCIAS TRANSITIVAS - NAO ESQUECER!
|
|
83
|
+
// ========================================
|
|
84
|
+
services.AddHttpClient("FakeImageDownloader");
|
|
85
|
+
services.AddScoped<IImageDownloader>(sp =>
|
|
86
|
+
{
|
|
87
|
+
var httpClientFactory = sp.GetRequiredService<IHttpClientFactory>();
|
|
88
|
+
var httpClient = httpClientFactory.CreateClient("FakeImageDownloader");
|
|
89
|
+
var logger = sp.GetRequiredService<ILogger<FakeImageDownloader>>();
|
|
90
|
+
var options = sp.GetRequiredService<IOptions<SimulationOptions>>();
|
|
91
|
+
return new FakeImageDownloader(httpClient, logger, options);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return services;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public static IServiceCollection AddProductionClients(
|
|
98
|
+
this IServiceCollection services,
|
|
99
|
+
IConfiguration configuration)
|
|
100
|
+
{
|
|
101
|
+
// Clientes reais com HttpClient tipado
|
|
102
|
+
services.AddHttpClient<IReplicateClient, ReplicateClient>();
|
|
103
|
+
services.AddHttpClient<IPaymentClient, AsaasClient>();
|
|
104
|
+
services.AddHttpClient<IEmailClient, ResendClient>();
|
|
105
|
+
services.AddHttpClient<IImageDownloader, HttpImageDownloader>();
|
|
106
|
+
|
|
107
|
+
return services;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Exemplos de Fake Clients
|
|
115
|
+
|
|
116
|
+
### FakeReplicateClient (Stateful → Singleton)
|
|
117
|
+
|
|
118
|
+
```csharp
|
|
119
|
+
public class FakeReplicateClient : IReplicateClient
|
|
120
|
+
{
|
|
121
|
+
// Stateful - REQUER Singleton
|
|
122
|
+
private readonly Dictionary<string, FakePrediction> _predictions = new();
|
|
123
|
+
private readonly ILogger<FakeReplicateClient> _logger;
|
|
124
|
+
private readonly SimulationOptions _options;
|
|
125
|
+
|
|
126
|
+
public FakeReplicateClient(
|
|
127
|
+
ILogger<FakeReplicateClient> logger,
|
|
128
|
+
IOptions<SimulationOptions> options)
|
|
129
|
+
{
|
|
130
|
+
_logger = logger;
|
|
131
|
+
_options = options.Value;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
public Task<string> CreatePredictionAsync(CreatePredictionRequest request, CancellationToken ct)
|
|
135
|
+
{
|
|
136
|
+
var id = Guid.NewGuid().ToString();
|
|
137
|
+
_predictions[id] = new FakePrediction
|
|
138
|
+
{
|
|
139
|
+
Id = id,
|
|
140
|
+
Status = "processing",
|
|
141
|
+
Prompt = request.Input.Prompt,
|
|
142
|
+
CreatedAt = DateTime.UtcNow
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
_logger.LogInformation(
|
|
146
|
+
"[SIMULATED] Created prediction {Id} with prompt: {Prompt}",
|
|
147
|
+
id, request.Input.Prompt?.Substring(0, Math.Min(50, request.Input.Prompt.Length)));
|
|
148
|
+
|
|
149
|
+
return Task.FromResult(id);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public async Task<PredictionResult> WaitForPredictionAsync(string id, CancellationToken ct)
|
|
153
|
+
{
|
|
154
|
+
if (!_predictions.TryGetValue(id, out var prediction))
|
|
155
|
+
throw new InvalidOperationException($"Prediction {id} not found");
|
|
156
|
+
|
|
157
|
+
// Simular delay de processamento
|
|
158
|
+
await Task.Delay(_options.ImageDelayMs, ct);
|
|
159
|
+
|
|
160
|
+
var style = ExtractStyleFromPrompt(prediction.Prompt);
|
|
161
|
+
|
|
162
|
+
_logger.LogInformation(
|
|
163
|
+
"[SIMULATED] Prediction {Id} completed. Style: {Style}",
|
|
164
|
+
id, style);
|
|
165
|
+
|
|
166
|
+
return new PredictionResult
|
|
167
|
+
{
|
|
168
|
+
Id = id,
|
|
169
|
+
Status = "succeeded",
|
|
170
|
+
Output = _options.PlaceholderImageUrl
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
private static string ExtractStyleFromPrompt(string? prompt)
|
|
175
|
+
{
|
|
176
|
+
if (string.IsNullOrEmpty(prompt)) return "Default";
|
|
177
|
+
|
|
178
|
+
var lowerPrompt = prompt.ToLowerInvariant();
|
|
179
|
+
|
|
180
|
+
// IMPORTANTE: Atualizar conforme prompts REAIS do projeto
|
|
181
|
+
if (lowerPrompt.Contains("movie poster")) return "MoviePoster";
|
|
182
|
+
if (lowerPrompt.Contains("impressionist")) return "Impressionist";
|
|
183
|
+
if (lowerPrompt.Contains("baroque")) return "Baroque";
|
|
184
|
+
if (lowerPrompt.Contains("watercolor")) return "Watercolor";
|
|
185
|
+
|
|
186
|
+
return "Default";
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private class FakePrediction
|
|
190
|
+
{
|
|
191
|
+
public string Id { get; init; } = "";
|
|
192
|
+
public string Status { get; set; } = "";
|
|
193
|
+
public string? Prompt { get; init; }
|
|
194
|
+
public DateTime CreatedAt { get; init; }
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### FakeEmailClient (Stateless → Scoped)
|
|
200
|
+
|
|
201
|
+
```csharp
|
|
202
|
+
public class FakeEmailClient : IEmailClient
|
|
203
|
+
{
|
|
204
|
+
private readonly ILogger<FakeEmailClient> _logger;
|
|
205
|
+
private readonly SimulationOptions _options;
|
|
206
|
+
|
|
207
|
+
public FakeEmailClient(
|
|
208
|
+
ILogger<FakeEmailClient> logger,
|
|
209
|
+
IOptions<SimulationOptions> options)
|
|
210
|
+
{
|
|
211
|
+
_logger = logger;
|
|
212
|
+
_options = options.Value;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
public async Task<string?> SendEmailAsync(
|
|
216
|
+
string to,
|
|
217
|
+
string subject,
|
|
218
|
+
string htmlBody,
|
|
219
|
+
IReadOnlyList<EmailAttachment>? attachments = null,
|
|
220
|
+
CancellationToken ct = default)
|
|
221
|
+
{
|
|
222
|
+
await Task.Delay(_options.EmailDelayMs, ct);
|
|
223
|
+
|
|
224
|
+
var attachmentCount = attachments?.Count ?? 0;
|
|
225
|
+
|
|
226
|
+
_logger.LogInformation(
|
|
227
|
+
"[SIMULATED] Email sent to {To}. Subject: {Subject}. Attachments: {Count}",
|
|
228
|
+
to, subject, attachmentCount);
|
|
229
|
+
|
|
230
|
+
return $"fake-message-{Guid.NewGuid():N}";
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### FakeImageDownloader (Stateless → Scoped)
|
|
236
|
+
|
|
237
|
+
```csharp
|
|
238
|
+
public class FakeImageDownloader : IImageDownloader
|
|
239
|
+
{
|
|
240
|
+
private readonly HttpClient _httpClient;
|
|
241
|
+
private readonly ILogger<FakeImageDownloader> _logger;
|
|
242
|
+
private readonly SimulationOptions _options;
|
|
243
|
+
|
|
244
|
+
public FakeImageDownloader(
|
|
245
|
+
HttpClient httpClient,
|
|
246
|
+
ILogger<FakeImageDownloader> logger,
|
|
247
|
+
IOptions<SimulationOptions> options)
|
|
248
|
+
{
|
|
249
|
+
_httpClient = httpClient;
|
|
250
|
+
_logger = logger;
|
|
251
|
+
_options = options.Value;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
public async Task<byte[]> DownloadAsync(string url, CancellationToken ct)
|
|
255
|
+
{
|
|
256
|
+
_logger.LogInformation(
|
|
257
|
+
"[SIMULATED] Downloading image from placeholder instead of {Url}",
|
|
258
|
+
url);
|
|
259
|
+
|
|
260
|
+
// Baixa imagem real do placeholder
|
|
261
|
+
var response = await _httpClient.GetAsync(_options.PlaceholderImageUrl, ct);
|
|
262
|
+
response.EnsureSuccessStatusCode();
|
|
263
|
+
|
|
264
|
+
return await response.Content.ReadAsByteArrayAsync(ct);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Startup Warning
|
|
272
|
+
|
|
273
|
+
```csharp
|
|
274
|
+
public class SimulationWarningStartupFilter : IStartupFilter
|
|
275
|
+
{
|
|
276
|
+
private readonly ILogger<SimulationWarningStartupFilter> _logger;
|
|
277
|
+
|
|
278
|
+
public SimulationWarningStartupFilter(ILogger<SimulationWarningStartupFilter> logger)
|
|
279
|
+
{
|
|
280
|
+
_logger = logger;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
|
|
284
|
+
{
|
|
285
|
+
_logger.LogWarning(
|
|
286
|
+
"⚠️ SIMULATION MODE ENABLED - External services are being simulated!");
|
|
287
|
+
|
|
288
|
+
return next;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## Dependency Trace Template
|
|
296
|
+
|
|
297
|
+
Antes de implementar, preencher este trace:
|
|
298
|
+
|
|
299
|
+
```markdown
|
|
300
|
+
## Dependency Trace para Simulacao
|
|
301
|
+
|
|
302
|
+
### Feature: {Nome da Feature}
|
|
303
|
+
|
|
304
|
+
### Fluxo Principal:
|
|
305
|
+
1. Controller/Page chama {ServiceA}
|
|
306
|
+
2. {ServiceA} chama {IExternalClient}
|
|
307
|
+
3. {IExternalClient} retorna dados
|
|
308
|
+
4. {ServiceA} chama {IDependenciaTransitiva} ← NAO ESQUECER!
|
|
309
|
+
|
|
310
|
+
### Servicos a Mockar:
|
|
311
|
+
| Interface | Fake | Lifetime | Motivo |
|
|
312
|
+
|-----------|------|----------|--------|
|
|
313
|
+
| IReplicateClient | FakeReplicateClient | Singleton | Stateful (Dictionary) |
|
|
314
|
+
| IEmailClient | FakeEmailClient | Scoped | Stateless |
|
|
315
|
+
| IImageDownloader | FakeImageDownloader | Scoped | Stateless |
|
|
316
|
+
|
|
317
|
+
### Checklist:
|
|
318
|
+
- [ ] Todas as interfaces mapeadas
|
|
319
|
+
- [ ] Lifetimes definidos corretamente
|
|
320
|
+
- [ ] Dependencias transitivas identificadas
|
|
321
|
+
- [ ] Assinaturas de metodos verificadas
|
|
322
|
+
- [ ] Prompts/payloads atuais lidos (se IA)
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## Checklist Rapido
|
|
328
|
+
|
|
329
|
+
```markdown
|
|
330
|
+
### Pre-Implementacao:
|
|
331
|
+
- [ ] Listar TODAS as interfaces envolvidas no fluxo
|
|
332
|
+
- [ ] Verificar dependencias transitivas (DI graph)
|
|
333
|
+
- [ ] Ler assinaturas COMPLETAS das interfaces
|
|
334
|
+
- [ ] Verificar lifetimes necessarios (Singleton vs Scoped)
|
|
335
|
+
|
|
336
|
+
### Para mocks de IA:
|
|
337
|
+
- [ ] Ler prompts/payloads ATUAIS do codigo
|
|
338
|
+
- [ ] Verificar formato de response da API real
|
|
339
|
+
- [ ] Testar com dados reais primeiro (1 chamada) antes de mockar
|
|
340
|
+
|
|
341
|
+
### Para mocks de Email:
|
|
342
|
+
- [ ] Verificar se ha attachments/inline images
|
|
343
|
+
- [ ] Testar renderizacao do template separadamente
|
|
344
|
+
|
|
345
|
+
### Pos-Implementacao:
|
|
346
|
+
- [ ] Build passa: `dotnet build`
|
|
347
|
+
- [ ] DI valido: `dotnet run` sem erros
|
|
348
|
+
- [ ] Fluxo funciona em modo simulacao
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
*MORPH-SPEC Simulation Template*
|