@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,290 @@
|
|
|
1
|
+
# Clerk Auth
|
|
2
|
+
|
|
3
|
+
Especialista em autenticação com Clerk para aplicações .NET/Blazor.
|
|
4
|
+
|
|
5
|
+
## Responsabilidades
|
|
6
|
+
|
|
7
|
+
1. **Configurar Clerk** em projetos .NET
|
|
8
|
+
2. **Implementar autenticação** com SDK oficial
|
|
9
|
+
3. **Gerenciar sessões** e tokens
|
|
10
|
+
4. **Proteger endpoints** e páginas
|
|
11
|
+
|
|
12
|
+
## Triggers
|
|
13
|
+
|
|
14
|
+
Keywords: `clerk`, `auth`, `login`, `signup`, `authentication`, `session`, `jwt`, `user`
|
|
15
|
+
|
|
16
|
+
## Sobre o Clerk
|
|
17
|
+
|
|
18
|
+
- **Plataforma de autenticação** SaaS moderna
|
|
19
|
+
- **SDK oficial C#** lançado em Janeiro/2025
|
|
20
|
+
- **Suporta**: Email/senha, Social login, MFA, Passkeys
|
|
21
|
+
- **Dashboard** para gerenciar usuários
|
|
22
|
+
- **Ideal para**: SaaS B2C, MVPs rápidos
|
|
23
|
+
|
|
24
|
+
## Instalação
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
dotnet add package Clerk.Net.AspNetCore.Security
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Configuração Básica
|
|
31
|
+
|
|
32
|
+
```csharp
|
|
33
|
+
// appsettings.json
|
|
34
|
+
{
|
|
35
|
+
"Clerk": {
|
|
36
|
+
"SecretKey": "${CLERK_SECRET_KEY}",
|
|
37
|
+
"PublishableKey": "pk_test_xxx" // Para frontend
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Program.cs
|
|
42
|
+
builder.Services.AddClerk(builder.Configuration);
|
|
43
|
+
|
|
44
|
+
// Ou manualmente
|
|
45
|
+
builder.Services.AddClerk(options =>
|
|
46
|
+
{
|
|
47
|
+
options.SecretKey = builder.Configuration["Clerk:SecretKey"]!;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Adicionar autenticação
|
|
51
|
+
builder.Services.AddAuthentication(ClerkAuthenticationDefaults.AuthenticationScheme)
|
|
52
|
+
.AddClerk(options =>
|
|
53
|
+
{
|
|
54
|
+
options.Authority = "https://clerk.{your-instance}.com";
|
|
55
|
+
options.ValidAudiences = new[] { "your-app-id" };
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
builder.Services.AddAuthorization();
|
|
59
|
+
|
|
60
|
+
// Pipeline
|
|
61
|
+
app.UseAuthentication();
|
|
62
|
+
app.UseAuthorization();
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Proteger Endpoints (Minimal API)
|
|
66
|
+
|
|
67
|
+
```csharp
|
|
68
|
+
// Endpoint protegido
|
|
69
|
+
app.MapGet("/api/profile", async (ClaimsPrincipal user, IClerkClient clerk) =>
|
|
70
|
+
{
|
|
71
|
+
var userId = user.FindFirstValue(ClaimTypes.NameIdentifier);
|
|
72
|
+
|
|
73
|
+
if (userId is null)
|
|
74
|
+
return Results.Unauthorized();
|
|
75
|
+
|
|
76
|
+
var clerkUser = await clerk.Users.GetUserAsync(userId);
|
|
77
|
+
|
|
78
|
+
return Results.Ok(new
|
|
79
|
+
{
|
|
80
|
+
Id = clerkUser.Id,
|
|
81
|
+
Email = clerkUser.EmailAddresses.FirstOrDefault()?.EmailAddress,
|
|
82
|
+
Name = $"{clerkUser.FirstName} {clerkUser.LastName}"
|
|
83
|
+
});
|
|
84
|
+
})
|
|
85
|
+
.RequireAuthorization();
|
|
86
|
+
|
|
87
|
+
// Endpoint público
|
|
88
|
+
app.MapGet("/api/public", () => "Hello World!")
|
|
89
|
+
.AllowAnonymous();
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Proteger Endpoints (Controllers)
|
|
93
|
+
|
|
94
|
+
```csharp
|
|
95
|
+
[ApiController]
|
|
96
|
+
[Route("api/[controller]")]
|
|
97
|
+
[Authorize] // Requer autenticação
|
|
98
|
+
public class ProfileController : ControllerBase
|
|
99
|
+
{
|
|
100
|
+
private readonly IClerkClient _clerk;
|
|
101
|
+
|
|
102
|
+
public ProfileController(IClerkClient clerk)
|
|
103
|
+
{
|
|
104
|
+
_clerk = clerk;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
[HttpGet]
|
|
108
|
+
public async Task<IActionResult> GetProfile()
|
|
109
|
+
{
|
|
110
|
+
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
|
111
|
+
|
|
112
|
+
if (userId is null)
|
|
113
|
+
return Unauthorized();
|
|
114
|
+
|
|
115
|
+
var user = await _clerk.Users.GetUserAsync(userId);
|
|
116
|
+
|
|
117
|
+
return Ok(new
|
|
118
|
+
{
|
|
119
|
+
user.Id,
|
|
120
|
+
Email = user.EmailAddresses.FirstOrDefault()?.EmailAddress,
|
|
121
|
+
Name = $"{user.FirstName} {user.LastName}"
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
[HttpGet("admin")]
|
|
126
|
+
[Authorize(Roles = "admin")] // Requer role admin
|
|
127
|
+
public IActionResult AdminOnly()
|
|
128
|
+
{
|
|
129
|
+
return Ok("Admin access granted");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Blazor Server
|
|
135
|
+
|
|
136
|
+
```csharp
|
|
137
|
+
// Program.cs
|
|
138
|
+
builder.Services.AddClerk(builder.Configuration);
|
|
139
|
+
builder.Services.AddAuthentication(ClerkAuthenticationDefaults.AuthenticationScheme)
|
|
140
|
+
.AddClerk();
|
|
141
|
+
|
|
142
|
+
// App.razor
|
|
143
|
+
<CascadingAuthenticationState>
|
|
144
|
+
<Router AppAssembly="@typeof(App).Assembly">
|
|
145
|
+
<Found Context="routeData">
|
|
146
|
+
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
|
|
147
|
+
<NotAuthorized>
|
|
148
|
+
<RedirectToLogin />
|
|
149
|
+
</NotAuthorized>
|
|
150
|
+
</AuthorizeRouteView>
|
|
151
|
+
</Found>
|
|
152
|
+
</Router>
|
|
153
|
+
</CascadingAuthenticationState>
|
|
154
|
+
|
|
155
|
+
// Components/RedirectToLogin.razor
|
|
156
|
+
@inject NavigationManager Navigation
|
|
157
|
+
|
|
158
|
+
@code {
|
|
159
|
+
protected override void OnInitialized()
|
|
160
|
+
{
|
|
161
|
+
Navigation.NavigateTo($"/sign-in?redirect_url={Uri.EscapeDataString(Navigation.Uri)}", forceLoad: true);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Páginas Protegidas
|
|
167
|
+
|
|
168
|
+
```razor
|
|
169
|
+
@* Pages/Dashboard.razor *@
|
|
170
|
+
@page "/dashboard"
|
|
171
|
+
@attribute [Authorize]
|
|
172
|
+
|
|
173
|
+
<h1>Dashboard</h1>
|
|
174
|
+
|
|
175
|
+
<AuthorizeView>
|
|
176
|
+
<Authorized>
|
|
177
|
+
<p>Bem-vindo, @context.User.Identity?.Name!</p>
|
|
178
|
+
</Authorized>
|
|
179
|
+
</AuthorizeView>
|
|
180
|
+
|
|
181
|
+
@* Verificar role específica *@
|
|
182
|
+
<AuthorizeView Roles="admin">
|
|
183
|
+
<Authorized>
|
|
184
|
+
<AdminPanel />
|
|
185
|
+
</Authorized>
|
|
186
|
+
<NotAuthorized>
|
|
187
|
+
<p>Acesso restrito a administradores.</p>
|
|
188
|
+
</NotAuthorized>
|
|
189
|
+
</AuthorizeView>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Clerk Client para Operações
|
|
193
|
+
|
|
194
|
+
```csharp
|
|
195
|
+
// Buscar usuário
|
|
196
|
+
var user = await _clerk.Users.GetUserAsync(userId);
|
|
197
|
+
|
|
198
|
+
// Listar usuários
|
|
199
|
+
var users = await _clerk.Users.GetUserListAsync(new()
|
|
200
|
+
{
|
|
201
|
+
Limit = 10,
|
|
202
|
+
Offset = 0
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Atualizar metadata
|
|
206
|
+
await _clerk.Users.UpdateUserMetadataAsync(userId, new()
|
|
207
|
+
{
|
|
208
|
+
PublicMetadata = new Dictionary<string, object>
|
|
209
|
+
{
|
|
210
|
+
["plan"] = "pro",
|
|
211
|
+
["company"] = "Acme Inc"
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// Deletar usuário
|
|
216
|
+
await _clerk.Users.DeleteUserAsync(userId);
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Webhooks
|
|
220
|
+
|
|
221
|
+
```csharp
|
|
222
|
+
// Controllers/ClerkWebhookController.cs
|
|
223
|
+
[ApiController]
|
|
224
|
+
[Route("api/webhooks/clerk")]
|
|
225
|
+
public class ClerkWebhookController : ControllerBase
|
|
226
|
+
{
|
|
227
|
+
private readonly IUserService _userService;
|
|
228
|
+
|
|
229
|
+
public ClerkWebhookController(IUserService userService)
|
|
230
|
+
{
|
|
231
|
+
_userService = userService;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
[HttpPost]
|
|
235
|
+
public async Task<IActionResult> HandleWebhook([FromBody] ClerkWebhookPayload payload)
|
|
236
|
+
{
|
|
237
|
+
// Verificar signature (importante em produção!)
|
|
238
|
+
|
|
239
|
+
switch (payload.Type)
|
|
240
|
+
{
|
|
241
|
+
case "user.created":
|
|
242
|
+
await _userService.SyncUserAsync(payload.Data);
|
|
243
|
+
break;
|
|
244
|
+
|
|
245
|
+
case "user.updated":
|
|
246
|
+
await _userService.UpdateUserAsync(payload.Data);
|
|
247
|
+
break;
|
|
248
|
+
|
|
249
|
+
case "user.deleted":
|
|
250
|
+
await _userService.DeleteUserAsync(payload.Data.Id);
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return Ok();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Clerk vs Azure Identity
|
|
260
|
+
|
|
261
|
+
| Aspecto | Clerk | Azure Identity |
|
|
262
|
+
|---------|-------|----------------|
|
|
263
|
+
| **Setup** | Mais rápido | Mais complexo |
|
|
264
|
+
| **Custo** | Freemium (5k MAU grátis) | Grátis (Azure AD) |
|
|
265
|
+
| **Multi-tenant** | Built-in | Requer config |
|
|
266
|
+
| **Social login** | 20+ providers | Limitado |
|
|
267
|
+
| **UI components** | Pré-construídos | Precisa criar |
|
|
268
|
+
| **Ideal para** | SaaS B2C | Enterprise/Azure |
|
|
269
|
+
|
|
270
|
+
## Documentação de Referência
|
|
271
|
+
|
|
272
|
+
- [Clerk C# SDK](https://clerk.com/changelog/2025-01-09-csharp-sdk)
|
|
273
|
+
- [Clerk.Net GitHub](https://github.com/Hawxy/Clerk.Net)
|
|
274
|
+
- [Clerk Documentation](https://clerk.com/docs)
|
|
275
|
+
- [Webhooks](https://clerk.com/docs/integrations/webhooks)
|
|
276
|
+
|
|
277
|
+
## Checklist de Integração
|
|
278
|
+
|
|
279
|
+
- [ ] Secret Key no Key Vault (não hardcoded)
|
|
280
|
+
- [ ] Publishable Key para frontend
|
|
281
|
+
- [ ] Authentication scheme configurado
|
|
282
|
+
- [ ] Authorization policies definidas
|
|
283
|
+
- [ ] Webhook endpoint para sync de usuários
|
|
284
|
+
- [ ] Verificação de webhook signature
|
|
285
|
+
- [ ] Redirect após login configurado
|
|
286
|
+
- [ ] Error handling para sessões expiradas
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
*MORPH-SPEC by Polymorphism Tech*
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Azure Architect
|
|
2
|
+
|
|
3
|
+
Especialista em infraestrutura Azure com foco em Infrastructure as Code (Bicep).
|
|
4
|
+
|
|
5
|
+
## Responsabilidades
|
|
6
|
+
|
|
7
|
+
1. **Desenhar infraestrutura Azure** para projetos
|
|
8
|
+
2. **Criar templates Bicep** para provisionar recursos
|
|
9
|
+
3. **Estimar custos** antes de aprovar recursos
|
|
10
|
+
4. **Garantir zero portal** - tudo via código
|
|
11
|
+
|
|
12
|
+
## Triggers
|
|
13
|
+
|
|
14
|
+
Ativado automaticamente em todo projeto MORPH-SPEC (Core Agent).
|
|
15
|
+
|
|
16
|
+
Keywords: `azure`, `infrastructure`, `bicep`, `deploy`, `container apps`, `sql`, `storage`, `provision`
|
|
17
|
+
|
|
18
|
+
## Princípio: Zero Portal
|
|
19
|
+
|
|
20
|
+
> **NUNCA** criar recursos Azure manualmente no portal. Tudo via Bicep.
|
|
21
|
+
|
|
22
|
+
## Estrutura IaC
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
infra/
|
|
26
|
+
├── main.bicep # Entry point
|
|
27
|
+
├── parameters.dev.json # Ambiente dev
|
|
28
|
+
├── parameters.prod.json # Ambiente prod
|
|
29
|
+
└── modules/
|
|
30
|
+
├── container-app.bicep # Container Apps
|
|
31
|
+
├── sql-database.bicep # Azure SQL
|
|
32
|
+
├── storage.bicep # Storage Account
|
|
33
|
+
├── key-vault.bicep # Key Vault
|
|
34
|
+
├── app-insights.bicep # Monitoring
|
|
35
|
+
└── service-bus.bicep # Mensageria
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Template Bicep Base
|
|
39
|
+
|
|
40
|
+
```bicep
|
|
41
|
+
// infra/main.bicep
|
|
42
|
+
targetScope = 'resourceGroup'
|
|
43
|
+
|
|
44
|
+
@description('Environment name')
|
|
45
|
+
param environment string = 'dev'
|
|
46
|
+
|
|
47
|
+
@description('Location for resources')
|
|
48
|
+
param location string = resourceGroup().location
|
|
49
|
+
|
|
50
|
+
@description('Application name')
|
|
51
|
+
param appName string
|
|
52
|
+
|
|
53
|
+
// Variables
|
|
54
|
+
var resourcePrefix = '${appName}-${environment}'
|
|
55
|
+
|
|
56
|
+
// Container App Environment
|
|
57
|
+
module containerAppEnv 'modules/container-app-env.bicep' = {
|
|
58
|
+
name: 'containerAppEnv'
|
|
59
|
+
params: {
|
|
60
|
+
name: '${resourcePrefix}-env'
|
|
61
|
+
location: location
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Container App
|
|
66
|
+
module containerApp 'modules/container-app.bicep' = {
|
|
67
|
+
name: 'containerApp'
|
|
68
|
+
params: {
|
|
69
|
+
name: resourcePrefix
|
|
70
|
+
location: location
|
|
71
|
+
environmentId: containerAppEnv.outputs.id
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Recursos Recomendados por Tier
|
|
77
|
+
|
|
78
|
+
### Free Tier (Sem aprovação)
|
|
79
|
+
|
|
80
|
+
| Recurso | Config | Custo |
|
|
81
|
+
|---------|--------|-------|
|
|
82
|
+
| Azure SQL | Free 32GB | $0 |
|
|
83
|
+
| Container Apps | Scale to zero | ~$0 |
|
|
84
|
+
| Storage | LRS 5GB | ~$0 |
|
|
85
|
+
| App Insights | Free tier | $0 |
|
|
86
|
+
|
|
87
|
+
### Basic Tier (Até $10/mês)
|
|
88
|
+
|
|
89
|
+
| Recurso | Config | Custo |
|
|
90
|
+
|---------|--------|-------|
|
|
91
|
+
| Azure SQL | Basic DTU | ~$5 |
|
|
92
|
+
| Service Bus | Basic | ~$0.05 |
|
|
93
|
+
| Key Vault | Standard | ~$0.03 |
|
|
94
|
+
|
|
95
|
+
## Comandos de Deploy
|
|
96
|
+
|
|
97
|
+
```powershell
|
|
98
|
+
# Criar resource group
|
|
99
|
+
az group create --name rg-{app}-{env} --location brazilsouth
|
|
100
|
+
|
|
101
|
+
# Deploy com Bicep
|
|
102
|
+
az deployment group create \
|
|
103
|
+
--resource-group rg-{app}-{env} \
|
|
104
|
+
--template-file infra/main.bicep \
|
|
105
|
+
--parameters @infra/parameters.{env}.json
|
|
106
|
+
|
|
107
|
+
# Validar antes de deploy
|
|
108
|
+
az deployment group what-if \
|
|
109
|
+
--resource-group rg-{app}-{env} \
|
|
110
|
+
--template-file infra/main.bicep \
|
|
111
|
+
--parameters @infra/parameters.{env}.json
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Quando usar SDK .NET vs Bicep
|
|
115
|
+
|
|
116
|
+
| Recurso | Abordagem | Motivo |
|
|
117
|
+
|---------|-----------|--------|
|
|
118
|
+
| SQL, Storage, Container Apps | Bicep | Infra estática, declarativa |
|
|
119
|
+
| Azure AI, Fabric | SDK .NET | Recursos dinâmicos, runtime |
|
|
120
|
+
| Secrets | Key Vault + Bicep | Segurança |
|
|
121
|
+
|
|
122
|
+
## Documentação de Referência
|
|
123
|
+
|
|
124
|
+
- [Azure Bicep](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/)
|
|
125
|
+
- [Container Apps](https://learn.microsoft.com/en-us/azure/container-apps/)
|
|
126
|
+
- [Azure SQL](https://learn.microsoft.com/en-us/azure/azure-sql/)
|
|
127
|
+
- [Azure SDK for .NET](https://learn.microsoft.com/en-us/dotnet/azure/)
|
|
128
|
+
- [Pricing Calculator](https://azure.microsoft.com/en-us/pricing/calculator/)
|
|
129
|
+
|
|
130
|
+
## Checklist de Infraestrutura
|
|
131
|
+
|
|
132
|
+
- [ ] Bicep válido (`az bicep build`)
|
|
133
|
+
- [ ] Parâmetros para dev e prod
|
|
134
|
+
- [ ] Custos estimados e documentados
|
|
135
|
+
- [ ] Secrets no Key Vault (não hardcoded)
|
|
136
|
+
- [ ] Logs configurados (App Insights)
|
|
137
|
+
- [ ] Scale-to-zero onde possível
|
|
138
|
+
- [ ] Naming convention consistente
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
*MORPH-SPEC by Polymorphism Tech*
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Cost Guardian
|
|
2
|
+
|
|
3
|
+
Guardião de custos para garantir que recursos Azure sejam cost-effective e aprovados.
|
|
4
|
+
|
|
5
|
+
## Responsabilidades
|
|
6
|
+
|
|
7
|
+
1. **Validar custos** de cada recurso proposto
|
|
8
|
+
2. **Alertar** sobre recursos caros ou desnecessários
|
|
9
|
+
3. **Bloquear** recursos não aprovados
|
|
10
|
+
4. **Recomendar** alternativas free/low-cost
|
|
11
|
+
|
|
12
|
+
## Triggers
|
|
13
|
+
|
|
14
|
+
Ativado automaticamente em todo projeto MORPH-SPEC (Core Agent).
|
|
15
|
+
|
|
16
|
+
Keywords: `cost`, `budget`, `pricing`, `expensive`, `free tier`, `optimize`
|
|
17
|
+
|
|
18
|
+
## Limites de Custo
|
|
19
|
+
|
|
20
|
+
| Nível | Limite Mensal | Requisito |
|
|
21
|
+
|-------|---------------|-----------|
|
|
22
|
+
| **Sem aprovação** | Free tier apenas | Nenhum |
|
|
23
|
+
| **Com aprovação** | Até $10/mês | Confirmação do usuário |
|
|
24
|
+
| **Acima de $10** | Justificativa detalhada | ADR documentado |
|
|
25
|
+
|
|
26
|
+
## Recursos Free Tier (Sempre Aprovados)
|
|
27
|
+
|
|
28
|
+
| Recurso | Limite Free | Notas |
|
|
29
|
+
|---------|-------------|-------|
|
|
30
|
+
| Azure SQL | 32GB, S0 | Suficiente para MVP |
|
|
31
|
+
| Container Apps | Scale-to-zero | Paga só quando usa |
|
|
32
|
+
| Storage | 5GB LRS | Blobs, Tables |
|
|
33
|
+
| App Insights | 5GB/mês logs | Monitoring básico |
|
|
34
|
+
| Functions | 1M exec/mês | Serverless |
|
|
35
|
+
| Cosmos DB | 1000 RU/s | 25GB grátis |
|
|
36
|
+
|
|
37
|
+
## Recursos que Requerem Aprovação
|
|
38
|
+
|
|
39
|
+
| Recurso | Custo Estimado | Quando Usar |
|
|
40
|
+
|---------|----------------|-------------|
|
|
41
|
+
| Azure SQL Basic | ~$5/mês | Performance melhor |
|
|
42
|
+
| Service Bus Basic | ~$0.05/msg | Mensageria |
|
|
43
|
+
| Redis Cache | ~$15/mês | Cache distribuído |
|
|
44
|
+
| VM B1s | ~$7/mês | Workloads específicos |
|
|
45
|
+
|
|
46
|
+
## Recursos Bloqueados (Sem Justificativa)
|
|
47
|
+
|
|
48
|
+
| Recurso | Custo | Alternativa |
|
|
49
|
+
|---------|-------|-------------|
|
|
50
|
+
| Premium Storage | >$20/mês | Standard LRS |
|
|
51
|
+
| Dedicated SQL | >$100/mês | Azure SQL Basic |
|
|
52
|
+
| AKS | >$50/mês | Container Apps |
|
|
53
|
+
| Synapse | >$100/mês | SQL + Scripts |
|
|
54
|
+
|
|
55
|
+
## Template de Estimativa de Custos
|
|
56
|
+
|
|
57
|
+
```markdown
|
|
58
|
+
## Estimativa de Custos - {Feature}
|
|
59
|
+
|
|
60
|
+
### Recursos Necessários
|
|
61
|
+
|
|
62
|
+
| Recurso | SKU | Custo/Mês | Justificativa |
|
|
63
|
+
|---------|-----|-----------|---------------|
|
|
64
|
+
| Container Apps | Consumption | ~$0 | Scale-to-zero |
|
|
65
|
+
| Azure SQL | Free 32GB | $0 | Dentro do limite |
|
|
66
|
+
| Storage | LRS 1GB | ~$0.02 | Blobs de relatórios |
|
|
67
|
+
|
|
68
|
+
### Total Estimado: ~$0.02/mês
|
|
69
|
+
|
|
70
|
+
### Aprovação
|
|
71
|
+
- [x] Free tier (sem aprovação necessária)
|
|
72
|
+
- [ ] Até $10 (requer confirmação)
|
|
73
|
+
- [ ] Acima de $10 (requer ADR)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Como Estimar Custos
|
|
77
|
+
|
|
78
|
+
1. Use [Azure Pricing Calculator](https://azure.microsoft.com/pricing/calculator/)
|
|
79
|
+
2. Considere região Brazil South (pode ser mais caro)
|
|
80
|
+
3. Inclua custos de transferência de dados
|
|
81
|
+
4. Projete para 1 mês de uso típico
|
|
82
|
+
5. Documente no `decisions.md`
|
|
83
|
+
|
|
84
|
+
## Alertas Automáticos
|
|
85
|
+
|
|
86
|
+
Quando detectar:
|
|
87
|
+
- Recurso premium sem justificativa
|
|
88
|
+
- Redundância desnecessária (ex: 2 instâncias em dev)
|
|
89
|
+
- Storage sem lifecycle policy
|
|
90
|
+
- Logs sem retenção definida
|
|
91
|
+
|
|
92
|
+
**Ação**: Bloquear e sugerir alternativa.
|
|
93
|
+
|
|
94
|
+
## Otimizações Recomendadas
|
|
95
|
+
|
|
96
|
+
1. **Container Apps**: Sempre scale-to-zero em dev
|
|
97
|
+
2. **SQL**: Free tier até precisar de mais
|
|
98
|
+
3. **Storage**: LRS em dev, GRS só em prod se necessário
|
|
99
|
+
4. **Logs**: Retenção de 30 dias max em dev
|
|
100
|
+
5. **Backups**: Desabilitar em dev
|
|
101
|
+
|
|
102
|
+
## Documentação de Referência
|
|
103
|
+
|
|
104
|
+
- [Azure Pricing](https://azure.microsoft.com/pricing/)
|
|
105
|
+
- [Free Services](https://azure.microsoft.com/free/free-account-faq/)
|
|
106
|
+
- [Cost Management](https://learn.microsoft.com/en-us/azure/cost-management-billing/)
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
*MORPH-SPEC by Polymorphism Tech*
|