@polymorphism-tech/morph-spec 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +314 -1673
- package/LICENSE +72 -72
- package/README.md +515 -516
- package/bin/detect-agents.js +225 -225
- package/bin/morph-spec.js +358 -173
- package/bin/render-template.js +302 -302
- package/bin/semantic-detect-agents.js +246 -246
- package/bin/task-manager.js +429 -0
- package/bin/validate-agents-skills.js +251 -251
- package/bin/validate-agents.js +69 -69
- package/bin/validate-phase.js +263 -263
- package/bin/validate.js +369 -0
- package/content/.azure/README.md +293 -293
- package/content/.azure/docs/azure-devops-setup.md +454 -454
- package/content/.azure/docs/branch-strategy.md +398 -398
- package/content/.azure/docs/local-development.md +515 -515
- package/content/.azure/pipelines/pipeline-variables.yml +34 -34
- package/content/.azure/pipelines/prod-pipeline.yml +319 -319
- package/content/.azure/pipelines/staging-pipeline.yml +234 -234
- package/content/.azure/pipelines/templates/build-dotnet.yml +75 -75
- package/content/.azure/pipelines/templates/deploy-app-service.yml +94 -94
- package/content/.azure/pipelines/templates/deploy-container-app.yml +120 -120
- package/content/.azure/pipelines/templates/infra-deploy.yml +90 -90
- package/content/.claude/commands/morph-apply.md +221 -158
- package/content/.claude/commands/morph-archive.md +79 -79
- package/content/.claude/commands/morph-infra.md +209 -209
- package/content/.claude/commands/morph-preflight.md +227 -0
- package/content/.claude/commands/morph-proposal.md +122 -101
- package/content/.claude/commands/morph-status.md +86 -86
- package/content/.claude/commands/morph-troubleshoot.md +122 -0
- package/content/.claude/settings.local.json +15 -15
- package/content/.claude/skills/checklists/code-review.md +226 -0
- package/content/.claude/skills/checklists/morph-checklist.md +117 -0
- package/content/.claude/skills/checklists/simulation-checklist.md +77 -0
- package/content/.claude/skills/infra/bicep-architect.md +126 -419
- package/content/.claude/skills/infra/container-specialist.md +131 -437
- package/content/.claude/skills/infra/devops-engineer.md +119 -405
- package/content/.claude/skills/integrations/asaas-financial.md +130 -333
- package/content/.claude/skills/integrations/azure-identity.md +142 -309
- package/content/.claude/skills/integrations/clerk-auth.md +108 -290
- package/content/.claude/skills/integrations/resend-email.md +119 -0
- package/content/.claude/skills/specialists/ai-system-architect.md +192 -604
- package/content/.claude/skills/specialists/azure-architect.md +142 -142
- package/content/.claude/skills/specialists/code-analyzer.md +235 -0
- package/content/.claude/skills/specialists/dotnet-senior.md +287 -0
- package/content/.claude/skills/specialists/ef-modeler.md +113 -200
- package/content/.claude/skills/specialists/hangfire-orchestrator.md +126 -245
- package/content/.claude/skills/specialists/ms-agent-expert.md +109 -263
- package/content/.claude/skills/specialists/po-pm-advisor.md +197 -197
- package/content/.claude/skills/specialists/standards-architect.md +156 -78
- package/content/.claude/skills/specialists/testing-specialist.md +126 -0
- package/content/.claude/skills/specialists/ui-ux-designer.md +191 -1060
- package/content/.claude/skills/stacks/dotnet-blazor.md +210 -588
- package/content/.claude/skills/stacks/dotnet-nextjs.md +154 -402
- package/content/.claude/skills/workflows/morph-replicate.md +213 -0
- package/content/.claude/{commands/morph-clarify.md → skills/workflows/phase-clarify.md} +5 -58
- package/content/.claude/{commands/morph-design.md → skills/workflows/phase-design.md} +16 -86
- package/content/.claude/{commands/morph-setup.md → skills/workflows/phase-setup.md} +9 -17
- package/content/.claude/skills/workflows/phase-tasks.md +164 -0
- package/content/.claude/{commands/morph-uiux.md → skills/workflows/phase-uiux.md} +15 -88
- package/content/.morph/.morphversion +5 -5
- package/content/.morph/archive/.gitkeep +25 -25
- package/content/.morph/config/agents.json +378 -242
- package/content/.morph/config/config.template.json +89 -108
- package/content/.morph/docs/STORY-DRIVEN-DEVELOPMENT.md +392 -392
- package/content/.morph/docs/workflows/design-impl.md +37 -0
- package/content/.morph/docs/workflows/fast-track.md +29 -0
- package/content/.morph/docs/workflows/full-morph.md +76 -0
- package/content/.morph/docs/workflows/standard.md +44 -0
- package/content/.morph/docs/workflows/ui-refresh.md +39 -0
- package/content/.morph/examples/api-nextjs/README.md +241 -241
- package/content/.morph/examples/api-nextjs/contracts.ts +307 -307
- package/content/.morph/examples/api-nextjs/spec.md +399 -399
- package/content/.morph/examples/api-nextjs/tasks.md +168 -168
- package/content/.morph/examples/micro-saas/README.md +125 -125
- package/content/.morph/examples/micro-saas/contracts.cs +358 -358
- package/content/.morph/examples/micro-saas/decisions.md +246 -246
- package/content/.morph/examples/micro-saas/spec.md +236 -236
- package/content/.morph/examples/micro-saas/tasks.md +150 -150
- package/content/.morph/examples/multi-agent/README.md +309 -309
- package/content/.morph/examples/multi-agent/contracts.cs +433 -433
- package/content/.morph/examples/multi-agent/spec.md +479 -479
- package/content/.morph/examples/multi-agent/tasks.md +185 -185
- package/content/.morph/examples/scheduled-reports/decisions.md +158 -0
- package/content/.morph/examples/scheduled-reports/proposal.md +95 -0
- package/content/.morph/examples/scheduled-reports/spec.md +267 -0
- package/content/.morph/examples/state-v3.json +188 -0
- package/content/.morph/features/.gitkeep +25 -25
- package/content/.morph/hooks/README.md +190 -239
- package/content/.morph/hooks/pre-commit-agents.sh +24 -24
- package/content/.morph/hooks/pre-commit-all.sh +48 -48
- package/content/.morph/hooks/pre-commit-specs.sh +49 -49
- package/content/.morph/hooks/pre-commit-tests.sh +60 -60
- package/content/.morph/project.md +160 -160
- package/content/.morph/schemas/agent.schema.json +296 -296
- package/content/.morph/schemas/tasks.schema.json +220 -0
- package/content/.morph/specs/.gitkeep +20 -20
- package/content/.morph/standards/agent-framework-blazor-ui.md +359 -0
- package/content/.morph/standards/agent-framework-production.md +410 -0
- package/content/.morph/standards/agent-framework-setup.md +413 -453
- package/content/.morph/standards/agent-framework-workflows.md +349 -0
- package/content/.morph/standards/architecture.md +325 -325
- package/content/.morph/standards/azure.md +605 -379
- package/content/.morph/standards/coding.md +377 -377
- package/content/.morph/standards/dotnet10-migration.md +520 -494
- package/content/.morph/standards/fluent-ui-setup.md +590 -590
- package/content/.morph/standards/migration-guide.md +514 -514
- package/content/.morph/standards/passkeys-auth.md +423 -423
- package/content/.morph/standards/vector-search-rag.md +536 -536
- package/content/.morph/state.json +17 -17
- package/content/.morph/templates/FluentDesignTheme.cs +149 -149
- package/content/.morph/templates/MudTheme.cs +281 -281
- package/content/.morph/templates/agent.cs +163 -172
- package/content/.morph/templates/clarify-questions.md +159 -0
- package/content/.morph/templates/component.razor +239 -239
- package/content/.morph/templates/contracts/Commands.cs +74 -0
- package/content/.morph/templates/contracts/Entities.cs +25 -0
- package/content/.morph/templates/contracts/Queries.cs +74 -0
- package/content/.morph/templates/contracts/README.md +74 -0
- package/content/.morph/templates/contracts.cs +217 -217
- package/content/.morph/templates/decisions.md +123 -106
- package/content/.morph/templates/design-system.css +226 -226
- package/content/.morph/templates/infra/.dockerignore.example +89 -89
- package/content/.morph/templates/infra/Dockerfile.example +82 -82
- package/content/.morph/templates/infra/README.md +286 -286
- package/content/.morph/templates/infra/app-insights.bicep +63 -63
- package/content/.morph/templates/infra/app-service.bicep +164 -164
- package/content/.morph/templates/infra/container-app-env.bicep +49 -49
- package/content/.morph/templates/infra/container-app.bicep +156 -156
- package/content/.morph/templates/infra/deploy-checklist.md +426 -0
- package/content/.morph/templates/infra/deploy.ps1 +229 -229
- package/content/.morph/templates/infra/deploy.sh +208 -208
- package/content/.morph/templates/infra/key-vault.bicep +91 -91
- package/content/.morph/templates/infra/main.bicep +189 -189
- package/content/.morph/templates/infra/parameters.dev.json +29 -29
- package/content/.morph/templates/infra/parameters.prod.json +29 -29
- package/content/.morph/templates/infra/parameters.staging.json +29 -29
- package/content/.morph/templates/infra/sql-database.bicep +103 -103
- package/content/.morph/templates/infra/storage.bicep +106 -106
- package/content/.morph/templates/integrations/asaas-client.cs +387 -387
- package/content/.morph/templates/integrations/asaas-webhook.cs +351 -351
- package/content/.morph/templates/integrations/azure-identity-config.cs +288 -288
- package/content/.morph/templates/integrations/clerk-config.cs +258 -258
- package/content/.morph/templates/job.cs +171 -171
- package/content/.morph/templates/migration.cs +83 -83
- package/content/.morph/templates/proposal.md +141 -155
- package/content/.morph/templates/recap.md +94 -105
- package/content/.morph/templates/repository.cs +141 -141
- package/content/.morph/templates/saas/subscription.cs +347 -347
- package/content/.morph/templates/saas/tenant.cs +338 -338
- package/content/.morph/templates/service.cs +139 -139
- package/content/.morph/templates/simulation.md +353 -0
- package/content/.morph/templates/spec.md +149 -148
- package/content/.morph/templates/sprint-status.yaml +68 -68
- package/content/.morph/templates/state.template.json +222 -222
- package/content/.morph/templates/story.md +143 -143
- package/content/.morph/templates/tasks.md +257 -235
- package/content/.morph/templates/test.cs +239 -239
- package/content/.morph/templates/ui-components.md +362 -276
- package/content/.morph/templates/ui-design-system.md +286 -286
- package/content/.morph/templates/ui-flows.md +336 -336
- package/content/.morph/templates/ui-mockups.md +133 -133
- package/content/.morph/test-infra/example.bicep +59 -59
- package/content/CLAUDE.md +150 -442
- package/content/README.md +79 -79
- package/detectors/config-detector.js +223 -223
- package/detectors/conversation-analyzer.js +163 -163
- package/detectors/index.js +84 -84
- package/detectors/standards-generator.js +275 -275
- package/detectors/structure-detector.js +245 -250
- package/docs/README.md +144 -149
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +977 -977
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1048 -1048
- package/docs/api/scripts/collapse.js +38 -38
- package/docs/api/scripts/commonNav.js +28 -28
- package/docs/api/scripts/linenumber.js +25 -25
- package/docs/api/scripts/nav.js +12 -12
- package/docs/api/scripts/polyfill.js +3 -3
- package/docs/api/scripts/prettify/Apache-License-2.0.txt +202 -202
- package/docs/api/scripts/prettify/lang-css.js +2 -2
- package/docs/api/scripts/prettify/prettify.js +28 -28
- package/docs/api/scripts/search.js +98 -98
- package/docs/api/styles/jsdoc.css +776 -776
- package/docs/api/styles/prettify.css +80 -80
- package/docs/examples.md +328 -328
- package/docs/getting-started.md +301 -302
- package/docs/installation.md +361 -361
- package/docs/templates.md +418 -418
- package/docs/validation-checklist.md +265 -266
- package/package.json +80 -80
- package/scripts/postinstall.js +132 -132
- package/src/commands/advance-phase.js +183 -0
- package/src/commands/analyze-blazor-concurrency.js +193 -0
- package/src/commands/create-story.js +351 -351
- package/src/commands/detect-agents.js +139 -0
- package/src/commands/detect.js +104 -104
- package/src/commands/doctor.js +356 -280
- package/src/commands/generate.js +149 -149
- package/src/commands/init.js +258 -245
- package/src/commands/lint-fluent.js +352 -0
- package/src/commands/rollback-phase.js +185 -0
- package/src/commands/session-summary.js +291 -0
- package/src/commands/shard-spec.js +224 -224
- package/src/commands/sprint-status.js +250 -250
- package/src/commands/state.js +333 -333
- package/src/commands/sync.js +167 -167
- package/src/commands/task.js +78 -0
- package/src/commands/troubleshoot.js +222 -0
- package/src/commands/update.js +192 -159
- package/src/commands/validate-blazor-state.js +210 -0
- package/src/commands/validate-blazor.js +156 -0
- package/src/commands/validate-css.js +84 -0
- package/src/commands/validate-phase.js +221 -0
- package/src/lib/blazor-concurrency-analyzer.js +288 -0
- package/src/lib/blazor-state-validator.js +291 -0
- package/src/lib/blazor-validator.js +374 -0
- package/src/lib/complexity-analyzer.js +441 -292
- package/src/lib/continuous-validator.js +421 -0
- package/src/lib/css-validator.js +352 -0
- package/src/lib/decision-constraint-loader.js +109 -0
- package/src/lib/design-system-generator.js +298 -298
- package/src/lib/learning-system.js +520 -0
- package/src/lib/mockup-generator.js +366 -0
- package/src/lib/recap-generator.js +205 -0
- package/src/lib/state-manager.js +397 -340
- package/src/lib/troubleshoot-grep.js +194 -0
- package/src/lib/troubleshoot-index.js +144 -0
- package/src/lib/ui-detector.js +350 -0
- package/src/lib/validation-runner.js +231 -0
- package/src/lib/validators/architecture-validator.js +387 -0
- package/src/lib/validators/contract-compliance-validator.js +273 -0
- package/src/lib/validators/package-validator.js +360 -0
- package/src/lib/validators/ui-contrast-validator.js +422 -0
- package/src/utils/file-copier.js +179 -139
- package/src/utils/logger.js +32 -32
- package/src/utils/version-checker.js +175 -175
- package/content/.claude/commands/morph-costs.md +0 -206
- package/content/.claude/commands/morph-tasks.md +0 -319
- package/content/.claude/skills/specialists/cost-guardian.md +0 -110
- package/content/.claude/skills/stacks/shopify.md +0 -445
- package/content/.morph/config/azure-pricing.json +0 -70
- package/content/.morph/config/azure-pricing.schema.json +0 -50
- package/content/.morph/hooks/pre-commit-costs.sh +0 -91
- package/docs/api/cost-calculator.js.html +0 -513
- package/docs/api/design-system-generator.js.html +0 -382
- package/docs/api/global.html +0 -5263
- package/docs/api/index.html +0 -96
- package/docs/api/state-manager.js.html +0 -423
- package/src/commands/cost.js +0 -181
- package/src/commands/update-pricing.js +0 -206
- package/src/lib/cost-calculator.js +0 -429
|
@@ -1,379 +1,605 @@
|
|
|
1
|
-
# Padrões Azure - MORPH Framework
|
|
2
|
-
|
|
3
|
-
## 💰 Filosofia de Custos
|
|
4
|
-
|
|
5
|
-
> **Free tier primeiro. Aprovação explícita para upgrade.**
|
|
6
|
-
|
|
7
|
-
| Nível | Limite | Requer |
|
|
8
|
-
|-------|--------|--------|
|
|
9
|
-
| Sem aprovação | Free tier apenas | Nada |
|
|
10
|
-
| Com aprovação | Até $10/mês | Confirmação |
|
|
11
|
-
| Acima de $10 | Justificativa detalhada | ADR |
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## 🌐 Hosting: App Service vs Container Apps
|
|
16
|
-
|
|
17
|
-
### Matriz de Decisão
|
|
18
|
-
|
|
19
|
-
| Critério | App Service (Free F1) | Container Apps (Consumption) |
|
|
20
|
-
|----------|----------------------|------------------------------|
|
|
21
|
-
| **Custo** | ✅ $0/mês | ⚠️ ~$5/mês |
|
|
22
|
-
| **RAM** | 1GB | Configurável (0.5Gi min) |
|
|
23
|
-
| **Storage** | 1GB | Ephemeral |
|
|
24
|
-
| **CPU** | ⚠️ 60 min/dia | ✅ Ilimitado |
|
|
25
|
-
| **Disponibilidade** | ⚠️ Sleep após 20min | ✅ Scale-to-zero sem sleep |
|
|
26
|
-
| **SSL Customizado** | ❌ Não (apenas *.azurewebsites.net) | ✅ Sim, gratuito |
|
|
27
|
-
| **Scale Out** | ❌ Não | ✅ Auto-scaling |
|
|
28
|
-
| **Blazor Server** | ✅ Suporte nativo | ✅ Via Docker |
|
|
29
|
-
| **Deploy** | ✅ Direto (ZIP, Git) | ⚠️ Requer container |
|
|
30
|
-
|
|
31
|
-
### Quando Usar App Service Free
|
|
32
|
-
|
|
33
|
-
**✅ Cenários Ideais:**
|
|
34
|
-
- Protótipos e MVPs de baixo tráfego
|
|
35
|
-
- Aplicações de uso interno (horário comercial)
|
|
36
|
-
- Demos e POCs
|
|
37
|
-
- Apps que toleram cold start (20 min sleep)
|
|
38
|
-
- Orçamento zero absoluto
|
|
39
|
-
|
|
40
|
-
**❌ Não Usar Quando:**
|
|
41
|
-
- Necessita estar sempre disponível (24/7)
|
|
42
|
-
- Tráfego imprevisível ou spikes
|
|
43
|
-
- Mais de 60 min de CPU/dia
|
|
44
|
-
- Precisa de SSL customizado
|
|
45
|
-
- Requer auto-scaling
|
|
46
|
-
|
|
47
|
-
### Quando Usar Container Apps
|
|
48
|
-
|
|
49
|
-
**✅ Cenários Ideais:**
|
|
50
|
-
- Produção com disponibilidade 24/7
|
|
51
|
-
- Auto-scaling baseado em demanda
|
|
52
|
-
- SSL customizado necessário
|
|
53
|
-
- Arquitetura microserviços
|
|
54
|
-
- Background jobs com Hangfire (minReplicas: 1)
|
|
55
|
-
- Apps que precisam estar sempre "quentes"
|
|
56
|
-
|
|
57
|
-
**❌ Não Usar Quando:**
|
|
58
|
-
- Orçamento zero obrigatório
|
|
59
|
-
- Tráfego extremamente baixo (< 100 req/dia)
|
|
60
|
-
- MVP simples sem requisitos de SLA
|
|
61
|
-
|
|
62
|
-
### Estratégia Híbrida
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
Dev/Staging: App Service Free F1
|
|
66
|
-
Production: Container Apps Consumption
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
**Benefícios:**
|
|
70
|
-
- 💰 Economia em ambientes não críticos
|
|
71
|
-
- 🚀 Performance garantida em produção
|
|
72
|
-
- 🔄 Fácil migração (mesma stack .NET)
|
|
73
|
-
|
|
74
|
-
---
|
|
75
|
-
|
|
76
|
-
## 📋 Stack Padrão Aprovado
|
|
77
|
-
|
|
78
|
-
| Recurso | Tier | Custo | Quando Usar |
|
|
79
|
-
|---------|------|-------|-------------|
|
|
80
|
-
| **App Service** | Free F1 | $0 | MVP, protótipos, dev/staging |
|
|
81
|
-
| **Container Apps** | Consumption | ~$0-5/mês | Produção, auto-scaling |
|
|
82
|
-
| **Azure SQL** | Free 32GB | $0 | Database |
|
|
83
|
-
| **ACR** | Basic | ~$5/mês | Container registry (apenas com CA) |
|
|
84
|
-
| **App Insights** | Free 5GB | $0 | Logs e métricas |
|
|
85
|
-
| **Azure OpenAI** | gpt-4o-mini | ~$2-10/mês | Análises AI |
|
|
86
|
-
|
|
87
|
-
**Custo total típico:**
|
|
88
|
-
- **App Service Stack:** $0-2/mês (sem ACR)
|
|
89
|
-
- **Container Apps Stack:** $7-20/mês (com ACR)
|
|
90
|
-
|
|
91
|
-
### ⚠️ Requer Aprovação
|
|
92
|
-
|
|
93
|
-
| Recurso | Custo | Alternativa Free |
|
|
94
|
-
|---------|-------|------------------|
|
|
95
|
-
| Azure Functions | ~$0-5/mês | Hangfire |
|
|
96
|
-
| Service Bus | ~$10/mês | Queue em SQL |
|
|
97
|
-
| Cosmos DB | ~$25/mês | Azure SQL JSON |
|
|
98
|
-
| Redis Cache | ~$15/mês | In-memory |
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
## 🌐 App Service Free Tier
|
|
103
|
-
|
|
104
|
-
### Configuração Obrigatória
|
|
105
|
-
```bicep
|
|
106
|
-
resource appService 'Microsoft.Web/sites@2022-03-01' = {
|
|
107
|
-
name: 'app-${projectName}-${environment}'
|
|
108
|
-
location: location
|
|
109
|
-
properties: {
|
|
110
|
-
serverFarmId: appServicePlan.id
|
|
111
|
-
httpsOnly: true
|
|
112
|
-
siteConfig: {
|
|
113
|
-
netFrameworkVersion: 'v8.0'
|
|
114
|
-
alwaysOn: false # ⚠️ OBRIGATÓRIO no Free tier
|
|
115
|
-
minTlsVersion: '1.2'
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = {
|
|
121
|
-
name: 'plan-${projectName}-${environment}'
|
|
122
|
-
location: location
|
|
123
|
-
sku: {
|
|
124
|
-
name: 'F1' # Free tier
|
|
125
|
-
tier: 'Free'
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### Limitações Importantes
|
|
131
|
-
- ⚠️ **CPU**: Apenas 60 minutos/dia (não contínuos)
|
|
132
|
-
- ⚠️ **Sleep**: App dorme após 20 minutos de inatividade
|
|
133
|
-
- ⚠️ **SSL**: Apenas `*.azurewebsites.net` (sem domínio customizado)
|
|
134
|
-
- ⚠️ **Escala**: Sem scale-out (apenas 1 instância)
|
|
135
|
-
- ✅ **Memória**: 1GB RAM
|
|
136
|
-
- ✅ **Storage**: 1GB disco
|
|
137
|
-
|
|
138
|
-
### Deploy
|
|
139
|
-
```bash
|
|
140
|
-
# Via Azure CLI
|
|
141
|
-
az webapp up --name app-myproject-dev --runtime "DOTNET:8.0"
|
|
142
|
-
|
|
143
|
-
# Via GitHub Actions
|
|
144
|
-
- task: AzureWebApp@1
|
|
145
|
-
inputs:
|
|
146
|
-
azureSubscription: 'Azure-Connection'
|
|
147
|
-
appName: 'app-myproject-dev'
|
|
148
|
-
package: '$(Build.ArtifactStagingDirectory)/**/*.zip'
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### Quando Migrar para Container Apps
|
|
152
|
-
Se você observar:
|
|
153
|
-
- 🔴 CPU quota esgotada frequentemente
|
|
154
|
-
- 🔴 Cold starts afetando UX
|
|
155
|
-
- 🔴 Necessidade de SSL customizado
|
|
156
|
-
- 🔴 Tráfego crescendo (>1000 req/dia)
|
|
157
|
-
|
|
158
|
-
**→ Considere migrar para Container Apps Consumption**
|
|
159
|
-
|
|
160
|
-
---
|
|
161
|
-
|
|
162
|
-
## 🐳 Container Apps
|
|
163
|
-
|
|
164
|
-
### Configuração Obrigatória
|
|
165
|
-
```yaml
|
|
166
|
-
properties:
|
|
167
|
-
template:
|
|
168
|
-
scale:
|
|
169
|
-
minReplicas: 0 # ⚠️ OBRIGATÓRIO: scale-to-zero
|
|
170
|
-
maxReplicas: 2
|
|
171
|
-
containers:
|
|
172
|
-
- name: app
|
|
173
|
-
resources:
|
|
174
|
-
cpu: 0.25 # Mínimo
|
|
175
|
-
memory: 0.5Gi # Mínimo
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
### Scale-to-Zero
|
|
179
|
-
- ✅ **OBRIGATÓRIO** para dev/staging
|
|
180
|
-
- ⚠️ Em prod com Hangfire: `minReplicas: 1`
|
|
181
|
-
- 💰 Economia: ~80% vs always-on
|
|
182
|
-
|
|
183
|
-
---
|
|
184
|
-
|
|
185
|
-
## 🗄️ Azure SQL Free Tier
|
|
186
|
-
|
|
187
|
-
```
|
|
188
|
-
- 32 GB storage
|
|
189
|
-
- 100,000 vCore seconds/month
|
|
190
|
-
- Serverless compute
|
|
191
|
-
- Auto-pause after 1 hour idle
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
### Práticas
|
|
195
|
-
- ✅ Usar Managed Identity
|
|
196
|
-
- ✅ TDE habilitado (default)
|
|
197
|
-
- ❌ Não criar índices em excesso
|
|
198
|
-
|
|
199
|
-
---
|
|
200
|
-
|
|
201
|
-
## 🤖 Azure OpenAI
|
|
202
|
-
|
|
203
|
-
### Modelo Padrão: gpt-4o-mini
|
|
204
|
-
|
|
205
|
-
| Modelo | Custo Input | Custo Output | Usar |
|
|
206
|
-
|--------|-------------|--------------|------|
|
|
207
|
-
| **gpt-4o-mini** | $0.15/1M | $0.60/1M | ✅ PADRÃO |
|
|
208
|
-
| gpt-4o | $2.50/1M | $10/1M | Com aprovação |
|
|
209
|
-
| gpt-4 | $30/1M | $60/1M | ❌ NUNCA |
|
|
210
|
-
|
|
211
|
-
### Otimização
|
|
212
|
-
```csharp
|
|
213
|
-
var settings = new OpenAIPromptExecutionSettings
|
|
214
|
-
{
|
|
215
|
-
MaxTokens = 500, // Limitar resposta
|
|
216
|
-
Temperature = 0.3 // Mais determinístico
|
|
217
|
-
};
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
---
|
|
221
|
-
|
|
222
|
-
## 🔐 Segurança
|
|
223
|
-
|
|
224
|
-
### Managed Identity (Preferido)
|
|
225
|
-
```csharp
|
|
226
|
-
// Para Azure SQL
|
|
227
|
-
"Authentication=Active Directory Managed Identity;"
|
|
228
|
-
|
|
229
|
-
// Para Azure OpenAI
|
|
230
|
-
var credential = new DefaultAzureCredential();
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
### Key Vault
|
|
234
|
-
Usar apenas para:
|
|
235
|
-
- Secrets de serviços externos
|
|
236
|
-
- API keys de terceiros
|
|
237
|
-
|
|
238
|
-
---
|
|
239
|
-
|
|
240
|
-
## 📛 Naming Conventions
|
|
241
|
-
|
|
242
|
-
```
|
|
243
|
-
{tipo}-{projeto}-{ambiente}
|
|
244
|
-
|
|
245
|
-
Exemplos:
|
|
246
|
-
- rg-myproject-dev # Resource Group
|
|
247
|
-
- app-myproject-dev # App Service
|
|
248
|
-
- plan-myproject-dev # App Service Plan
|
|
249
|
-
- ca-myproject-dev # Container App
|
|
250
|
-
- sql-myproject-dev # SQL Server
|
|
251
|
-
- sqldb-myproject-dev # SQL Database
|
|
252
|
-
- acr-myproject # Container Registry
|
|
253
|
-
- appi-myproject-dev # App Insights
|
|
254
|
-
- kv-myproject-dev # Key Vault
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
| Ambiente | Sufixo | Características |
|
|
258
|
-
|----------|--------|-----------------|
|
|
259
|
-
| Development | -dev | Scale-to-zero, free tier |
|
|
260
|
-
| Staging | -stg | Scale-to-zero, free tier |
|
|
261
|
-
| Production | -prod | Min 1 replica |
|
|
262
|
-
|
|
263
|
-
---
|
|
264
|
-
|
|
265
|
-
## 🚀 Azure DevOps Pipelines
|
|
266
|
-
|
|
267
|
-
### Estratégia de Ambientes
|
|
268
|
-
|
|
269
|
-
**2 ambientes:**
|
|
270
|
-
- **Staging**: Desenvolvimento + QA (branch: `staging`)
|
|
271
|
-
- Developers rodam projeto LOCAL
|
|
272
|
-
- Acessam recursos REMOTOS staging
|
|
273
|
-
- Deploy automático via pipeline
|
|
274
|
-
|
|
275
|
-
- **Produção**: Ambiente crítico (branch: `main`/`master`)
|
|
276
|
-
- Deploy via pipeline com aprovação manual
|
|
277
|
-
- Always-on, monitoramento 24/7
|
|
278
|
-
|
|
279
|
-
### Estrutura de Pipelines
|
|
280
|
-
|
|
281
|
-
```
|
|
282
|
-
.azure/pipelines/
|
|
283
|
-
├── staging-pipeline.yml # Branch: staging
|
|
284
|
-
├── prod-pipeline.yml # Branch: main/master
|
|
285
|
-
├── pipeline-variables.yml # Variáveis compartilhadas
|
|
286
|
-
└── templates/
|
|
287
|
-
├── build-dotnet.yml
|
|
288
|
-
├── deploy-container-app.yml
|
|
289
|
-
└── infra-deploy.yml
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
### Pipeline Staging
|
|
293
|
-
|
|
294
|
-
```yaml
|
|
295
|
-
# staging-pipeline.yml
|
|
296
|
-
trigger:
|
|
297
|
-
branches:
|
|
298
|
-
include: [staging]
|
|
299
|
-
|
|
300
|
-
variables:
|
|
301
|
-
- template: pipeline-variables.yml
|
|
302
|
-
- name: environment
|
|
303
|
-
value: 'staging'
|
|
304
|
-
- name: hostingType
|
|
305
|
-
value: 'containerapp'
|
|
306
|
-
|
|
307
|
-
stages:
|
|
308
|
-
- stage: Build
|
|
309
|
-
- stage: DeployInfra
|
|
310
|
-
- stage: BuildContainer
|
|
311
|
-
- stage: DeployApp
|
|
312
|
-
jobs:
|
|
313
|
-
- deployment: DeployAppJob
|
|
314
|
-
environment: 'staging' # No approval
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
### Pipeline Production
|
|
318
|
-
|
|
319
|
-
```yaml
|
|
320
|
-
# prod-pipeline.yml
|
|
321
|
-
trigger:
|
|
322
|
-
branches:
|
|
323
|
-
include: [main, master]
|
|
324
|
-
|
|
325
|
-
variables:
|
|
326
|
-
- template: pipeline-variables.yml
|
|
327
|
-
- name: environment
|
|
328
|
-
value: 'prod'
|
|
329
|
-
- name: hostingType
|
|
330
|
-
value: 'containerapp'
|
|
331
|
-
|
|
332
|
-
stages:
|
|
333
|
-
- stage: Build
|
|
334
|
-
- stage: SecurityScan
|
|
335
|
-
- stage: DeployInfra
|
|
336
|
-
- stage: BuildContainer
|
|
337
|
-
- stage: DeployApp
|
|
338
|
-
jobs:
|
|
339
|
-
- deployment: DeployAppJob
|
|
340
|
-
environment: 'production' # Approval required
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
### Workload Identity (Sem Secrets)
|
|
344
|
-
|
|
345
|
-
Ao invés de Service Principals com secrets, use Workload Identity Federation:
|
|
346
|
-
|
|
347
|
-
```bash
|
|
348
|
-
# Criar App Registration com Federated Credential
|
|
349
|
-
az ad app create --display-name "myapp-prod-pipeline"
|
|
350
|
-
|
|
351
|
-
# Configurar federated credential
|
|
352
|
-
az ad app federated-credential create \
|
|
353
|
-
--id <APP_ID> \
|
|
354
|
-
--parameters @federated-credential.json
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
**Vantagens:**
|
|
358
|
-
- ✅ Sem secrets para gerenciar
|
|
359
|
-
- ✅ Rotação automática de tokens
|
|
360
|
-
- ✅ Mais seguro
|
|
361
|
-
- ✅ Auditoria melhorada
|
|
362
|
-
|
|
363
|
-
**Documentação completa:** `.azure/docs/azure-devops-setup.md`
|
|
364
|
-
|
|
365
|
-
---
|
|
366
|
-
|
|
367
|
-
## ✅ Checklist de Deploy
|
|
368
|
-
|
|
369
|
-
### Antes
|
|
370
|
-
- [ ] Testes passando
|
|
371
|
-
- [ ] Migrations aplicadas
|
|
372
|
-
- [ ] Secrets no Key Vault
|
|
373
|
-
- [ ] Managed Identity configurada
|
|
374
|
-
|
|
375
|
-
### Após
|
|
376
|
-
- [ ] Health check OK
|
|
377
|
-
- [ ] Logs no App Insights
|
|
378
|
-
- [ ] Funcionalidade testada
|
|
379
|
-
- [ ] Custos verificados
|
|
1
|
+
# Padrões Azure - MORPH Framework
|
|
2
|
+
|
|
3
|
+
## 💰 Filosofia de Custos
|
|
4
|
+
|
|
5
|
+
> **Free tier primeiro. Aprovação explícita para upgrade.**
|
|
6
|
+
|
|
7
|
+
| Nível | Limite | Requer |
|
|
8
|
+
|-------|--------|--------|
|
|
9
|
+
| Sem aprovação | Free tier apenas | Nada |
|
|
10
|
+
| Com aprovação | Até $10/mês | Confirmação |
|
|
11
|
+
| Acima de $10 | Justificativa detalhada | ADR |
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 🌐 Hosting: App Service vs Container Apps
|
|
16
|
+
|
|
17
|
+
### Matriz de Decisão
|
|
18
|
+
|
|
19
|
+
| Critério | App Service (Free F1) | Container Apps (Consumption) |
|
|
20
|
+
|----------|----------------------|------------------------------|
|
|
21
|
+
| **Custo** | ✅ $0/mês | ⚠️ ~$5/mês |
|
|
22
|
+
| **RAM** | 1GB | Configurável (0.5Gi min) |
|
|
23
|
+
| **Storage** | 1GB | Ephemeral |
|
|
24
|
+
| **CPU** | ⚠️ 60 min/dia | ✅ Ilimitado |
|
|
25
|
+
| **Disponibilidade** | ⚠️ Sleep após 20min | ✅ Scale-to-zero sem sleep |
|
|
26
|
+
| **SSL Customizado** | ❌ Não (apenas *.azurewebsites.net) | ✅ Sim, gratuito |
|
|
27
|
+
| **Scale Out** | ❌ Não | ✅ Auto-scaling |
|
|
28
|
+
| **Blazor Server** | ✅ Suporte nativo | ✅ Via Docker |
|
|
29
|
+
| **Deploy** | ✅ Direto (ZIP, Git) | ⚠️ Requer container |
|
|
30
|
+
|
|
31
|
+
### Quando Usar App Service Free
|
|
32
|
+
|
|
33
|
+
**✅ Cenários Ideais:**
|
|
34
|
+
- Protótipos e MVPs de baixo tráfego
|
|
35
|
+
- Aplicações de uso interno (horário comercial)
|
|
36
|
+
- Demos e POCs
|
|
37
|
+
- Apps que toleram cold start (20 min sleep)
|
|
38
|
+
- Orçamento zero absoluto
|
|
39
|
+
|
|
40
|
+
**❌ Não Usar Quando:**
|
|
41
|
+
- Necessita estar sempre disponível (24/7)
|
|
42
|
+
- Tráfego imprevisível ou spikes
|
|
43
|
+
- Mais de 60 min de CPU/dia
|
|
44
|
+
- Precisa de SSL customizado
|
|
45
|
+
- Requer auto-scaling
|
|
46
|
+
|
|
47
|
+
### Quando Usar Container Apps
|
|
48
|
+
|
|
49
|
+
**✅ Cenários Ideais:**
|
|
50
|
+
- Produção com disponibilidade 24/7
|
|
51
|
+
- Auto-scaling baseado em demanda
|
|
52
|
+
- SSL customizado necessário
|
|
53
|
+
- Arquitetura microserviços
|
|
54
|
+
- Background jobs com Hangfire (minReplicas: 1)
|
|
55
|
+
- Apps que precisam estar sempre "quentes"
|
|
56
|
+
|
|
57
|
+
**❌ Não Usar Quando:**
|
|
58
|
+
- Orçamento zero obrigatório
|
|
59
|
+
- Tráfego extremamente baixo (< 100 req/dia)
|
|
60
|
+
- MVP simples sem requisitos de SLA
|
|
61
|
+
|
|
62
|
+
### Estratégia Híbrida
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
Dev/Staging: App Service Free F1
|
|
66
|
+
Production: Container Apps Consumption
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Benefícios:**
|
|
70
|
+
- 💰 Economia em ambientes não críticos
|
|
71
|
+
- 🚀 Performance garantida em produção
|
|
72
|
+
- 🔄 Fácil migração (mesma stack .NET)
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 📋 Stack Padrão Aprovado
|
|
77
|
+
|
|
78
|
+
| Recurso | Tier | Custo | Quando Usar |
|
|
79
|
+
|---------|------|-------|-------------|
|
|
80
|
+
| **App Service** | Free F1 | $0 | MVP, protótipos, dev/staging |
|
|
81
|
+
| **Container Apps** | Consumption | ~$0-5/mês | Produção, auto-scaling |
|
|
82
|
+
| **Azure SQL** | Free 32GB | $0 | Database |
|
|
83
|
+
| **ACR** | Basic | ~$5/mês | Container registry (apenas com CA) |
|
|
84
|
+
| **App Insights** | Free 5GB | $0 | Logs e métricas |
|
|
85
|
+
| **Azure OpenAI** | gpt-4o-mini | ~$2-10/mês | Análises AI |
|
|
86
|
+
|
|
87
|
+
**Custo total típico:**
|
|
88
|
+
- **App Service Stack:** $0-2/mês (sem ACR)
|
|
89
|
+
- **Container Apps Stack:** $7-20/mês (com ACR)
|
|
90
|
+
|
|
91
|
+
### ⚠️ Requer Aprovação
|
|
92
|
+
|
|
93
|
+
| Recurso | Custo | Alternativa Free |
|
|
94
|
+
|---------|-------|------------------|
|
|
95
|
+
| Azure Functions | ~$0-5/mês | Hangfire |
|
|
96
|
+
| Service Bus | ~$10/mês | Queue em SQL |
|
|
97
|
+
| Cosmos DB | ~$25/mês | Azure SQL JSON |
|
|
98
|
+
| Redis Cache | ~$15/mês | In-memory |
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 🌐 App Service Free Tier
|
|
103
|
+
|
|
104
|
+
### Configuração Obrigatória
|
|
105
|
+
```bicep
|
|
106
|
+
resource appService 'Microsoft.Web/sites@2022-03-01' = {
|
|
107
|
+
name: 'app-${projectName}-${environment}'
|
|
108
|
+
location: location
|
|
109
|
+
properties: {
|
|
110
|
+
serverFarmId: appServicePlan.id
|
|
111
|
+
httpsOnly: true
|
|
112
|
+
siteConfig: {
|
|
113
|
+
netFrameworkVersion: 'v8.0'
|
|
114
|
+
alwaysOn: false # ⚠️ OBRIGATÓRIO no Free tier
|
|
115
|
+
minTlsVersion: '1.2'
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = {
|
|
121
|
+
name: 'plan-${projectName}-${environment}'
|
|
122
|
+
location: location
|
|
123
|
+
sku: {
|
|
124
|
+
name: 'F1' # Free tier
|
|
125
|
+
tier: 'Free'
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Limitações Importantes
|
|
131
|
+
- ⚠️ **CPU**: Apenas 60 minutos/dia (não contínuos)
|
|
132
|
+
- ⚠️ **Sleep**: App dorme após 20 minutos de inatividade
|
|
133
|
+
- ⚠️ **SSL**: Apenas `*.azurewebsites.net` (sem domínio customizado)
|
|
134
|
+
- ⚠️ **Escala**: Sem scale-out (apenas 1 instância)
|
|
135
|
+
- ✅ **Memória**: 1GB RAM
|
|
136
|
+
- ✅ **Storage**: 1GB disco
|
|
137
|
+
|
|
138
|
+
### Deploy
|
|
139
|
+
```bash
|
|
140
|
+
# Via Azure CLI
|
|
141
|
+
az webapp up --name app-myproject-dev --runtime "DOTNET:8.0"
|
|
142
|
+
|
|
143
|
+
# Via GitHub Actions
|
|
144
|
+
- task: AzureWebApp@1
|
|
145
|
+
inputs:
|
|
146
|
+
azureSubscription: 'Azure-Connection'
|
|
147
|
+
appName: 'app-myproject-dev'
|
|
148
|
+
package: '$(Build.ArtifactStagingDirectory)/**/*.zip'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Quando Migrar para Container Apps
|
|
152
|
+
Se você observar:
|
|
153
|
+
- 🔴 CPU quota esgotada frequentemente
|
|
154
|
+
- 🔴 Cold starts afetando UX
|
|
155
|
+
- 🔴 Necessidade de SSL customizado
|
|
156
|
+
- 🔴 Tráfego crescendo (>1000 req/dia)
|
|
157
|
+
|
|
158
|
+
**→ Considere migrar para Container Apps Consumption**
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## 🐳 Container Apps
|
|
163
|
+
|
|
164
|
+
### Configuração Obrigatória
|
|
165
|
+
```yaml
|
|
166
|
+
properties:
|
|
167
|
+
template:
|
|
168
|
+
scale:
|
|
169
|
+
minReplicas: 0 # ⚠️ OBRIGATÓRIO: scale-to-zero
|
|
170
|
+
maxReplicas: 2
|
|
171
|
+
containers:
|
|
172
|
+
- name: app
|
|
173
|
+
resources:
|
|
174
|
+
cpu: 0.25 # Mínimo
|
|
175
|
+
memory: 0.5Gi # Mínimo
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Scale-to-Zero
|
|
179
|
+
- ✅ **OBRIGATÓRIO** para dev/staging
|
|
180
|
+
- ⚠️ Em prod com Hangfire: `minReplicas: 1`
|
|
181
|
+
- 💰 Economia: ~80% vs always-on
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## 🗄️ Azure SQL Free Tier
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
- 32 GB storage
|
|
189
|
+
- 100,000 vCore seconds/month
|
|
190
|
+
- Serverless compute
|
|
191
|
+
- Auto-pause after 1 hour idle
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Práticas
|
|
195
|
+
- ✅ Usar Managed Identity
|
|
196
|
+
- ✅ TDE habilitado (default)
|
|
197
|
+
- ❌ Não criar índices em excesso
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## 🤖 Azure OpenAI
|
|
202
|
+
|
|
203
|
+
### Modelo Padrão: gpt-4o-mini
|
|
204
|
+
|
|
205
|
+
| Modelo | Custo Input | Custo Output | Usar |
|
|
206
|
+
|--------|-------------|--------------|------|
|
|
207
|
+
| **gpt-4o-mini** | $0.15/1M | $0.60/1M | ✅ PADRÃO |
|
|
208
|
+
| gpt-4o | $2.50/1M | $10/1M | Com aprovação |
|
|
209
|
+
| gpt-4 | $30/1M | $60/1M | ❌ NUNCA |
|
|
210
|
+
|
|
211
|
+
### Otimização
|
|
212
|
+
```csharp
|
|
213
|
+
var settings = new OpenAIPromptExecutionSettings
|
|
214
|
+
{
|
|
215
|
+
MaxTokens = 500, // Limitar resposta
|
|
216
|
+
Temperature = 0.3 // Mais determinístico
|
|
217
|
+
};
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## 🔐 Segurança
|
|
223
|
+
|
|
224
|
+
### Managed Identity (Preferido)
|
|
225
|
+
```csharp
|
|
226
|
+
// Para Azure SQL
|
|
227
|
+
"Authentication=Active Directory Managed Identity;"
|
|
228
|
+
|
|
229
|
+
// Para Azure OpenAI
|
|
230
|
+
var credential = new DefaultAzureCredential();
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Key Vault
|
|
234
|
+
Usar apenas para:
|
|
235
|
+
- Secrets de serviços externos
|
|
236
|
+
- API keys de terceiros
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## 📛 Naming Conventions
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
{tipo}-{projeto}-{ambiente}
|
|
244
|
+
|
|
245
|
+
Exemplos:
|
|
246
|
+
- rg-myproject-dev # Resource Group
|
|
247
|
+
- app-myproject-dev # App Service
|
|
248
|
+
- plan-myproject-dev # App Service Plan
|
|
249
|
+
- ca-myproject-dev # Container App
|
|
250
|
+
- sql-myproject-dev # SQL Server
|
|
251
|
+
- sqldb-myproject-dev # SQL Database
|
|
252
|
+
- acr-myproject # Container Registry
|
|
253
|
+
- appi-myproject-dev # App Insights
|
|
254
|
+
- kv-myproject-dev # Key Vault
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
| Ambiente | Sufixo | Características |
|
|
258
|
+
|----------|--------|-----------------|
|
|
259
|
+
| Development | -dev | Scale-to-zero, free tier |
|
|
260
|
+
| Staging | -stg | Scale-to-zero, free tier |
|
|
261
|
+
| Production | -prod | Min 1 replica |
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## 🚀 Azure DevOps Pipelines
|
|
266
|
+
|
|
267
|
+
### Estratégia de Ambientes
|
|
268
|
+
|
|
269
|
+
**2 ambientes:**
|
|
270
|
+
- **Staging**: Desenvolvimento + QA (branch: `staging`)
|
|
271
|
+
- Developers rodam projeto LOCAL
|
|
272
|
+
- Acessam recursos REMOTOS staging
|
|
273
|
+
- Deploy automático via pipeline
|
|
274
|
+
|
|
275
|
+
- **Produção**: Ambiente crítico (branch: `main`/`master`)
|
|
276
|
+
- Deploy via pipeline com aprovação manual
|
|
277
|
+
- Always-on, monitoramento 24/7
|
|
278
|
+
|
|
279
|
+
### Estrutura de Pipelines
|
|
280
|
+
|
|
281
|
+
```
|
|
282
|
+
.azure/pipelines/
|
|
283
|
+
├── staging-pipeline.yml # Branch: staging
|
|
284
|
+
├── prod-pipeline.yml # Branch: main/master
|
|
285
|
+
├── pipeline-variables.yml # Variáveis compartilhadas
|
|
286
|
+
└── templates/
|
|
287
|
+
├── build-dotnet.yml
|
|
288
|
+
├── deploy-container-app.yml
|
|
289
|
+
└── infra-deploy.yml
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Pipeline Staging
|
|
293
|
+
|
|
294
|
+
```yaml
|
|
295
|
+
# staging-pipeline.yml
|
|
296
|
+
trigger:
|
|
297
|
+
branches:
|
|
298
|
+
include: [staging]
|
|
299
|
+
|
|
300
|
+
variables:
|
|
301
|
+
- template: pipeline-variables.yml
|
|
302
|
+
- name: environment
|
|
303
|
+
value: 'staging'
|
|
304
|
+
- name: hostingType
|
|
305
|
+
value: 'containerapp'
|
|
306
|
+
|
|
307
|
+
stages:
|
|
308
|
+
- stage: Build
|
|
309
|
+
- stage: DeployInfra
|
|
310
|
+
- stage: BuildContainer
|
|
311
|
+
- stage: DeployApp
|
|
312
|
+
jobs:
|
|
313
|
+
- deployment: DeployAppJob
|
|
314
|
+
environment: 'staging' # No approval
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Pipeline Production
|
|
318
|
+
|
|
319
|
+
```yaml
|
|
320
|
+
# prod-pipeline.yml
|
|
321
|
+
trigger:
|
|
322
|
+
branches:
|
|
323
|
+
include: [main, master]
|
|
324
|
+
|
|
325
|
+
variables:
|
|
326
|
+
- template: pipeline-variables.yml
|
|
327
|
+
- name: environment
|
|
328
|
+
value: 'prod'
|
|
329
|
+
- name: hostingType
|
|
330
|
+
value: 'containerapp'
|
|
331
|
+
|
|
332
|
+
stages:
|
|
333
|
+
- stage: Build
|
|
334
|
+
- stage: SecurityScan
|
|
335
|
+
- stage: DeployInfra
|
|
336
|
+
- stage: BuildContainer
|
|
337
|
+
- stage: DeployApp
|
|
338
|
+
jobs:
|
|
339
|
+
- deployment: DeployAppJob
|
|
340
|
+
environment: 'production' # Approval required
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Workload Identity (Sem Secrets)
|
|
344
|
+
|
|
345
|
+
Ao invés de Service Principals com secrets, use Workload Identity Federation:
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
# Criar App Registration com Federated Credential
|
|
349
|
+
az ad app create --display-name "myapp-prod-pipeline"
|
|
350
|
+
|
|
351
|
+
# Configurar federated credential
|
|
352
|
+
az ad app federated-credential create \
|
|
353
|
+
--id <APP_ID> \
|
|
354
|
+
--parameters @federated-credential.json
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
**Vantagens:**
|
|
358
|
+
- ✅ Sem secrets para gerenciar
|
|
359
|
+
- ✅ Rotação automática de tokens
|
|
360
|
+
- ✅ Mais seguro
|
|
361
|
+
- ✅ Auditoria melhorada
|
|
362
|
+
|
|
363
|
+
**Documentação completa:** `.azure/docs/azure-devops-setup.md`
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## ✅ Checklist de Deploy
|
|
368
|
+
|
|
369
|
+
### Antes
|
|
370
|
+
- [ ] Testes passando
|
|
371
|
+
- [ ] Migrations aplicadas
|
|
372
|
+
- [ ] Secrets no Key Vault
|
|
373
|
+
- [ ] Managed Identity configurada
|
|
374
|
+
|
|
375
|
+
### Após
|
|
376
|
+
- [ ] Health check OK
|
|
377
|
+
- [ ] Logs no App Insights
|
|
378
|
+
- [ ] Funcionalidade testada
|
|
379
|
+
- [ ] Custos verificados
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## ⚠️ Package Version Conflicts
|
|
384
|
+
|
|
385
|
+
### Azure.Identity Downgrade Error
|
|
386
|
+
|
|
387
|
+
**Error:**
|
|
388
|
+
```
|
|
389
|
+
NU1605: Detected package downgrade: Azure.Identity from 1.14.2 to 1.13.2
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
**Cause:** `Microsoft.Data.SqlClient` or other packages require a newer version.
|
|
393
|
+
|
|
394
|
+
**Solution:** Always specify `Azure.Identity` explicitly in your `.csproj`:
|
|
395
|
+
|
|
396
|
+
```xml
|
|
397
|
+
<!-- Prevent version conflicts -->
|
|
398
|
+
<PackageReference Include="Azure.Identity" Version="1.14.2" />
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
**Why this happens:**
|
|
402
|
+
- Transitive dependencies pull different versions
|
|
403
|
+
- NuGet picks the lowest common version
|
|
404
|
+
- This causes runtime failures with newer APIs
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## 🔑 Key Vault Configuration
|
|
409
|
+
|
|
410
|
+
### Critical Rule
|
|
411
|
+
|
|
412
|
+
**NEVER condition Key Vault loading on environment. Load whenever URI is configured.**
|
|
413
|
+
|
|
414
|
+
**❌ WRONG:**
|
|
415
|
+
```csharp
|
|
416
|
+
// This breaks DI in development!
|
|
417
|
+
if (!string.IsNullOrEmpty(keyVaultUri) && !builder.Environment.IsDevelopment())
|
|
418
|
+
{
|
|
419
|
+
builder.Configuration.AddAzureKeyVault(...);
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
**✅ CORRECT:**
|
|
424
|
+
```csharp
|
|
425
|
+
// Load Key Vault in ALL environments where URI exists
|
|
426
|
+
if (!string.IsNullOrEmpty(keyVaultUri))
|
|
427
|
+
{
|
|
428
|
+
builder.Configuration.AddAzureKeyVault(
|
|
429
|
+
new Uri(keyVaultUri),
|
|
430
|
+
new DefaultAzureCredential());
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
**Why:**
|
|
435
|
+
- Services registered via DI may depend on Key Vault secrets
|
|
436
|
+
- `IBlobStorageService`, `IPaymentService`, etc. fail if secrets not loaded
|
|
437
|
+
- Development can use Azure Key Vault with developer credentials
|
|
438
|
+
- Or use `appsettings.Development.json` to override secrets locally
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## 🚀 DefaultAzureCredential Optimization
|
|
443
|
+
|
|
444
|
+
### Problem
|
|
445
|
+
|
|
446
|
+
`DefaultAzureCredential` is **slow in containers** because it tries multiple authentication methods sequentially (environment, workload identity, managed identity, Visual Studio, CLI, etc.).
|
|
447
|
+
|
|
448
|
+
**Symptom:** Startup takes 30+ seconds, or times out.
|
|
449
|
+
|
|
450
|
+
### Solution: Disable Unused Credential Types
|
|
451
|
+
|
|
452
|
+
```csharp
|
|
453
|
+
// For Container Apps / AKS with Managed Identity ONLY
|
|
454
|
+
var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions
|
|
455
|
+
{
|
|
456
|
+
// Disable all except Managed Identity
|
|
457
|
+
ExcludeEnvironmentCredential = true,
|
|
458
|
+
ExcludeWorkloadIdentityCredential = true,
|
|
459
|
+
ExcludeSharedTokenCacheCredential = true,
|
|
460
|
+
ExcludeVisualStudioCredential = true,
|
|
461
|
+
ExcludeVisualStudioCodeCredential = true,
|
|
462
|
+
ExcludeAzureCliCredential = true,
|
|
463
|
+
ExcludeAzurePowerShellCredential = true,
|
|
464
|
+
ExcludeAzureDeveloperCliCredential = true,
|
|
465
|
+
ExcludeInteractiveBrowserCredential = true,
|
|
466
|
+
ExcludeManagedIdentityCredential = false // Keep this one!
|
|
467
|
+
});
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### Environment-Specific Configuration
|
|
471
|
+
|
|
472
|
+
```csharp
|
|
473
|
+
// Program.cs - Smart credential selection
|
|
474
|
+
DefaultAzureCredential CreateCredential(IHostEnvironment env)
|
|
475
|
+
{
|
|
476
|
+
if (env.IsDevelopment())
|
|
477
|
+
{
|
|
478
|
+
// Development: Allow CLI, VS, VS Code
|
|
479
|
+
return new DefaultAzureCredential();
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Production: Only Managed Identity (fast!)
|
|
483
|
+
return new DefaultAzureCredential(new DefaultAzureCredentialOptions
|
|
484
|
+
{
|
|
485
|
+
ExcludeEnvironmentCredential = true,
|
|
486
|
+
ExcludeWorkloadIdentityCredential = true,
|
|
487
|
+
ExcludeSharedTokenCacheCredential = true,
|
|
488
|
+
ExcludeVisualStudioCredential = true,
|
|
489
|
+
ExcludeVisualStudioCodeCredential = true,
|
|
490
|
+
ExcludeAzureCliCredential = true,
|
|
491
|
+
ExcludeAzurePowerShellCredential = true,
|
|
492
|
+
ExcludeAzureDeveloperCliCredential = true,
|
|
493
|
+
ExcludeInteractiveBrowserCredential = true,
|
|
494
|
+
ExcludeManagedIdentityCredential = false
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## 🐳 Container App Deployment Issues
|
|
502
|
+
|
|
503
|
+
### Problem: Container App Not Updating
|
|
504
|
+
|
|
505
|
+
After pushing a new image, Container App continues running the old version.
|
|
506
|
+
|
|
507
|
+
**Cause:** Same image digest doesn't trigger a new revision.
|
|
508
|
+
|
|
509
|
+
**Solution:** Force a new revision with a timestamp:
|
|
510
|
+
|
|
511
|
+
```bash
|
|
512
|
+
# Force new revision with environment variable
|
|
513
|
+
az containerapp update \
|
|
514
|
+
--name ca-myapp-prod \
|
|
515
|
+
--resource-group rg-myapp-prod \
|
|
516
|
+
--set-env-vars "DEPLOY_TIMESTAMP=$(date +%s)"
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### Complete Deploy Script
|
|
520
|
+
|
|
521
|
+
```bash
|
|
522
|
+
#!/bin/bash
|
|
523
|
+
# deploy-container-app.sh
|
|
524
|
+
|
|
525
|
+
APP_NAME="ca-myapp-prod"
|
|
526
|
+
RG_NAME="rg-myapp-prod"
|
|
527
|
+
ACR_NAME="acrmyapp"
|
|
528
|
+
IMAGE_TAG="latest"
|
|
529
|
+
|
|
530
|
+
# 1. Build and push
|
|
531
|
+
docker build --no-cache -t $ACR_NAME.azurecr.io/myapp:$IMAGE_TAG .
|
|
532
|
+
docker push $ACR_NAME.azurecr.io/myapp:$IMAGE_TAG
|
|
533
|
+
|
|
534
|
+
# 2. Update with timestamp (forces new revision)
|
|
535
|
+
az containerapp update \
|
|
536
|
+
--name $APP_NAME \
|
|
537
|
+
--resource-group $RG_NAME \
|
|
538
|
+
--set-env-vars "DEPLOY_TIMESTAMP=$(date +%s)"
|
|
539
|
+
|
|
540
|
+
# 3. Verify
|
|
541
|
+
az containerapp show \
|
|
542
|
+
--name $APP_NAME \
|
|
543
|
+
--resource-group $RG_NAME \
|
|
544
|
+
--query "properties.runningStatus"
|
|
545
|
+
|
|
546
|
+
# 4. Check logs
|
|
547
|
+
az containerapp logs show \
|
|
548
|
+
--name $APP_NAME \
|
|
549
|
+
--resource-group $RG_NAME \
|
|
550
|
+
--follow
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
---
|
|
554
|
+
|
|
555
|
+
## 🔧 Troubleshooting Azure
|
|
556
|
+
|
|
557
|
+
Quick reference for common Azure issues:
|
|
558
|
+
|
|
559
|
+
### Key Vault access denied
|
|
560
|
+
→ Verify RBAC role assignment (Key Vault Secrets User)
|
|
561
|
+
→ Check Managed Identity is enabled on the resource
|
|
562
|
+
→ Verify Key Vault firewall allows the resource's IP/VNet
|
|
563
|
+
|
|
564
|
+
### Container App 404
|
|
565
|
+
→ Check ingress configuration (external/internal)
|
|
566
|
+
→ Verify health probe endpoint exists and returns 200
|
|
567
|
+
→ Check container is actually running (logs)
|
|
568
|
+
|
|
569
|
+
### Managed Identity not working
|
|
570
|
+
→ Verify identity is assigned to the resource
|
|
571
|
+
→ Check RBAC scope (subscription vs resource group vs resource)
|
|
572
|
+
→ Allow 5-10 minutes for propagation after assignment
|
|
573
|
+
|
|
574
|
+
### blazor.web.js 404 (.NET 10)
|
|
575
|
+
→ Add to `.csproj`:
|
|
576
|
+
```xml
|
|
577
|
+
<RequiresAspNetWebAssets>true</RequiresAspNetWebAssets>
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
### DefaultAzureCredential slow/timeout
|
|
581
|
+
→ Disable unused credential types (see section above)
|
|
582
|
+
→ Check network connectivity to Azure AD
|
|
583
|
+
|
|
584
|
+
### Container App not updating
|
|
585
|
+
→ Use `DEPLOY_TIMESTAMP` to force new revision (see section above)
|
|
586
|
+
→ Verify image was actually pushed to ACR
|
|
587
|
+
→ Check ACR webhook/event subscription
|
|
588
|
+
|
|
589
|
+
### EF Core migrations not applied
|
|
590
|
+
→ Add auto-migration to startup (dev/staging only)
|
|
591
|
+
→ Or run migration in pipeline before deploy
|
|
592
|
+
|
|
593
|
+
---
|
|
594
|
+
|
|
595
|
+
## 📚 Lessons Learned - Deploy
|
|
596
|
+
|
|
597
|
+
Key insights from production deployments:
|
|
598
|
+
|
|
599
|
+
1. **`docker build --no-cache`** is essential when debugging image issues
|
|
600
|
+
2. **`DEPLOY_TIMESTAMP`** forces new revision in Container Apps
|
|
601
|
+
3. **.NET 10 Preview** has undocumented breaking changes - check GitHub Issues
|
|
602
|
+
4. **GitHub Issues** are more effective than official docs for edge cases
|
|
603
|
+
5. **Auto-migration** simplifies deploy but has risks in production
|
|
604
|
+
6. **Key Vault in dev** needs developer credentials, not just prod Managed Identity
|
|
605
|
+
7. **Document while solving** - saves time later (hence this document!)
|