@polymorphism-tech/morph-spec 4.3.4 → 4.3.6
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/.morph/.morphversion +5 -0
- package/.morph/config/agents.json +948 -0
- package/.morph/config/config.json +9 -9
- package/.morph/project/context/README.md +17 -0
- package/.morph/project/context/detection-log.md +16 -0
- package/.morph/project/standards/inferred.md +59 -0
- package/.morph/standards/ai-agents/blazor-ui.md +364 -0
- package/.morph/standards/ai-agents/production.md +415 -0
- package/.morph/standards/ai-agents/setup.md +418 -0
- package/.morph/standards/ai-agents/team-orchestration.md +479 -0
- package/.morph/standards/ai-agents/workflows.md +354 -0
- package/.morph/standards/architecture/ddd/aggregates.md +120 -0
- package/.morph/standards/architecture/ddd/entities.md +99 -0
- package/.morph/standards/architecture/ddd/value-objects.md +124 -0
- package/.morph/standards/backend/api/minimal-api.md +494 -0
- package/.morph/standards/backend/api/rest.md +492 -0
- package/.morph/standards/backend/api/validation.md +88 -0
- package/.morph/standards/backend/authentication/passkeys.md +428 -0
- package/.morph/standards/backend/database/ef-core.md +199 -0
- package/.morph/standards/backend/database/migrations.md +393 -0
- package/.morph/standards/backend/database/postgresql/database.md +352 -0
- package/.morph/standards/backend/database/repository-patterns.md +528 -0
- package/.morph/standards/backend/database/vector-search-rag.md +541 -0
- package/.morph/standards/backend/dotnet/async.md +366 -0
- package/.morph/standards/backend/dotnet/core.md +117 -0
- package/.morph/standards/backend/dotnet/di.md +439 -0
- package/.morph/standards/backend/dotnet/program-cs-checklist.md +92 -0
- package/.morph/standards/backend/integrations/asaas/asaas-api.md +216 -0
- package/.morph/standards/backend/integrations/clerk/clerk-auth.md +290 -0
- package/.morph/standards/backend/integrations/hangfire/hangfire-jobs.md +350 -0
- package/.morph/standards/backend/integrations/resend/resend-email.md +385 -0
- package/.morph/standards/context/analytics.md +96 -0
- package/.morph/standards/context/bundles.md +110 -0
- package/.morph/standards/context/priming.md +78 -0
- package/.morph/standards/core/architecture.md +185 -0
- package/.morph/standards/core/coding.md +214 -0
- package/.morph/standards/core/git-branching-strategy.md +403 -0
- package/.morph/standards/core/git.md +185 -0
- package/.morph/standards/core/testing.md +295 -0
- package/.morph/standards/data/nosql/blob-storage.md +102 -0
- package/.morph/standards/data/nosql/cache/redis.md +97 -0
- package/.morph/standards/data/nosql/cosmos-db.md +118 -0
- package/.morph/standards/data/vector-search/azure-ai-search.md +121 -0
- package/.morph/standards/data/vector-search/rag-chunking.md +104 -0
- package/.morph/standards/frontend/blazor/design-checklist.md +222 -0
- package/.morph/standards/frontend/blazor/fluent-ui-setup.md +595 -0
- package/.morph/standards/frontend/blazor/fluent-ui.md +137 -0
- package/.morph/standards/frontend/blazor/html-conversion.md +184 -0
- package/.morph/standards/frontend/blazor/lifecycle.md +195 -0
- package/.morph/standards/frontend/blazor/pitfalls.md +198 -0
- package/.morph/standards/frontend/blazor/state.md +191 -0
- package/.morph/standards/frontend/design-system/animations.md +151 -0
- package/.morph/standards/frontend/design-system/naming.md +64 -0
- package/.morph/standards/frontend/nextjs/nextjs-patterns.md +198 -0
- package/.morph/standards/infrastructure/azure/azure.md +624 -0
- package/.morph/standards/infrastructure/azure/bicep/bicep-patterns.md +422 -0
- package/.morph/standards/infrastructure/azure/devops/azure-devops-setup.md +516 -0
- package/.morph/standards/infrastructure/azure/devops/local-development.md +520 -0
- package/.morph/standards/infrastructure/azure/services/functions.md +486 -0
- package/.morph/standards/infrastructure/azure/services/service-bus.md +459 -0
- package/.morph/standards/infrastructure/azure/services/storage.md +407 -0
- package/.morph/standards/infrastructure/docker/easypanel-deploy.md +196 -0
- package/.morph/standards/infrastructure/supabase/mcp-setup.md +252 -0
- package/.morph/standards/infrastructure/supabase/supabase-auth.md +176 -0
- package/.morph/standards/infrastructure/supabase/supabase-pgvector.md +169 -0
- package/.morph/standards/infrastructure/supabase/supabase-rls.md +184 -0
- package/.morph/standards/infrastructure/supabase/supabase-storage.md +153 -0
- package/.morph/standards/integration/api/graphql.md +91 -0
- package/.morph/standards/integration/api/grpc.md +114 -0
- package/.morph/standards/integration/api/rest-design.md +95 -0
- package/.morph/standards/integration/event-driven/cqrs.md +101 -0
- package/.morph/standards/integration/event-driven/event-sourcing.md +124 -0
- package/.morph/standards/integration/event-driven/service-bus.md +95 -0
- package/.morph/standards/observability/logging.md +131 -0
- package/.morph/standards/observability/metrics.md +121 -0
- package/.morph/standards/observability/monitoring.md +114 -0
- package/.morph/standards/observability/tracing.md +132 -0
- package/.morph/standards/workflows/parallel-execution.md +112 -0
- package/.morph/standards/workflows/thread-management.md +113 -0
- package/.morph/templates/.idea/morph-templates.xml +92 -0
- package/.morph/templates/.vscode/morph-templates.code-snippets +186 -0
- package/.morph/templates/IDE-SNIPPETS.md +266 -0
- package/.morph/templates/README.md +814 -0
- package/.morph/templates/REGISTRY.json +1677 -0
- package/.morph/templates/code/dotnet/backend/repository.cs +141 -0
- package/.morph/templates/code/dotnet/backend/service.cs +139 -0
- package/.morph/templates/code/dotnet/contracts/Commands.cs +74 -0
- package/.morph/templates/code/dotnet/contracts/Entities.cs +25 -0
- package/.morph/templates/code/dotnet/contracts/Queries.cs +74 -0
- package/.morph/templates/code/dotnet/contracts/README.md +74 -0
- package/.morph/templates/code/dotnet/contracts/api-contracts.cs +173 -0
- package/.morph/templates/code/dotnet/contracts/contracts.cs +217 -0
- package/.morph/templates/code/dotnet/database/migration.cs +83 -0
- package/.morph/templates/code/dotnet/frontend/component.razor +239 -0
- package/.morph/templates/code/dotnet/jobs/agent.cs +163 -0
- package/.morph/templates/code/dotnet/jobs/job.cs +171 -0
- package/.morph/templates/code/dotnet/test.cs +239 -0
- package/.morph/templates/code/sql/rls-policy.sql +57 -0
- package/.morph/templates/code/sql/supabase-migration.sql +100 -0
- package/.morph/templates/code/sql/supabase-migration.template.sql +113 -0
- package/.morph/templates/code/typescript/contracts.ts +168 -0
- package/.morph/templates/context/CONTEXT-FEATURE.md +276 -0
- package/.morph/templates/context/CONTEXT.md +181 -0
- package/.morph/templates/docs/proposal.md +182 -0
- package/.morph/templates/docs/spec.md +149 -0
- package/.morph/templates/examples/design-system-examples.md +357 -0
- package/.morph/templates/examples/spec-examples.md +90 -0
- package/.morph/templates/feature/decisions.md +187 -0
- package/.morph/templates/feature/recap.md +146 -0
- package/.morph/templates/feature/tasks.md +199 -0
- package/.morph/templates/infrastructure/azure/Dockerfile.example +82 -0
- package/.morph/templates/infrastructure/azure/README.md +286 -0
- package/.morph/templates/infrastructure/azure/app-insights.bicep +63 -0
- package/.morph/templates/infrastructure/azure/app-service.bicep +164 -0
- package/.morph/templates/infrastructure/azure/container-app-env.bicep +49 -0
- package/.morph/templates/infrastructure/azure/container-app.bicep +156 -0
- package/.morph/templates/infrastructure/azure/deploy-checklist.md +426 -0
- package/.morph/templates/infrastructure/azure/deploy.ps1 +229 -0
- package/.morph/templates/infrastructure/azure/deploy.sh +208 -0
- package/.morph/templates/infrastructure/azure/key-vault.bicep +91 -0
- package/.morph/templates/infrastructure/azure/main.bicep +189 -0
- package/.morph/templates/infrastructure/azure/parameters.dev.json +29 -0
- package/.morph/templates/infrastructure/azure/parameters.prod.json +29 -0
- package/.morph/templates/infrastructure/azure/parameters.staging.json +29 -0
- package/.morph/templates/infrastructure/azure/sql-database.bicep +103 -0
- package/.morph/templates/infrastructure/azure/storage.bicep +106 -0
- package/.morph/templates/infrastructure/docker/Dockerfile.template +58 -0
- package/.morph/templates/infrastructure/docker/docker-compose.template.yml +67 -0
- package/.morph/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -0
- package/.morph/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -0
- package/.morph/templates/infrastructure/docker/easypanel.template.json +54 -0
- package/.morph/templates/infrastructure/github/README.md +593 -0
- package/.morph/templates/infrastructure/github/actions/azure-auth/action.yml.hbs +22 -0
- package/.morph/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -0
- package/.morph/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -0
- package/.morph/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +61 -0
- package/.morph/templates/infrastructure/github/workflows/deploy-easypanel.yml.hbs +31 -0
- package/.morph/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -0
- package/.morph/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -0
- package/.morph/templates/integrations/asaas-client.cs +387 -0
- package/.morph/templates/integrations/asaas-webhook.cs +351 -0
- package/.morph/templates/integrations/azure-identity-config.cs +288 -0
- package/.morph/templates/integrations/clerk-config.cs +258 -0
- package/.morph/templates/meta-prompts/fusion/fusion-agent.md +76 -0
- package/.morph/templates/meta-prompts/fusion/fusion-aggregator.md +100 -0
- package/.morph/templates/meta-prompts/hops/hop-retry.md +78 -0
- package/.morph/templates/meta-prompts/hops/hop-validation.md +97 -0
- package/.morph/templates/meta-prompts/hops/hop-wrapper.md +36 -0
- package/.morph/templates/meta-prompts/parallel-workers/parallel-coordinator.md +113 -0
- package/.morph/templates/meta-prompts/parallel-workers/parallel-worker.md +80 -0
- package/.morph/templates/meta-prompts/squad-leaders/backend-squad.md +90 -0
- package/.morph/templates/meta-prompts/squad-leaders/frontend-squad.md +126 -0
- package/.morph/templates/meta-prompts/squad-leaders/squad-leader.md +43 -0
- package/.morph/templates/meta-prompts/validators/checkpoint-validator.md +107 -0
- package/.morph/templates/meta-prompts/validators/pre-commit-validator.md +95 -0
- package/.morph/templates/saas/subscription.cs +347 -0
- package/.morph/templates/saas/tenant.cs +338 -0
- package/.morph/templates/state.template.json +17 -0
- package/.morph/templates/ui/FluentDesignTheme.cs +149 -0
- package/.morph/templates/ui/MudTheme.cs +281 -0
- package/.morph/templates/ui/design-system.css +226 -0
- package/bin/morph-spec.js +1 -1
- package/package.json +1 -1
- package/src/commands/project/update.js +185 -46
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# MORPH-SPEC - Templates Bicep
|
|
2
|
+
|
|
3
|
+
Templates de infraestrutura para Azure com suporte a App Service e Container Apps.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🚀 Quick Start
|
|
8
|
+
|
|
9
|
+
### 1. App Service Free (Desenvolvimento - $0/mês)
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Deploy infraestrutura com App Service Free
|
|
13
|
+
az deployment group create \
|
|
14
|
+
--resource-group rg-myapp-dev \
|
|
15
|
+
--template-file main.bicep \
|
|
16
|
+
--parameters @parameters.dev.json \
|
|
17
|
+
--parameters appName=myapp
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### 2. Container Apps (Produção - $5-15/mês)
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Build e push imagem para ACR
|
|
24
|
+
az acr build \
|
|
25
|
+
--registry acrXXXX \
|
|
26
|
+
--image myapp:v1.0.0 \
|
|
27
|
+
--file Dockerfile \
|
|
28
|
+
.
|
|
29
|
+
|
|
30
|
+
# Deploy infraestrutura com Container Apps
|
|
31
|
+
az deployment group create \
|
|
32
|
+
--resource-group rg-myapp-prod \
|
|
33
|
+
--template-file main.bicep \
|
|
34
|
+
--parameters @parameters.prod.json \
|
|
35
|
+
--parameters appName=myapp
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 📁 Estrutura de Arquivos
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
infra/
|
|
44
|
+
├── main.bicep # Entry point com lógica condicional
|
|
45
|
+
├── parameters.dev.json # Params dev (App Service Free)
|
|
46
|
+
├── parameters.prod.json # Params prod (Container Apps)
|
|
47
|
+
├── app-service.bicep # Template App Service
|
|
48
|
+
├── container-app.bicep # Template Container App
|
|
49
|
+
├── container-app-env.bicep # Container Apps Environment
|
|
50
|
+
├── sql-database.bicep # Azure SQL Database
|
|
51
|
+
├── storage.bicep # Storage Account
|
|
52
|
+
├── key-vault.bicep # Key Vault
|
|
53
|
+
└── app-insights.bicep # Application Insights
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## ⚙️ Parâmetros Principais
|
|
59
|
+
|
|
60
|
+
### main.bicep
|
|
61
|
+
|
|
62
|
+
| Parâmetro | Tipo | Default | Descrição |
|
|
63
|
+
|-----------|------|---------|-----------|
|
|
64
|
+
| `environment` | string | `dev` | Ambiente (dev, staging, prod) |
|
|
65
|
+
| `appName` | string | **required** | Nome da aplicação (3-15 chars) |
|
|
66
|
+
| `location` | string | `resourceGroup().location` | Região Azure |
|
|
67
|
+
| `hostingType` | string | `appservice` | Tipo de hosting (`appservice` ou `containerapp`) |
|
|
68
|
+
| `appServiceSku` | string | `F1` | SKU do App Service (F1, B1, S1, P1v2) |
|
|
69
|
+
| `containerImage` | string | `mcr.microsoft.com/hello-world:latest` | Imagem Docker (apenas Container Apps) |
|
|
70
|
+
| `sqlAdminPassword` | securestring | **required** | Senha do SQL Server |
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 🌐 Escolhendo o Hosting Type
|
|
75
|
+
|
|
76
|
+
### App Service (`hostingType: appservice`)
|
|
77
|
+
|
|
78
|
+
**Usar quando:**
|
|
79
|
+
- ✅ Orçamento zero (Free F1)
|
|
80
|
+
- ✅ MVP ou protótipo
|
|
81
|
+
- ✅ Tráfego baixo (<100 req/dia)
|
|
82
|
+
- ✅ App tolerante a cold starts (20 min sleep)
|
|
83
|
+
- ✅ Deploy simplificado (sem Docker)
|
|
84
|
+
|
|
85
|
+
**SKUs disponíveis:**
|
|
86
|
+
- `F1` (Free): $0/mês - 1GB RAM, 60 min CPU/dia, sleep após 20min
|
|
87
|
+
- `B1` (Basic): $13/mês - 1.75GB RAM, always-on
|
|
88
|
+
- `S1` (Standard): $70/mês - 1.75GB RAM, auto-scale, slots
|
|
89
|
+
- `P1v2` (Premium): $85/mês - 3.5GB RAM, melhor performance
|
|
90
|
+
|
|
91
|
+
### Container Apps (`hostingType: containerapp`)
|
|
92
|
+
|
|
93
|
+
**Usar quando:**
|
|
94
|
+
- ✅ Produção com SLA 24/7
|
|
95
|
+
- ✅ Auto-scaling baseado em demanda
|
|
96
|
+
- ✅ SSL customizado necessário
|
|
97
|
+
- ✅ Background jobs (Hangfire)
|
|
98
|
+
- ✅ Arquitetura microserviços
|
|
99
|
+
|
|
100
|
+
**Custo:** $0-15/mês (scale-to-zero + consumo)
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 📝 Configuração por Ambiente
|
|
105
|
+
|
|
106
|
+
### Development (parameters.dev.json)
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"environment": { "value": "dev" },
|
|
111
|
+
"hostingType": { "value": "appservice" },
|
|
112
|
+
"appServiceSku": { "value": "F1" }
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Infraestrutura:**
|
|
117
|
+
- App Service Free F1
|
|
118
|
+
- Azure SQL Free (32GB)
|
|
119
|
+
- App Insights Free (5GB)
|
|
120
|
+
|
|
121
|
+
**Custo total:** $0/mês
|
|
122
|
+
|
|
123
|
+
### Staging (parameters.staging.json)
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"environment": { "value": "staging" },
|
|
128
|
+
"hostingType": { "value": "containerapp" },
|
|
129
|
+
"minReplicas": { "value": 0 } // scale-to-zero
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Infraestrutura:**
|
|
134
|
+
- Container Apps (scale-to-zero)
|
|
135
|
+
- Azure SQL Free (32GB)
|
|
136
|
+
- ACR Basic
|
|
137
|
+
- App Insights Free
|
|
138
|
+
|
|
139
|
+
**Custo total:** $5-10/mês
|
|
140
|
+
|
|
141
|
+
### Production (parameters.prod.json)
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"environment": { "value": "prod" },
|
|
146
|
+
"hostingType": { "value": "containerapp" },
|
|
147
|
+
"minReplicas": { "value": 1 } // always-on
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Infraestrutura:**
|
|
152
|
+
- Container Apps (min 1 replica)
|
|
153
|
+
- Azure SQL Free (ou pago se necessário)
|
|
154
|
+
- ACR Basic
|
|
155
|
+
- App Insights (pode ultrapassar free tier)
|
|
156
|
+
|
|
157
|
+
**Custo total:** $10-20/mês
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 🔧 Customização
|
|
162
|
+
|
|
163
|
+
### Adicionar variáveis de ambiente
|
|
164
|
+
|
|
165
|
+
**App Service:**
|
|
166
|
+
```bicep
|
|
167
|
+
module appService 'app-service.bicep' = {
|
|
168
|
+
params: {
|
|
169
|
+
envVars: {
|
|
170
|
+
MY_CUSTOM_VAR: 'value'
|
|
171
|
+
ANOTHER_VAR: 'another-value'
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Container Apps:**
|
|
178
|
+
```bicep
|
|
179
|
+
module containerApp 'container-app.bicep' = {
|
|
180
|
+
params: {
|
|
181
|
+
envVars: [
|
|
182
|
+
{
|
|
183
|
+
name: 'MY_CUSTOM_VAR'
|
|
184
|
+
value: 'value'
|
|
185
|
+
}
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Usar secrets do Key Vault
|
|
192
|
+
|
|
193
|
+
```bicep
|
|
194
|
+
param sqlAdminPassword string {
|
|
195
|
+
reference: {
|
|
196
|
+
keyVault: {
|
|
197
|
+
id: '/subscriptions/.../providers/Microsoft.KeyVault/vaults/kv-myapp'
|
|
198
|
+
}
|
|
199
|
+
secretName: 'sql-admin-password'
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## 🔄 Migração App Service → Container Apps
|
|
207
|
+
|
|
208
|
+
Ver guia completo em: `../../standards/migration-guide.md`
|
|
209
|
+
|
|
210
|
+
**Resumo:**
|
|
211
|
+
1. Criar Dockerfile
|
|
212
|
+
2. Implementar health checks
|
|
213
|
+
3. Build e push para ACR
|
|
214
|
+
4. Atualizar `parameters.json` → `hostingType: containerapp`
|
|
215
|
+
5. Redeploy
|
|
216
|
+
6. Testar
|
|
217
|
+
7. Cutover DNS
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## 📊 Outputs Gerados
|
|
222
|
+
|
|
223
|
+
Após deploy, os seguintes outputs são gerados:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
# Obter URL da aplicação
|
|
227
|
+
az deployment group show \
|
|
228
|
+
-g rg-myapp-dev \
|
|
229
|
+
-n deployment-name \
|
|
230
|
+
--query properties.outputs.appUrl.value
|
|
231
|
+
|
|
232
|
+
# Obter connection string SQL
|
|
233
|
+
az deployment group show \
|
|
234
|
+
-g rg-myapp-dev \
|
|
235
|
+
-n deployment-name \
|
|
236
|
+
--query properties.outputs.sqlConnectionString.value
|
|
237
|
+
|
|
238
|
+
# Obter App Insights connection string
|
|
239
|
+
az deployment group show \
|
|
240
|
+
-g rg-myapp-dev \
|
|
241
|
+
-n deployment-name \
|
|
242
|
+
--query properties.outputs.appInsightsConnectionString.value
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 🆘 Troubleshooting
|
|
248
|
+
|
|
249
|
+
### Erro: "The template deployment 'X' is not valid"
|
|
250
|
+
|
|
251
|
+
Validar template:
|
|
252
|
+
```bash
|
|
253
|
+
az deployment group validate \
|
|
254
|
+
--resource-group rg-myapp-dev \
|
|
255
|
+
--template-file main.bicep \
|
|
256
|
+
--parameters @parameters.dev.json
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Erro: "SKU not available in this location"
|
|
260
|
+
|
|
261
|
+
Verificar SKUs disponíveis:
|
|
262
|
+
```bash
|
|
263
|
+
az appservice list-locations --sku F1
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Deploy muito lento
|
|
267
|
+
|
|
268
|
+
Container Apps pode levar 5-10 minutos no primeiro deploy. Use `--no-wait` para não bloquear:
|
|
269
|
+
```bash
|
|
270
|
+
az deployment group create \
|
|
271
|
+
... \
|
|
272
|
+
--no-wait
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## 📚 Referências
|
|
278
|
+
|
|
279
|
+
- [Bicep Documentation](https://learn.microsoft.com/azure/azure-resource-manager/bicep/)
|
|
280
|
+
- [App Service Bicep Reference](https://learn.microsoft.com/azure/templates/microsoft.web/sites)
|
|
281
|
+
- [Container Apps Bicep Reference](https://learn.microsoft.com/azure/templates/microsoft.app/containerapps)
|
|
282
|
+
- [Azure CLI Reference](https://learn.microsoft.com/cli/azure/)
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
*MORPH-SPEC by Polymorphism Tech*
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// ==============================================================================
|
|
2
|
+
// MORPH-SPEC - Application Insights
|
|
3
|
+
// Azure Application Insights for monitoring and telemetry
|
|
4
|
+
// ==============================================================================
|
|
5
|
+
|
|
6
|
+
@description('Application Insights name')
|
|
7
|
+
param name string
|
|
8
|
+
|
|
9
|
+
@description('Location')
|
|
10
|
+
param location string
|
|
11
|
+
|
|
12
|
+
@description('Tags')
|
|
13
|
+
param tags object = {}
|
|
14
|
+
|
|
15
|
+
@description('Log Analytics Workspace ID')
|
|
16
|
+
param logAnalyticsWorkspaceId string
|
|
17
|
+
|
|
18
|
+
@description('Application type')
|
|
19
|
+
@allowed(['web', 'other'])
|
|
20
|
+
param applicationType string = 'web'
|
|
21
|
+
|
|
22
|
+
@description('Retention in days')
|
|
23
|
+
@minValue(30)
|
|
24
|
+
@maxValue(730)
|
|
25
|
+
param retentionInDays int = 90
|
|
26
|
+
|
|
27
|
+
// ==============================================================================
|
|
28
|
+
// APPLICATION INSIGHTS
|
|
29
|
+
// ==============================================================================
|
|
30
|
+
|
|
31
|
+
resource appInsights 'Microsoft.Insights/components@2020-02-02' = {
|
|
32
|
+
name: name
|
|
33
|
+
location: location
|
|
34
|
+
tags: tags
|
|
35
|
+
kind: applicationType
|
|
36
|
+
properties: {
|
|
37
|
+
Application_Type: applicationType
|
|
38
|
+
WorkspaceResourceId: logAnalyticsWorkspaceId
|
|
39
|
+
IngestionMode: 'LogAnalytics'
|
|
40
|
+
publicNetworkAccessForIngestion: 'Enabled'
|
|
41
|
+
publicNetworkAccessForQuery: 'Enabled'
|
|
42
|
+
RetentionInDays: retentionInDays
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ==============================================================================
|
|
47
|
+
// OUTPUTS
|
|
48
|
+
// ==============================================================================
|
|
49
|
+
|
|
50
|
+
@description('Application Insights ID')
|
|
51
|
+
output id string = appInsights.id
|
|
52
|
+
|
|
53
|
+
@description('Application Insights name')
|
|
54
|
+
output name string = appInsights.name
|
|
55
|
+
|
|
56
|
+
@description('Instrumentation Key')
|
|
57
|
+
output instrumentationKey string = appInsights.properties.InstrumentationKey
|
|
58
|
+
|
|
59
|
+
@description('Connection String')
|
|
60
|
+
output connectionString string = appInsights.properties.ConnectionString
|
|
61
|
+
|
|
62
|
+
@description('App ID')
|
|
63
|
+
output appId string = appInsights.properties.AppId
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// ==============================================================================
|
|
2
|
+
// MORPH-SPEC - App Service
|
|
3
|
+
// Azure App Service with Free F1 tier support
|
|
4
|
+
// ==============================================================================
|
|
5
|
+
|
|
6
|
+
@description('App Service name')
|
|
7
|
+
param name string
|
|
8
|
+
|
|
9
|
+
@description('Location')
|
|
10
|
+
param location string
|
|
11
|
+
|
|
12
|
+
@description('Tags')
|
|
13
|
+
param tags object = {}
|
|
14
|
+
|
|
15
|
+
@description('App Service Plan SKU (F1, B1, S1, P1v2)')
|
|
16
|
+
@allowed(['F1', 'B1', 'S1', 'P1v2', 'P2v2'])
|
|
17
|
+
param sku string = 'F1'
|
|
18
|
+
|
|
19
|
+
@description('App Insights connection string')
|
|
20
|
+
param appInsightsConnectionString string = ''
|
|
21
|
+
|
|
22
|
+
@description('.NET version')
|
|
23
|
+
@allowed(['v6.0', 'v7.0', 'v8.0'])
|
|
24
|
+
param dotnetVersion string = 'v8.0'
|
|
25
|
+
|
|
26
|
+
@description('Always On (not available on Free tier)')
|
|
27
|
+
param alwaysOn bool = false
|
|
28
|
+
|
|
29
|
+
@description('Environment variables')
|
|
30
|
+
param envVars object = {}
|
|
31
|
+
|
|
32
|
+
// ==============================================================================
|
|
33
|
+
// VARIABLES
|
|
34
|
+
// ==============================================================================
|
|
35
|
+
|
|
36
|
+
var skuTiers = {
|
|
37
|
+
F1: 'Free'
|
|
38
|
+
B1: 'Basic'
|
|
39
|
+
S1: 'Standard'
|
|
40
|
+
P1v2: 'PremiumV2'
|
|
41
|
+
P2v2: 'PremiumV2'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var planName = 'plan-${name}'
|
|
45
|
+
|
|
46
|
+
// Merge default env vars with custom ones
|
|
47
|
+
var defaultEnvVars = {
|
|
48
|
+
ASPNETCORE_ENVIRONMENT: 'Production'
|
|
49
|
+
APPLICATIONINSIGHTS_CONNECTION_STRING: appInsightsConnectionString
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
var mergedEnvVars = union(defaultEnvVars, envVars)
|
|
53
|
+
|
|
54
|
+
// ==============================================================================
|
|
55
|
+
// APP SERVICE PLAN
|
|
56
|
+
// ==============================================================================
|
|
57
|
+
|
|
58
|
+
resource appServicePlan 'Microsoft.Web/serverfarms@2022-09-01' = {
|
|
59
|
+
name: planName
|
|
60
|
+
location: location
|
|
61
|
+
tags: tags
|
|
62
|
+
sku: {
|
|
63
|
+
name: sku
|
|
64
|
+
tier: skuTiers[sku]
|
|
65
|
+
}
|
|
66
|
+
kind: 'linux'
|
|
67
|
+
properties: {
|
|
68
|
+
reserved: true // Required for Linux
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ==============================================================================
|
|
73
|
+
// APP SERVICE
|
|
74
|
+
// ==============================================================================
|
|
75
|
+
|
|
76
|
+
resource appService 'Microsoft.Web/sites@2022-09-01' = {
|
|
77
|
+
name: name
|
|
78
|
+
location: location
|
|
79
|
+
tags: tags
|
|
80
|
+
kind: 'app,linux'
|
|
81
|
+
identity: {
|
|
82
|
+
type: 'SystemAssigned'
|
|
83
|
+
}
|
|
84
|
+
properties: {
|
|
85
|
+
serverFarmId: appServicePlan.id
|
|
86
|
+
httpsOnly: true
|
|
87
|
+
siteConfig: {
|
|
88
|
+
linuxFxVersion: 'DOTNETCORE|${dotnetVersion}'
|
|
89
|
+
alwaysOn: alwaysOn
|
|
90
|
+
minTlsVersion: '1.2'
|
|
91
|
+
ftpsState: 'Disabled'
|
|
92
|
+
http20Enabled: true
|
|
93
|
+
healthCheckPath: '/health'
|
|
94
|
+
appSettings: [for key in objectKeys(mergedEnvVars): {
|
|
95
|
+
name: key
|
|
96
|
+
value: mergedEnvVars[key]
|
|
97
|
+
}]
|
|
98
|
+
cors: {
|
|
99
|
+
allowedOrigins: [
|
|
100
|
+
'https://portal.azure.com'
|
|
101
|
+
]
|
|
102
|
+
supportCredentials: false
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
clientAffinityEnabled: false // Recommended for stateless apps
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ==============================================================================
|
|
110
|
+
// DEPLOYMENT SLOT (Only for non-Free tiers)
|
|
111
|
+
// ==============================================================================
|
|
112
|
+
|
|
113
|
+
resource stagingSlot 'Microsoft.Web/sites/slots@2022-09-01' = if (sku != 'F1') {
|
|
114
|
+
name: 'staging'
|
|
115
|
+
parent: appService
|
|
116
|
+
location: location
|
|
117
|
+
tags: tags
|
|
118
|
+
kind: 'app,linux'
|
|
119
|
+
identity: {
|
|
120
|
+
type: 'SystemAssigned'
|
|
121
|
+
}
|
|
122
|
+
properties: {
|
|
123
|
+
serverFarmId: appServicePlan.id
|
|
124
|
+
httpsOnly: true
|
|
125
|
+
siteConfig: {
|
|
126
|
+
linuxFxVersion: 'DOTNETCORE|${dotnetVersion}'
|
|
127
|
+
alwaysOn: alwaysOn
|
|
128
|
+
minTlsVersion: '1.2'
|
|
129
|
+
ftpsState: 'Disabled'
|
|
130
|
+
http20Enabled: true
|
|
131
|
+
healthCheckPath: '/health'
|
|
132
|
+
appSettings: [for key in objectKeys(mergedEnvVars): {
|
|
133
|
+
name: key
|
|
134
|
+
value: mergedEnvVars[key]
|
|
135
|
+
}]
|
|
136
|
+
}
|
|
137
|
+
clientAffinityEnabled: false
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ==============================================================================
|
|
142
|
+
// OUTPUTS
|
|
143
|
+
// ==============================================================================
|
|
144
|
+
|
|
145
|
+
@description('App Service ID')
|
|
146
|
+
output id string = appService.id
|
|
147
|
+
|
|
148
|
+
@description('App Service name')
|
|
149
|
+
output name string = appService.name
|
|
150
|
+
|
|
151
|
+
@description('App Service URL')
|
|
152
|
+
output url string = 'https://${appService.properties.defaultHostName}'
|
|
153
|
+
|
|
154
|
+
@description('App Service default hostname')
|
|
155
|
+
output defaultHostName string = appService.properties.defaultHostName
|
|
156
|
+
|
|
157
|
+
@description('App Service Plan ID')
|
|
158
|
+
output planId string = appServicePlan.id
|
|
159
|
+
|
|
160
|
+
@description('App Service Managed Identity Principal ID')
|
|
161
|
+
output principalId string = appService.identity.principalId
|
|
162
|
+
|
|
163
|
+
@description('Staging slot URL (if available)')
|
|
164
|
+
output stagingUrl string = sku != 'F1' ? 'https://${stagingSlot.properties.defaultHostName}' : ''
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// ==============================================================================
|
|
2
|
+
// MORPH-SPEC - Container Apps Environment
|
|
3
|
+
// Azure Container Apps managed environment
|
|
4
|
+
// ==============================================================================
|
|
5
|
+
|
|
6
|
+
@description('Environment name')
|
|
7
|
+
param name string
|
|
8
|
+
|
|
9
|
+
@description('Location')
|
|
10
|
+
param location string
|
|
11
|
+
|
|
12
|
+
@description('Tags')
|
|
13
|
+
param tags object = {}
|
|
14
|
+
|
|
15
|
+
@description('Log Analytics Workspace ID')
|
|
16
|
+
param logAnalyticsWorkspaceId string
|
|
17
|
+
|
|
18
|
+
// ==============================================================================
|
|
19
|
+
// CONTAINER APPS ENVIRONMENT
|
|
20
|
+
// ==============================================================================
|
|
21
|
+
|
|
22
|
+
resource containerAppEnv 'Microsoft.App/managedEnvironments@2023-05-01' = {
|
|
23
|
+
name: name
|
|
24
|
+
location: location
|
|
25
|
+
tags: tags
|
|
26
|
+
properties: {
|
|
27
|
+
appLogsConfiguration: {
|
|
28
|
+
destination: 'log-analytics'
|
|
29
|
+
logAnalyticsConfiguration: {
|
|
30
|
+
customerId: reference(logAnalyticsWorkspaceId, '2022-10-01').customerId
|
|
31
|
+
sharedKey: listKeys(logAnalyticsWorkspaceId, '2022-10-01').primarySharedKey
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
zoneRedundant: false
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ==============================================================================
|
|
39
|
+
// OUTPUTS
|
|
40
|
+
// ==============================================================================
|
|
41
|
+
|
|
42
|
+
@description('Container Apps Environment ID')
|
|
43
|
+
output id string = containerAppEnv.id
|
|
44
|
+
|
|
45
|
+
@description('Container Apps Environment name')
|
|
46
|
+
output name string = containerAppEnv.name
|
|
47
|
+
|
|
48
|
+
@description('Default domain')
|
|
49
|
+
output defaultDomain string = containerAppEnv.properties.defaultDomain
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// ==============================================================================
|
|
2
|
+
// MORPH-SPEC - Container App
|
|
3
|
+
// Azure Container Apps with ingress and auto-scaling
|
|
4
|
+
// ==============================================================================
|
|
5
|
+
|
|
6
|
+
@description('App name')
|
|
7
|
+
param name string
|
|
8
|
+
|
|
9
|
+
@description('Location')
|
|
10
|
+
param location string
|
|
11
|
+
|
|
12
|
+
@description('Tags')
|
|
13
|
+
param tags object = {}
|
|
14
|
+
|
|
15
|
+
@description('Container App Environment ID')
|
|
16
|
+
param environmentId string
|
|
17
|
+
|
|
18
|
+
@description('Container image')
|
|
19
|
+
param containerImage string
|
|
20
|
+
|
|
21
|
+
@description('App Insights connection string')
|
|
22
|
+
param appInsightsConnectionString string = ''
|
|
23
|
+
|
|
24
|
+
@description('CPU cores (0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0)')
|
|
25
|
+
param cpu string = '0.25'
|
|
26
|
+
|
|
27
|
+
@description('Memory (0.5Gi, 1Gi, 1.5Gi, 2Gi, 3Gi, 4Gi)')
|
|
28
|
+
param memory string = '0.5Gi'
|
|
29
|
+
|
|
30
|
+
@description('Minimum replicas (0 = scale to zero)')
|
|
31
|
+
param minReplicas int = 0
|
|
32
|
+
|
|
33
|
+
@description('Maximum replicas')
|
|
34
|
+
param maxReplicas int = 3
|
|
35
|
+
|
|
36
|
+
@description('Target port')
|
|
37
|
+
param targetPort int = 8080
|
|
38
|
+
|
|
39
|
+
@description('Environment variables')
|
|
40
|
+
param envVars array = []
|
|
41
|
+
|
|
42
|
+
// ==============================================================================
|
|
43
|
+
// CONTAINER APP
|
|
44
|
+
// ==============================================================================
|
|
45
|
+
|
|
46
|
+
var secrets = appInsightsConnectionString != '' ? [
|
|
47
|
+
{
|
|
48
|
+
name: 'appinsights-connection-string'
|
|
49
|
+
value: appInsightsConnectionString
|
|
50
|
+
}
|
|
51
|
+
] : []
|
|
52
|
+
|
|
53
|
+
var defaultEnvVars = appInsightsConnectionString != '' ? [
|
|
54
|
+
{
|
|
55
|
+
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
|
|
56
|
+
secretRef: 'appinsights-connection-string'
|
|
57
|
+
}
|
|
58
|
+
{
|
|
59
|
+
name: 'ASPNETCORE_ENVIRONMENT'
|
|
60
|
+
value: 'Production'
|
|
61
|
+
}
|
|
62
|
+
] : [
|
|
63
|
+
{
|
|
64
|
+
name: 'ASPNETCORE_ENVIRONMENT'
|
|
65
|
+
value: 'Production'
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
resource containerApp 'Microsoft.App/containerApps@2023-05-01' = {
|
|
70
|
+
name: name
|
|
71
|
+
location: location
|
|
72
|
+
tags: tags
|
|
73
|
+
properties: {
|
|
74
|
+
managedEnvironmentId: environmentId
|
|
75
|
+
configuration: {
|
|
76
|
+
ingress: {
|
|
77
|
+
external: true
|
|
78
|
+
targetPort: targetPort
|
|
79
|
+
transport: 'http'
|
|
80
|
+
allowInsecure: false
|
|
81
|
+
traffic: [
|
|
82
|
+
{
|
|
83
|
+
latestRevision: true
|
|
84
|
+
weight: 100
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
secrets: secrets
|
|
89
|
+
}
|
|
90
|
+
template: {
|
|
91
|
+
containers: [
|
|
92
|
+
{
|
|
93
|
+
name: name
|
|
94
|
+
image: containerImage
|
|
95
|
+
resources: {
|
|
96
|
+
cpu: json(cpu)
|
|
97
|
+
memory: memory
|
|
98
|
+
}
|
|
99
|
+
env: concat(defaultEnvVars, envVars)
|
|
100
|
+
probes: [
|
|
101
|
+
{
|
|
102
|
+
type: 'Liveness'
|
|
103
|
+
httpGet: {
|
|
104
|
+
path: '/health'
|
|
105
|
+
port: targetPort
|
|
106
|
+
}
|
|
107
|
+
initialDelaySeconds: 10
|
|
108
|
+
periodSeconds: 30
|
|
109
|
+
failureThreshold: 3
|
|
110
|
+
}
|
|
111
|
+
{
|
|
112
|
+
type: 'Readiness'
|
|
113
|
+
httpGet: {
|
|
114
|
+
path: '/health/ready'
|
|
115
|
+
port: targetPort
|
|
116
|
+
}
|
|
117
|
+
initialDelaySeconds: 5
|
|
118
|
+
periodSeconds: 10
|
|
119
|
+
failureThreshold: 3
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
scale: {
|
|
125
|
+
minReplicas: minReplicas
|
|
126
|
+
maxReplicas: maxReplicas
|
|
127
|
+
rules: [
|
|
128
|
+
{
|
|
129
|
+
name: 'http-scale'
|
|
130
|
+
http: {
|
|
131
|
+
metadata: {
|
|
132
|
+
concurrentRequests: '100'
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ==============================================================================
|
|
143
|
+
// OUTPUTS
|
|
144
|
+
// ==============================================================================
|
|
145
|
+
|
|
146
|
+
@description('Container App ID')
|
|
147
|
+
output id string = containerApp.id
|
|
148
|
+
|
|
149
|
+
@description('Container App name')
|
|
150
|
+
output name string = containerApp.name
|
|
151
|
+
|
|
152
|
+
@description('Container App URL')
|
|
153
|
+
output url string = 'https://${containerApp.properties.configuration.ingress.fqdn}'
|
|
154
|
+
|
|
155
|
+
@description('Container App FQDN')
|
|
156
|
+
output fqdn string = containerApp.properties.configuration.ingress.fqdn
|