@polymorphism-tech/morph-spec 1.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/README.md +279 -0
- package/bin/morph-spec.js +53 -0
- package/content/.claude/commands/morph-apply.md +66 -0
- package/content/.claude/commands/morph-archive.md +79 -0
- package/content/.claude/commands/morph-costs.md +206 -0
- package/content/.claude/commands/morph-infra.md +209 -0
- package/content/.claude/commands/morph-proposal.md +60 -0
- package/content/.claude/commands/morph-status.md +71 -0
- package/content/.claude/settings.local.json +15 -0
- package/content/.claude/skills/infra/bicep-architect.md +419 -0
- package/content/.claude/skills/infra/container-specialist.md +437 -0
- package/content/.claude/skills/infra/devops-engineer.md +405 -0
- package/content/.claude/skills/integrations/asaas-financial.md +333 -0
- package/content/.claude/skills/integrations/azure-identity.md +309 -0
- package/content/.claude/skills/integrations/clerk-auth.md +290 -0
- package/content/.claude/skills/specialists/azure-architect.md +142 -0
- package/content/.claude/skills/specialists/cost-guardian.md +110 -0
- package/content/.claude/skills/specialists/ef-modeler.md +200 -0
- package/content/.claude/skills/specialists/hangfire-orchestrator.md +245 -0
- package/content/.claude/skills/specialists/ms-agent-expert.md +209 -0
- package/content/.claude/skills/specialists/po-pm-advisor.md +197 -0
- package/content/.claude/skills/specialists/standards-architect.md +78 -0
- package/content/.claude/skills/specialists/ui-ux-designer.md +325 -0
- package/content/.claude/skills/stacks/dotnet-blazor.md +352 -0
- package/content/.claude/skills/stacks/dotnet-nextjs.md +402 -0
- package/content/.claude/skills/stacks/shopify.md +445 -0
- package/content/.morph/archive/.gitkeep +25 -0
- package/content/.morph/config/agents.json +149 -0
- package/content/.morph/config/config.template.json +96 -0
- package/content/.morph/examples/api-nextjs/README.md +241 -0
- package/content/.morph/examples/api-nextjs/contracts.ts +307 -0
- package/content/.morph/examples/api-nextjs/spec.md +399 -0
- package/content/.morph/examples/api-nextjs/tasks.md +168 -0
- package/content/.morph/examples/micro-saas/README.md +125 -0
- package/content/.morph/examples/micro-saas/contracts.cs +358 -0
- package/content/.morph/examples/micro-saas/decisions.md +246 -0
- package/content/.morph/examples/micro-saas/spec.md +236 -0
- package/content/.morph/examples/micro-saas/tasks.md +150 -0
- package/content/.morph/examples/multi-agent/README.md +309 -0
- package/content/.morph/examples/multi-agent/contracts.cs +433 -0
- package/content/.morph/examples/multi-agent/spec.md +479 -0
- package/content/.morph/examples/multi-agent/tasks.md +185 -0
- package/content/.morph/features/.gitkeep +25 -0
- package/content/.morph/project.md +159 -0
- package/content/.morph/specs/.gitkeep +20 -0
- package/content/.morph/standards/architecture.md +190 -0
- package/content/.morph/standards/azure.md +184 -0
- package/content/.morph/standards/coding.md +342 -0
- package/content/.morph/templates/agent.cs +172 -0
- package/content/.morph/templates/component.razor +239 -0
- package/content/.morph/templates/contracts.cs +217 -0
- package/content/.morph/templates/decisions.md +106 -0
- package/content/.morph/templates/infra/app-insights.bicep +63 -0
- package/content/.morph/templates/infra/container-app-env.bicep +49 -0
- package/content/.morph/templates/infra/container-app.bicep +156 -0
- package/content/.morph/templates/infra/key-vault.bicep +91 -0
- package/content/.morph/templates/infra/main.bicep +155 -0
- package/content/.morph/templates/infra/parameters.dev.json +23 -0
- package/content/.morph/templates/infra/parameters.prod.json +23 -0
- package/content/.morph/templates/infra/sql-database.bicep +103 -0
- package/content/.morph/templates/infra/storage.bicep +106 -0
- package/content/.morph/templates/integrations/asaas-client.cs +387 -0
- package/content/.morph/templates/integrations/asaas-webhook.cs +351 -0
- package/content/.morph/templates/integrations/azure-identity-config.cs +288 -0
- package/content/.morph/templates/integrations/clerk-config.cs +258 -0
- package/content/.morph/templates/job.cs +171 -0
- package/content/.morph/templates/migration.cs +83 -0
- package/content/.morph/templates/proposal.md +155 -0
- package/content/.morph/templates/recap.md +105 -0
- package/content/.morph/templates/repository.cs +141 -0
- package/content/.morph/templates/saas/subscription.cs +347 -0
- package/content/.morph/templates/saas/tenant.cs +338 -0
- package/content/.morph/templates/service.cs +139 -0
- package/content/.morph/templates/spec.md +147 -0
- package/content/.morph/templates/tasks.md +235 -0
- package/content/.morph/templates/test.cs +239 -0
- package/content/CLAUDE.md +318 -0
- package/package.json +50 -0
- package/src/commands/doctor.js +132 -0
- package/src/commands/init.js +121 -0
- package/src/commands/update.js +84 -0
- package/src/utils/file-copier.js +50 -0
- package/src/utils/logger.js +32 -0
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
# DevOps Engineer
|
|
2
|
+
|
|
3
|
+
Especialista em CI/CD, pipelines e automação de deploy.
|
|
4
|
+
|
|
5
|
+
## Responsabilidades
|
|
6
|
+
|
|
7
|
+
1. **Criar pipelines** de CI/CD para build e deploy
|
|
8
|
+
2. **Automatizar releases** para múltiplos ambientes
|
|
9
|
+
3. **Configurar testes** automatizados no pipeline
|
|
10
|
+
4. **Gerenciar ambientes** e variáveis
|
|
11
|
+
|
|
12
|
+
## Triggers
|
|
13
|
+
|
|
14
|
+
Keywords: `pipeline`, `ci/cd`, `deploy`, `release`, `azure devops`, `github actions`, `build`, `automation`
|
|
15
|
+
|
|
16
|
+
## Azure Pipelines (Azure DevOps)
|
|
17
|
+
|
|
18
|
+
### Pipeline YAML Completo
|
|
19
|
+
|
|
20
|
+
```yaml
|
|
21
|
+
# azure-pipelines.yml
|
|
22
|
+
trigger:
|
|
23
|
+
branches:
|
|
24
|
+
include:
|
|
25
|
+
- main
|
|
26
|
+
- develop
|
|
27
|
+
paths:
|
|
28
|
+
exclude:
|
|
29
|
+
- '**/*.md'
|
|
30
|
+
- '.gitignore'
|
|
31
|
+
|
|
32
|
+
pr:
|
|
33
|
+
branches:
|
|
34
|
+
include:
|
|
35
|
+
- main
|
|
36
|
+
- develop
|
|
37
|
+
|
|
38
|
+
variables:
|
|
39
|
+
buildConfiguration: 'Release'
|
|
40
|
+
dotnetVersion: '9.0.x'
|
|
41
|
+
azureSubscription: 'Azure-Service-Connection'
|
|
42
|
+
|
|
43
|
+
stages:
|
|
44
|
+
# Build Stage
|
|
45
|
+
- stage: Build
|
|
46
|
+
displayName: 'Build & Test'
|
|
47
|
+
jobs:
|
|
48
|
+
- job: BuildJob
|
|
49
|
+
displayName: 'Build .NET App'
|
|
50
|
+
pool:
|
|
51
|
+
vmImage: 'ubuntu-latest'
|
|
52
|
+
steps:
|
|
53
|
+
- task: UseDotNet@2
|
|
54
|
+
displayName: 'Install .NET SDK'
|
|
55
|
+
inputs:
|
|
56
|
+
version: '$(dotnetVersion)'
|
|
57
|
+
|
|
58
|
+
- task: DotNetCoreCLI@2
|
|
59
|
+
displayName: 'Restore packages'
|
|
60
|
+
inputs:
|
|
61
|
+
command: 'restore'
|
|
62
|
+
projects: '**/*.csproj'
|
|
63
|
+
|
|
64
|
+
- task: DotNetCoreCLI@2
|
|
65
|
+
displayName: 'Build'
|
|
66
|
+
inputs:
|
|
67
|
+
command: 'build'
|
|
68
|
+
projects: '**/*.csproj'
|
|
69
|
+
arguments: '--configuration $(buildConfiguration) --no-restore'
|
|
70
|
+
|
|
71
|
+
- task: DotNetCoreCLI@2
|
|
72
|
+
displayName: 'Run Tests'
|
|
73
|
+
inputs:
|
|
74
|
+
command: 'test'
|
|
75
|
+
projects: '**/tests/**/*.csproj'
|
|
76
|
+
arguments: '--configuration $(buildConfiguration) --collect:"XPlat Code Coverage"'
|
|
77
|
+
|
|
78
|
+
- task: PublishCodeCoverageResults@1
|
|
79
|
+
displayName: 'Publish Coverage'
|
|
80
|
+
inputs:
|
|
81
|
+
codeCoverageTool: 'Cobertura'
|
|
82
|
+
summaryFileLocation: '$(Agent.TempDirectory)/**/coverage.cobertura.xml'
|
|
83
|
+
|
|
84
|
+
- task: DotNetCoreCLI@2
|
|
85
|
+
displayName: 'Publish'
|
|
86
|
+
inputs:
|
|
87
|
+
command: 'publish'
|
|
88
|
+
publishWebProjects: true
|
|
89
|
+
arguments: '--configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)'
|
|
90
|
+
|
|
91
|
+
- task: PublishBuildArtifacts@1
|
|
92
|
+
displayName: 'Publish Artifacts'
|
|
93
|
+
inputs:
|
|
94
|
+
pathToPublish: '$(Build.ArtifactStagingDirectory)'
|
|
95
|
+
artifactName: 'drop'
|
|
96
|
+
|
|
97
|
+
# Deploy to Dev
|
|
98
|
+
- stage: DeployDev
|
|
99
|
+
displayName: 'Deploy to Dev'
|
|
100
|
+
dependsOn: Build
|
|
101
|
+
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/develop'))
|
|
102
|
+
jobs:
|
|
103
|
+
- deployment: DeployToDev
|
|
104
|
+
displayName: 'Deploy to Development'
|
|
105
|
+
environment: 'development'
|
|
106
|
+
pool:
|
|
107
|
+
vmImage: 'ubuntu-latest'
|
|
108
|
+
strategy:
|
|
109
|
+
runOnce:
|
|
110
|
+
deploy:
|
|
111
|
+
steps:
|
|
112
|
+
- task: AzureWebApp@1
|
|
113
|
+
displayName: 'Deploy to Container App'
|
|
114
|
+
inputs:
|
|
115
|
+
azureSubscription: '$(azureSubscription)'
|
|
116
|
+
appType: 'webAppContainer'
|
|
117
|
+
appName: 'myapp-dev'
|
|
118
|
+
deployToSlotOrASE: false
|
|
119
|
+
|
|
120
|
+
# Deploy to Production
|
|
121
|
+
- stage: DeployProd
|
|
122
|
+
displayName: 'Deploy to Production'
|
|
123
|
+
dependsOn: Build
|
|
124
|
+
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
|
|
125
|
+
jobs:
|
|
126
|
+
- deployment: DeployToProd
|
|
127
|
+
displayName: 'Deploy to Production'
|
|
128
|
+
environment: 'production'
|
|
129
|
+
pool:
|
|
130
|
+
vmImage: 'ubuntu-latest'
|
|
131
|
+
strategy:
|
|
132
|
+
runOnce:
|
|
133
|
+
deploy:
|
|
134
|
+
steps:
|
|
135
|
+
- task: AzureWebApp@1
|
|
136
|
+
displayName: 'Deploy to Container App'
|
|
137
|
+
inputs:
|
|
138
|
+
azureSubscription: '$(azureSubscription)'
|
|
139
|
+
appType: 'webAppContainer'
|
|
140
|
+
appName: 'myapp-prod'
|
|
141
|
+
deployToSlotOrASE: true
|
|
142
|
+
slotName: 'staging'
|
|
143
|
+
|
|
144
|
+
- task: AzureAppServiceManage@0
|
|
145
|
+
displayName: 'Swap Slots'
|
|
146
|
+
inputs:
|
|
147
|
+
azureSubscription: '$(azureSubscription)'
|
|
148
|
+
action: 'Swap Slots'
|
|
149
|
+
webAppName: 'myapp-prod'
|
|
150
|
+
sourceSlot: 'staging'
|
|
151
|
+
targetSlot: 'production'
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Pipeline com Docker
|
|
155
|
+
|
|
156
|
+
```yaml
|
|
157
|
+
# azure-pipelines-docker.yml
|
|
158
|
+
trigger:
|
|
159
|
+
- main
|
|
160
|
+
|
|
161
|
+
variables:
|
|
162
|
+
dockerRegistryServiceConnection: 'acr-connection'
|
|
163
|
+
containerRegistry: 'myacr.azurecr.io'
|
|
164
|
+
imageRepository: 'myapp'
|
|
165
|
+
dockerfilePath: 'Dockerfile'
|
|
166
|
+
tag: '$(Build.BuildId)'
|
|
167
|
+
|
|
168
|
+
stages:
|
|
169
|
+
- stage: Build
|
|
170
|
+
jobs:
|
|
171
|
+
- job: BuildAndPush
|
|
172
|
+
pool:
|
|
173
|
+
vmImage: 'ubuntu-latest'
|
|
174
|
+
steps:
|
|
175
|
+
- task: Docker@2
|
|
176
|
+
displayName: 'Build and push image'
|
|
177
|
+
inputs:
|
|
178
|
+
containerRegistry: '$(dockerRegistryServiceConnection)'
|
|
179
|
+
repository: '$(imageRepository)'
|
|
180
|
+
command: 'buildAndPush'
|
|
181
|
+
Dockerfile: '$(dockerfilePath)'
|
|
182
|
+
tags: |
|
|
183
|
+
$(tag)
|
|
184
|
+
latest
|
|
185
|
+
|
|
186
|
+
- stage: DeployDev
|
|
187
|
+
dependsOn: Build
|
|
188
|
+
jobs:
|
|
189
|
+
- deployment: Deploy
|
|
190
|
+
environment: 'development'
|
|
191
|
+
strategy:
|
|
192
|
+
runOnce:
|
|
193
|
+
deploy:
|
|
194
|
+
steps:
|
|
195
|
+
- task: AzureCLI@2
|
|
196
|
+
displayName: 'Update Container App'
|
|
197
|
+
inputs:
|
|
198
|
+
azureSubscription: 'Azure-Connection'
|
|
199
|
+
scriptType: 'bash'
|
|
200
|
+
scriptLocation: 'inlineScript'
|
|
201
|
+
inlineScript: |
|
|
202
|
+
az containerapp update \
|
|
203
|
+
--name myapp-dev \
|
|
204
|
+
--resource-group rg-myapp-dev \
|
|
205
|
+
--image $(containerRegistry)/$(imageRepository):$(tag)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## GitHub Actions
|
|
209
|
+
|
|
210
|
+
### Workflow Completo
|
|
211
|
+
|
|
212
|
+
```yaml
|
|
213
|
+
# .github/workflows/ci-cd.yml
|
|
214
|
+
name: CI/CD
|
|
215
|
+
|
|
216
|
+
on:
|
|
217
|
+
push:
|
|
218
|
+
branches: [main, develop]
|
|
219
|
+
pull_request:
|
|
220
|
+
branches: [main, develop]
|
|
221
|
+
|
|
222
|
+
env:
|
|
223
|
+
DOTNET_VERSION: '9.0.x'
|
|
224
|
+
REGISTRY: ghcr.io
|
|
225
|
+
IMAGE_NAME: ${{ github.repository }}
|
|
226
|
+
|
|
227
|
+
jobs:
|
|
228
|
+
build:
|
|
229
|
+
runs-on: ubuntu-latest
|
|
230
|
+
steps:
|
|
231
|
+
- uses: actions/checkout@v4
|
|
232
|
+
|
|
233
|
+
- name: Setup .NET
|
|
234
|
+
uses: actions/setup-dotnet@v4
|
|
235
|
+
with:
|
|
236
|
+
dotnet-version: ${{ env.DOTNET_VERSION }}
|
|
237
|
+
|
|
238
|
+
- name: Restore
|
|
239
|
+
run: dotnet restore
|
|
240
|
+
|
|
241
|
+
- name: Build
|
|
242
|
+
run: dotnet build --configuration Release --no-restore
|
|
243
|
+
|
|
244
|
+
- name: Test
|
|
245
|
+
run: dotnet test --configuration Release --no-build --verbosity normal
|
|
246
|
+
|
|
247
|
+
- name: Publish
|
|
248
|
+
run: dotnet publish src/Web/Web.csproj -c Release -o ./publish
|
|
249
|
+
|
|
250
|
+
- name: Upload artifact
|
|
251
|
+
uses: actions/upload-artifact@v4
|
|
252
|
+
with:
|
|
253
|
+
name: app
|
|
254
|
+
path: ./publish
|
|
255
|
+
|
|
256
|
+
docker:
|
|
257
|
+
needs: build
|
|
258
|
+
runs-on: ubuntu-latest
|
|
259
|
+
if: github.event_name == 'push'
|
|
260
|
+
permissions:
|
|
261
|
+
contents: read
|
|
262
|
+
packages: write
|
|
263
|
+
steps:
|
|
264
|
+
- uses: actions/checkout@v4
|
|
265
|
+
|
|
266
|
+
- name: Log in to Container Registry
|
|
267
|
+
uses: docker/login-action@v3
|
|
268
|
+
with:
|
|
269
|
+
registry: ${{ env.REGISTRY }}
|
|
270
|
+
username: ${{ github.actor }}
|
|
271
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
272
|
+
|
|
273
|
+
- name: Build and push
|
|
274
|
+
uses: docker/build-push-action@v5
|
|
275
|
+
with:
|
|
276
|
+
context: .
|
|
277
|
+
push: true
|
|
278
|
+
tags: |
|
|
279
|
+
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
|
|
280
|
+
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
|
281
|
+
|
|
282
|
+
deploy-dev:
|
|
283
|
+
needs: docker
|
|
284
|
+
runs-on: ubuntu-latest
|
|
285
|
+
if: github.ref == 'refs/heads/develop'
|
|
286
|
+
environment: development
|
|
287
|
+
steps:
|
|
288
|
+
- name: Azure Login
|
|
289
|
+
uses: azure/login@v2
|
|
290
|
+
with:
|
|
291
|
+
creds: ${{ secrets.AZURE_CREDENTIALS }}
|
|
292
|
+
|
|
293
|
+
- name: Deploy to Container App
|
|
294
|
+
uses: azure/container-apps-deploy-action@v1
|
|
295
|
+
with:
|
|
296
|
+
resourceGroup: rg-myapp-dev
|
|
297
|
+
containerAppName: myapp-dev
|
|
298
|
+
imageToDeploy: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
|
|
299
|
+
|
|
300
|
+
deploy-prod:
|
|
301
|
+
needs: docker
|
|
302
|
+
runs-on: ubuntu-latest
|
|
303
|
+
if: github.ref == 'refs/heads/main'
|
|
304
|
+
environment: production
|
|
305
|
+
steps:
|
|
306
|
+
- name: Azure Login
|
|
307
|
+
uses: azure/login@v2
|
|
308
|
+
with:
|
|
309
|
+
creds: ${{ secrets.AZURE_CREDENTIALS }}
|
|
310
|
+
|
|
311
|
+
- name: Deploy to Container App
|
|
312
|
+
uses: azure/container-apps-deploy-action@v1
|
|
313
|
+
with:
|
|
314
|
+
resourceGroup: rg-myapp-prod
|
|
315
|
+
containerAppName: myapp-prod
|
|
316
|
+
imageToDeploy: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## Dockerfile
|
|
320
|
+
|
|
321
|
+
```dockerfile
|
|
322
|
+
# Dockerfile
|
|
323
|
+
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
|
|
324
|
+
WORKDIR /app
|
|
325
|
+
EXPOSE 8080
|
|
326
|
+
|
|
327
|
+
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
|
|
328
|
+
WORKDIR /src
|
|
329
|
+
|
|
330
|
+
# Copy csproj and restore
|
|
331
|
+
COPY ["src/Web/Web.csproj", "src/Web/"]
|
|
332
|
+
COPY ["src/Application/Application.csproj", "src/Application/"]
|
|
333
|
+
COPY ["src/Domain/Domain.csproj", "src/Domain/"]
|
|
334
|
+
COPY ["src/Infrastructure/Infrastructure.csproj", "src/Infrastructure/"]
|
|
335
|
+
RUN dotnet restore "src/Web/Web.csproj"
|
|
336
|
+
|
|
337
|
+
# Copy everything and build
|
|
338
|
+
COPY . .
|
|
339
|
+
RUN dotnet build "src/Web/Web.csproj" -c Release -o /app/build
|
|
340
|
+
|
|
341
|
+
FROM build AS publish
|
|
342
|
+
RUN dotnet publish "src/Web/Web.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
|
343
|
+
|
|
344
|
+
FROM base AS final
|
|
345
|
+
WORKDIR /app
|
|
346
|
+
COPY --from=publish /app/publish .
|
|
347
|
+
|
|
348
|
+
# Non-root user
|
|
349
|
+
USER $APP_UID
|
|
350
|
+
|
|
351
|
+
ENTRYPOINT ["dotnet", "Web.dll"]
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## Variáveis e Secrets
|
|
355
|
+
|
|
356
|
+
### Azure DevOps
|
|
357
|
+
|
|
358
|
+
```yaml
|
|
359
|
+
# Variable Groups
|
|
360
|
+
variables:
|
|
361
|
+
- group: 'MyApp-Dev-Variables' # Link to variable group
|
|
362
|
+
|
|
363
|
+
# Pipeline variables with secrets
|
|
364
|
+
variables:
|
|
365
|
+
- name: 'SqlPassword'
|
|
366
|
+
value: '$(SQL_PASSWORD)' # From variable group or pipeline variables
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### GitHub Actions
|
|
370
|
+
|
|
371
|
+
```yaml
|
|
372
|
+
# Using secrets
|
|
373
|
+
env:
|
|
374
|
+
CONNECTION_STRING: ${{ secrets.CONNECTION_STRING }}
|
|
375
|
+
|
|
376
|
+
# Using environments
|
|
377
|
+
jobs:
|
|
378
|
+
deploy:
|
|
379
|
+
environment: production
|
|
380
|
+
env:
|
|
381
|
+
API_KEY: ${{ secrets.API_KEY }} # Environment-specific secret
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
## Documentação de Referência
|
|
385
|
+
|
|
386
|
+
- [Azure Pipelines](https://learn.microsoft.com/en-us/azure/devops/pipelines/)
|
|
387
|
+
- [GitHub Actions](https://docs.github.com/en/actions)
|
|
388
|
+
- [YAML Schema](https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/)
|
|
389
|
+
- [Container Apps Deploy](https://learn.microsoft.com/en-us/azure/container-apps/github-actions)
|
|
390
|
+
|
|
391
|
+
## Checklist de Pipeline
|
|
392
|
+
|
|
393
|
+
- [ ] Trigger configurado (branches, paths)
|
|
394
|
+
- [ ] Build com restore, build, test
|
|
395
|
+
- [ ] Publicação de artifacts
|
|
396
|
+
- [ ] Code coverage publicado
|
|
397
|
+
- [ ] Deploy para dev automático
|
|
398
|
+
- [ ] Deploy para prod com approval
|
|
399
|
+
- [ ] Secrets no Key Vault ou variable groups
|
|
400
|
+
- [ ] Dockerfile otimizado (multi-stage)
|
|
401
|
+
- [ ] Health check após deploy
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
*MORPH-SPEC by Polymorphism Tech*
|