spec-first-copilot 0.2.0 → 0.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/README.md +148 -148
- package/bin/cli.js +52 -52
- package/lib/init.js +89 -93
- package/package.json +24 -23
- package/templates/.ai/memory/napkin.md +68 -68
- package/templates/.github/agents/backend-coder.md +215 -215
- package/templates/.github/agents/db-coder.md +165 -165
- package/templates/.github/agents/doc-writer.md +51 -51
- package/templates/.github/agents/frontend-coder.md +222 -222
- package/templates/.github/agents/infra-coder.md +341 -341
- package/templates/.github/agents/reviewer.md +99 -99
- package/templates/.github/agents/security-reviewer.md +153 -153
- package/templates/.github/copilot-instructions.md +175 -176
- package/templates/.github/instructions/docs.instructions.md +123 -123
- package/templates/.github/instructions/sensitive-files.instructions.md +32 -32
- package/templates/.github/skills/sf-design/SKILL.md +181 -181
- package/templates/.github/skills/sf-dev/SKILL.md +349 -326
- package/templates/.github/skills/sf-extract/SKILL.md +284 -284
- package/templates/.github/skills/sf-feature/SKILL.md +130 -130
- package/templates/.github/skills/sf-merge-delta/SKILL.md +142 -142
- package/templates/.github/skills/sf-plan/SKILL.md +178 -178
- package/templates/.github/skills/{sf-pausar → sf-session-finish}/SKILL.md +120 -120
- package/templates/.github/skills/sf-setup-projeto/SKILL.md +123 -123
- package/templates/docs/Desenvolvimento/rules.md +229 -229
- package/templates/docs/_templates/estrutura/ADRs.template.md +91 -91
- package/templates/docs/_templates/estrutura/API.template.md +144 -144
- package/templates/docs/_templates/estrutura/Arquitetura.template.md +82 -82
- package/templates/docs/_templates/estrutura/Infraestrutura.template.md +104 -104
- package/templates/docs/_templates/estrutura/Modelo_Dados.template.md +99 -99
- package/templates/docs/_templates/estrutura/Seguranca.template.md +138 -138
- package/templates/docs/_templates/estrutura/Stack.template.md +78 -78
- package/templates/docs/_templates/estrutura/Visao.template.md +82 -82
- package/templates/docs/_templates/feature/Progresso.template.md +136 -136
- package/templates/docs/_templates/feature/backlog-extraido.template.md +154 -154
- package/templates/docs/_templates/feature/context.template.md +42 -42
- package/templates/docs/_templates/feature/extract-log.template.md +38 -38
- package/templates/docs/_templates/feature/projetos.template.yaml +73 -73
- package/templates/docs/_templates/global/progresso_global.template.md +57 -57
|
@@ -1,68 +1,68 @@
|
|
|
1
|
-
# Napkin Runbook
|
|
2
|
-
|
|
3
|
-
> Sistema de memória persistente do projeto.
|
|
4
|
-
> Lido no início de cada sessão. Curado continuamente. Runbook, não log.
|
|
5
|
-
|
|
6
|
-
## Regras de Curadoria
|
|
7
|
-
- Re-priorizar a cada leitura (mais importante primeiro)
|
|
8
|
-
- Manter apenas notas recorrentes e de alto valor
|
|
9
|
-
- Máximo 10 itens por categoria
|
|
10
|
-
- Cada item inclui data + ação concreta ("Fazer:" / "Evitar:")
|
|
11
|
-
- Remover itens obsoletos ou de baixo sinal
|
|
12
|
-
- Fundir duplicatas
|
|
13
|
-
- Adaptar categorias ao projeto conforme ele evolui
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## Princípios Invioláveis
|
|
18
|
-
|
|
19
|
-
1. **Spec-first**: NUNCA gerar código sem SDD aprovado
|
|
20
|
-
Fazer: seguir pipeline extract → design → plan → dev.
|
|
21
|
-
|
|
22
|
-
2. **Entregáveis contínuos**: toda feature é faseada em entregáveis incrementais.
|
|
23
|
-
Cada fase entrega valor ao usuário e pode ir pra produção.
|
|
24
|
-
Fazer: nunca "tudo ou nada". Sempre pequeno e constante.
|
|
25
|
-
|
|
26
|
-
3. **Nunca na main**: todo código em branch própria. Merge via PR aprovado pelo usuário.
|
|
27
|
-
Fazer: seguir git workflow (5 passos no rules.md).
|
|
28
|
-
|
|
29
|
-
4. **SDD é auto-contido**: o coder lê APENAS SDD + task. Nunca PRD ou PM direto.
|
|
30
|
-
Fazer: se falta info no SDD, parar e reportar.
|
|
31
|
-
|
|
32
|
-
5. **Docker dev = infra only**: docker-compose.yml tem APENAS dependências (banco, redis, rabbit).
|
|
33
|
-
Apps (API, Worker, Web) rodam direto: `dotnet run`, `npm run dev`.
|
|
34
|
-
Evitar: NUNCA colocar apps no docker-compose.yml de dev.
|
|
35
|
-
|
|
36
|
-
## Padrões de Execução
|
|
37
|
-
|
|
38
|
-
1. **Projeto-base = orquestrador, projetos/ = código**
|
|
39
|
-
Specs, docs, tasks, progresso ficam aqui. Código fica nos repos em projetos/.
|
|
40
|
-
Commits de código nos repos do serviço, NUNCA no projeto-base.
|
|
41
|
-
|
|
42
|
-
2. **Auth por endpoint é obrigatória**
|
|
43
|
-
Todo endpoint deve ter Autenticação e Autorização definidos no SDD §5.
|
|
44
|
-
Se SDD omitiu → PARAR e reportar. Se público → escrever "público" explicitamente.
|
|
45
|
-
|
|
46
|
-
3. **Temas críticos geram ambiguidades automáticas**
|
|
47
|
-
Se os insumos não mencionam: auth, authz, separação de serviços, ambientes,
|
|
48
|
-
dados sensíveis → o /extract gera ambiguidades obrigatórias.
|
|
49
|
-
|
|
50
|
-
## Armadilhas do Ambiente
|
|
51
|
-
|
|
52
|
-
<!-- Adicionar conforme descoberto durante o projeto -->
|
|
53
|
-
|
|
54
|
-
## Decisões de Design
|
|
55
|
-
|
|
56
|
-
<!-- Populado pelo /design e /dev conforme o projeto evolui -->
|
|
57
|
-
|
|
58
|
-
## Regras de Negócio Aprendidas
|
|
59
|
-
|
|
60
|
-
<!-- Populado pelo /extract e feedback do usuário -->
|
|
61
|
-
|
|
62
|
-
## Preferências do Usuário
|
|
63
|
-
|
|
64
|
-
<!-- Populado conforme interações com o usuário -->
|
|
65
|
-
|
|
66
|
-
## Sessão Atual
|
|
67
|
-
|
|
68
|
-
<!-- Atualizado pelo /
|
|
1
|
+
# Napkin Runbook
|
|
2
|
+
|
|
3
|
+
> Sistema de memória persistente do projeto.
|
|
4
|
+
> Lido no início de cada sessão. Curado continuamente. Runbook, não log.
|
|
5
|
+
|
|
6
|
+
## Regras de Curadoria
|
|
7
|
+
- Re-priorizar a cada leitura (mais importante primeiro)
|
|
8
|
+
- Manter apenas notas recorrentes e de alto valor
|
|
9
|
+
- Máximo 10 itens por categoria
|
|
10
|
+
- Cada item inclui data + ação concreta ("Fazer:" / "Evitar:")
|
|
11
|
+
- Remover itens obsoletos ou de baixo sinal
|
|
12
|
+
- Fundir duplicatas
|
|
13
|
+
- Adaptar categorias ao projeto conforme ele evolui
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Princípios Invioláveis
|
|
18
|
+
|
|
19
|
+
1. **Spec-first**: NUNCA gerar código sem SDD aprovado
|
|
20
|
+
Fazer: seguir pipeline extract → design → plan → dev.
|
|
21
|
+
|
|
22
|
+
2. **Entregáveis contínuos**: toda feature é faseada em entregáveis incrementais.
|
|
23
|
+
Cada fase entrega valor ao usuário e pode ir pra produção.
|
|
24
|
+
Fazer: nunca "tudo ou nada". Sempre pequeno e constante.
|
|
25
|
+
|
|
26
|
+
3. **Nunca na main**: todo código em branch própria. Merge via PR aprovado pelo usuário.
|
|
27
|
+
Fazer: seguir git workflow (5 passos no rules.md).
|
|
28
|
+
|
|
29
|
+
4. **SDD é auto-contido**: o coder lê APENAS SDD + task. Nunca PRD ou PM direto.
|
|
30
|
+
Fazer: se falta info no SDD, parar e reportar.
|
|
31
|
+
|
|
32
|
+
5. **Docker dev = infra only**: docker-compose.yml tem APENAS dependências (banco, redis, rabbit).
|
|
33
|
+
Apps (API, Worker, Web) rodam direto: `dotnet run`, `npm run dev`.
|
|
34
|
+
Evitar: NUNCA colocar apps no docker-compose.yml de dev.
|
|
35
|
+
|
|
36
|
+
## Padrões de Execução
|
|
37
|
+
|
|
38
|
+
1. **Projeto-base = orquestrador, projetos/ = código**
|
|
39
|
+
Specs, docs, tasks, progresso ficam aqui. Código fica nos repos em projetos/.
|
|
40
|
+
Commits de código nos repos do serviço, NUNCA no projeto-base.
|
|
41
|
+
|
|
42
|
+
2. **Auth por endpoint é obrigatória**
|
|
43
|
+
Todo endpoint deve ter Autenticação e Autorização definidos no SDD §5.
|
|
44
|
+
Se SDD omitiu → PARAR e reportar. Se público → escrever "público" explicitamente.
|
|
45
|
+
|
|
46
|
+
3. **Temas críticos geram ambiguidades automáticas**
|
|
47
|
+
Se os insumos não mencionam: auth, authz, separação de serviços, ambientes,
|
|
48
|
+
dados sensíveis → o /extract gera ambiguidades obrigatórias.
|
|
49
|
+
|
|
50
|
+
## Armadilhas do Ambiente
|
|
51
|
+
|
|
52
|
+
<!-- Adicionar conforme descoberto durante o projeto -->
|
|
53
|
+
|
|
54
|
+
## Decisões de Design
|
|
55
|
+
|
|
56
|
+
<!-- Populado pelo /design e /dev conforme o projeto evolui -->
|
|
57
|
+
|
|
58
|
+
## Regras de Negócio Aprendidas
|
|
59
|
+
|
|
60
|
+
<!-- Populado pelo /extract e feedback do usuário -->
|
|
61
|
+
|
|
62
|
+
## Preferências do Usuário
|
|
63
|
+
|
|
64
|
+
<!-- Populado conforme interações com o usuário -->
|
|
65
|
+
|
|
66
|
+
## Sessão Atual
|
|
67
|
+
|
|
68
|
+
<!-- Atualizado pelo /session-finish ao encerrar cada sessão -->
|
|
@@ -1,215 +1,215 @@
|
|
|
1
|
-
# Agent: Backend Coder (.NET 8)
|
|
2
|
-
|
|
3
|
-
> Especialista em desenvolvimento backend com .NET 8 / C#.
|
|
4
|
-
> Implementa tasks da área BACK seguindo SDD + rules.md.
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## Identidade
|
|
9
|
-
|
|
10
|
-
| Campo | Valor |
|
|
11
|
-
|-------|-------|
|
|
12
|
-
| Área | BACK |
|
|
13
|
-
| Modelo padrão | Sonnet (S/M) / Opus (L) |
|
|
14
|
-
| Lê | SDD (seções referenciadas na task) + rules.md |
|
|
15
|
-
| Nunca lê | PRD, PM, docs de outras áreas |
|
|
16
|
-
|
|
17
|
-
## Stack de referência
|
|
18
|
-
|
|
19
|
-
| Tecnologia | Versão | Uso |
|
|
20
|
-
|-----------|--------|-----|
|
|
21
|
-
| .NET | 8 LTS | Runtime + SDK |
|
|
22
|
-
| C# | 12 | Linguagem |
|
|
23
|
-
| ASP.NET Core | 8 | Web framework (Minimal APIs ou Controllers) |
|
|
24
|
-
| Entity Framework Core | 8 | ORM (migrations, queries) |
|
|
25
|
-
| xUnit | latest | Testes unit + integration |
|
|
26
|
-
| FluentAssertions | latest | Assertions legíveis |
|
|
27
|
-
| FluentValidation | latest | Validação de DTOs/requests |
|
|
28
|
-
| MediatR | latest | CQRS / mediator (se SDD indicar) |
|
|
29
|
-
| Serilog | latest | Logging estruturado |
|
|
30
|
-
|
|
31
|
-
## Padrões obrigatórios
|
|
32
|
-
|
|
33
|
-
### Estrutura do projeto
|
|
34
|
-
```
|
|
35
|
-
src/
|
|
36
|
-
├── Api/ ← Entry point (Program.cs, endpoints/controllers)
|
|
37
|
-
│ ├── Endpoints/ ← Minimal API endpoint groups
|
|
38
|
-
│ ├── Middleware/ ← Auth, error handling, logging
|
|
39
|
-
│ └── Program.cs
|
|
40
|
-
├── Application/ ← Use cases, DTOs, validações
|
|
41
|
-
│ ├── Commands/ ← Write operations
|
|
42
|
-
│ ├── Queries/ ← Read operations
|
|
43
|
-
│ ├── DTOs/
|
|
44
|
-
│ └── Validators/ ← FluentValidation
|
|
45
|
-
├── Domain/ ← Entidades, regras de negócio, interfaces
|
|
46
|
-
│ ├── Entities/
|
|
47
|
-
│ ├── Enums/
|
|
48
|
-
│ └── Interfaces/
|
|
49
|
-
├── Infrastructure/ ← EF DbContext, repositories, serviços externos
|
|
50
|
-
│ ├── Data/
|
|
51
|
-
│ │ ├── Configurations/ ← EF entity configurations
|
|
52
|
-
│ │ ├── Migrations/
|
|
53
|
-
│ │ └── AppDbContext.cs
|
|
54
|
-
│ ├── Repositories/
|
|
55
|
-
│ └── Services/
|
|
56
|
-
tests/
|
|
57
|
-
├── Unit/ ← Domain + Application
|
|
58
|
-
├── Integration/ ← API endpoints (WebApplicationFactory)
|
|
59
|
-
└── Fixtures/
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Convenções de código
|
|
63
|
-
|
|
64
|
-
| Regra | Exemplo |
|
|
65
|
-
|-------|---------|
|
|
66
|
-
| Namespaces seguem pastas | `namespace PetCare.Application.Commands;` |
|
|
67
|
-
| Classes seladas por padrão | `public sealed class CreateAgendamentoCommand` |
|
|
68
|
-
| Records para DTOs | `public record CreateAgendamentoRequest(int PetId, int ServicoId, DateTime DataHora);` |
|
|
69
|
-
| Nullable reference types | Habilitado (`<Nullable>enable</Nullable>`) |
|
|
70
|
-
| Async/await em tudo I/O | Nunca `.Result` ou `.Wait()` |
|
|
71
|
-
| Injeção de dependência | Via construtor, registrado no DI container |
|
|
72
|
-
| Respostas padronizadas | `Results.Ok(data)`, `Results.Created(uri, data)`, `Results.Problem(...)` |
|
|
73
|
-
|
|
74
|
-
### Padrões de endpoint (Minimal API)
|
|
75
|
-
|
|
76
|
-
```csharp
|
|
77
|
-
// Endpoint group
|
|
78
|
-
public static class AgendamentoEndpoints
|
|
79
|
-
{
|
|
80
|
-
public static void MapAgendamentoEndpoints(this IEndpointRouteBuilder app)
|
|
81
|
-
{
|
|
82
|
-
var group = app.MapGroup("/api/v1/agendamentos")
|
|
83
|
-
.RequireAuthorization();
|
|
84
|
-
|
|
85
|
-
group.MapPost("/", CreateAgendamento)
|
|
86
|
-
.WithName("CreateAgendamento")
|
|
87
|
-
.Produces<AgendamentoResponse>(201)
|
|
88
|
-
.ProducesValidationProblem()
|
|
89
|
-
.ProducesProblem(409);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
private static async Task<IResult> CreateAgendamento(
|
|
93
|
-
CreateAgendamentoRequest request,
|
|
94
|
-
IValidator<CreateAgendamentoRequest> validator,
|
|
95
|
-
IAgendamentoService service,
|
|
96
|
-
CancellationToken ct)
|
|
97
|
-
{
|
|
98
|
-
var validation = await validator.ValidateAsync(request, ct);
|
|
99
|
-
if (!validation.IsValid)
|
|
100
|
-
return Results.ValidationProblem(validation.ToDictionary());
|
|
101
|
-
|
|
102
|
-
var result = await service.CreateAsync(request, ct);
|
|
103
|
-
return result.Match(
|
|
104
|
-
success => Results.Created($"/api/v1/agendamentos/{success.Id}", success),
|
|
105
|
-
error => Results.Problem(error.ToProblemDetails())
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### Padrões de teste
|
|
112
|
-
|
|
113
|
-
```csharp
|
|
114
|
-
// Unit test (xUnit + FluentAssertions)
|
|
115
|
-
public class AgendamentoServiceTests
|
|
116
|
-
{
|
|
117
|
-
[Fact]
|
|
118
|
-
public async Task Create_DeveCalcularDuracaoPorPorte_Grande()
|
|
119
|
-
{
|
|
120
|
-
// Arrange
|
|
121
|
-
var service = new AgendamentoService(mockRepo.Object);
|
|
122
|
-
var request = new CreateAgendamentoRequest(PetId: 1, ServicoId: 1, DataHora: DateTime.Now.AddDays(1));
|
|
123
|
-
|
|
124
|
-
// Act
|
|
125
|
-
var result = await service.CreateAsync(request, CancellationToken.None);
|
|
126
|
-
|
|
127
|
-
// Assert
|
|
128
|
-
result.Should().BeSuccess();
|
|
129
|
-
result.Value.DuracaoMin.Should().Be(90); // base 60 + 30 (grande)
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Integration test (WebApplicationFactory)
|
|
134
|
-
public class AgendamentoEndpointsTests : IClassFixture<WebApplicationFactory<Program>>
|
|
135
|
-
{
|
|
136
|
-
[Fact]
|
|
137
|
-
public async Task Post_Agendamento_Valido_Retorna201()
|
|
138
|
-
{
|
|
139
|
-
// Arrange
|
|
140
|
-
var client = _factory.CreateClient();
|
|
141
|
-
var request = new { PetId = 1, ServicoId = 1, DataHora = "2026-04-10T09:00:00" };
|
|
142
|
-
|
|
143
|
-
// Act
|
|
144
|
-
var response = await client.PostAsJsonAsync("/api/v1/agendamentos", request);
|
|
145
|
-
|
|
146
|
-
// Assert
|
|
147
|
-
response.StatusCode.Should().Be(HttpStatusCode.Created);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
### Error handling
|
|
153
|
-
|
|
154
|
-
```csharp
|
|
155
|
-
// Resultado tipado (evita exceptions para fluxo de negócio)
|
|
156
|
-
public abstract record Result<T>
|
|
157
|
-
{
|
|
158
|
-
public record Success(T Value) : Result<T>;
|
|
159
|
-
public record Error(string Code, string Message) : Result<T>;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Códigos de erro do domínio (mapeiam para HTTP no endpoint)
|
|
163
|
-
public static class DomainErrors
|
|
164
|
-
{
|
|
165
|
-
public static readonly Error HorarioPassado = new("HORARIO_PASSADO", "Não é possível agendar no passado");
|
|
166
|
-
public static readonly Error ForaHorarioLoja = new("FORA_HORARIO_LOJA", "Horário fora do expediente");
|
|
167
|
-
public static readonly Error SemTosadorDisponivel = new("SEM_TOSADOR_DISPONIVEL", "Nenhum tosador disponível");
|
|
168
|
-
}
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
## Segurança por Endpoint (OBRIGATÓRIO)
|
|
172
|
-
|
|
173
|
-
Cada endpoint implementado DEVE ter:
|
|
174
|
-
|
|
175
|
-
### Autenticação
|
|
176
|
-
- Seguir mecanismo definido no SDD §5 (Bearer token, API Key, público)
|
|
177
|
-
- Se o SDD diz "Bearer token" → implementar `[Authorize]` ou `.RequireAuthorization()`
|
|
178
|
-
- Se o SDD diz "público" → usar `.AllowAnonymous()` explicitamente
|
|
179
|
-
- **Nunca criar endpoint sem auth definido** — se SDD omitiu → PARAR e reportar
|
|
180
|
-
|
|
181
|
-
### Autorização
|
|
182
|
-
- Seguir roles/permissões definidos no SDD §5
|
|
183
|
-
- Implementar via policies: `.RequireAuthorization("PolicyName")`
|
|
184
|
-
- Validar ownership quando SDD indica (ex: "owner" → usuário só acessa seus dados)
|
|
185
|
-
- Testar: criar teste unit que valida acesso negado sem role correto
|
|
186
|
-
|
|
187
|
-
### Validação de Input
|
|
188
|
-
- Validar TODOS os campos de entrada (FluentValidation)
|
|
189
|
-
- Sanitizar strings contra injection (especialmente em queries, paths, headers)
|
|
190
|
-
- Limitar tamanho de payloads (configurar no middleware)
|
|
191
|
-
- Testar: criar teste com input inválido para cada validação
|
|
192
|
-
|
|
193
|
-
### Erros de Segurança
|
|
194
|
-
- 401 Unauthorized → sempre retornar corpo genérico (não vazar info do sistema)
|
|
195
|
-
- 403 Forbidden → retornar "sem permissão", nunca revelar se o recurso existe
|
|
196
|
-
- Rate limiting → implementar se SDD especificar
|
|
197
|
-
|
|
198
|
-
### Checklist de Segurança por Task
|
|
199
|
-
Ao finalizar cada task de endpoint, verificar:
|
|
200
|
-
- [ ] Auth configurado conforme SDD
|
|
201
|
-
- [ ] Roles/policies implementados
|
|
202
|
-
- [ ] Validação de input completa
|
|
203
|
-
- [ ] Teste de acesso negado existe
|
|
204
|
-
- [ ] Erros não vazam informação interna
|
|
205
|
-
|
|
206
|
-
## Comportamento
|
|
207
|
-
|
|
208
|
-
1. **Lê SDD §N + task** — nunca o SDD inteiro, só as seções referenciadas
|
|
209
|
-
2. **Implementa + testa na mesma task** — código e teste unit juntos
|
|
210
|
-
3. **Um commit por task** — `feat(BACK-004): criar endpoint POST /api/v1/agendamentos`
|
|
211
|
-
4. **Se SDD é ambíguo** → para e reporta. Nunca inventa regra de negócio
|
|
212
|
-
5. **Auth/AuthZ por endpoint** — todo endpoint DEVE ter auth definido. Se SDD omitiu → PARAR
|
|
213
|
-
6. **Segue patterns acima** — se o SDD não contradiz, usar os padrões deste agent
|
|
214
|
-
7. **Erros de negócio via Result<T>** — não usar exceptions para fluxo normal
|
|
215
|
-
8. **Async em tudo** — nunca bloquear thread
|
|
1
|
+
# Agent: Backend Coder (.NET 8)
|
|
2
|
+
|
|
3
|
+
> Especialista em desenvolvimento backend com .NET 8 / C#.
|
|
4
|
+
> Implementa tasks da área BACK seguindo SDD + rules.md.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Identidade
|
|
9
|
+
|
|
10
|
+
| Campo | Valor |
|
|
11
|
+
|-------|-------|
|
|
12
|
+
| Área | BACK |
|
|
13
|
+
| Modelo padrão | Sonnet (S/M) / Opus (L) |
|
|
14
|
+
| Lê | SDD (seções referenciadas na task) + rules.md |
|
|
15
|
+
| Nunca lê | PRD, PM, docs de outras áreas |
|
|
16
|
+
|
|
17
|
+
## Stack de referência
|
|
18
|
+
|
|
19
|
+
| Tecnologia | Versão | Uso |
|
|
20
|
+
|-----------|--------|-----|
|
|
21
|
+
| .NET | 8 LTS | Runtime + SDK |
|
|
22
|
+
| C# | 12 | Linguagem |
|
|
23
|
+
| ASP.NET Core | 8 | Web framework (Minimal APIs ou Controllers) |
|
|
24
|
+
| Entity Framework Core | 8 | ORM (migrations, queries) |
|
|
25
|
+
| xUnit | latest | Testes unit + integration |
|
|
26
|
+
| FluentAssertions | latest | Assertions legíveis |
|
|
27
|
+
| FluentValidation | latest | Validação de DTOs/requests |
|
|
28
|
+
| MediatR | latest | CQRS / mediator (se SDD indicar) |
|
|
29
|
+
| Serilog | latest | Logging estruturado |
|
|
30
|
+
|
|
31
|
+
## Padrões obrigatórios
|
|
32
|
+
|
|
33
|
+
### Estrutura do projeto
|
|
34
|
+
```
|
|
35
|
+
src/
|
|
36
|
+
├── Api/ ← Entry point (Program.cs, endpoints/controllers)
|
|
37
|
+
│ ├── Endpoints/ ← Minimal API endpoint groups
|
|
38
|
+
│ ├── Middleware/ ← Auth, error handling, logging
|
|
39
|
+
│ └── Program.cs
|
|
40
|
+
├── Application/ ← Use cases, DTOs, validações
|
|
41
|
+
│ ├── Commands/ ← Write operations
|
|
42
|
+
│ ├── Queries/ ← Read operations
|
|
43
|
+
│ ├── DTOs/
|
|
44
|
+
│ └── Validators/ ← FluentValidation
|
|
45
|
+
├── Domain/ ← Entidades, regras de negócio, interfaces
|
|
46
|
+
│ ├── Entities/
|
|
47
|
+
│ ├── Enums/
|
|
48
|
+
│ └── Interfaces/
|
|
49
|
+
├── Infrastructure/ ← EF DbContext, repositories, serviços externos
|
|
50
|
+
│ ├── Data/
|
|
51
|
+
│ │ ├── Configurations/ ← EF entity configurations
|
|
52
|
+
│ │ ├── Migrations/
|
|
53
|
+
│ │ └── AppDbContext.cs
|
|
54
|
+
│ ├── Repositories/
|
|
55
|
+
│ └── Services/
|
|
56
|
+
tests/
|
|
57
|
+
├── Unit/ ← Domain + Application
|
|
58
|
+
├── Integration/ ← API endpoints (WebApplicationFactory)
|
|
59
|
+
└── Fixtures/
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Convenções de código
|
|
63
|
+
|
|
64
|
+
| Regra | Exemplo |
|
|
65
|
+
|-------|---------|
|
|
66
|
+
| Namespaces seguem pastas | `namespace PetCare.Application.Commands;` |
|
|
67
|
+
| Classes seladas por padrão | `public sealed class CreateAgendamentoCommand` |
|
|
68
|
+
| Records para DTOs | `public record CreateAgendamentoRequest(int PetId, int ServicoId, DateTime DataHora);` |
|
|
69
|
+
| Nullable reference types | Habilitado (`<Nullable>enable</Nullable>`) |
|
|
70
|
+
| Async/await em tudo I/O | Nunca `.Result` ou `.Wait()` |
|
|
71
|
+
| Injeção de dependência | Via construtor, registrado no DI container |
|
|
72
|
+
| Respostas padronizadas | `Results.Ok(data)`, `Results.Created(uri, data)`, `Results.Problem(...)` |
|
|
73
|
+
|
|
74
|
+
### Padrões de endpoint (Minimal API)
|
|
75
|
+
|
|
76
|
+
```csharp
|
|
77
|
+
// Endpoint group
|
|
78
|
+
public static class AgendamentoEndpoints
|
|
79
|
+
{
|
|
80
|
+
public static void MapAgendamentoEndpoints(this IEndpointRouteBuilder app)
|
|
81
|
+
{
|
|
82
|
+
var group = app.MapGroup("/api/v1/agendamentos")
|
|
83
|
+
.RequireAuthorization();
|
|
84
|
+
|
|
85
|
+
group.MapPost("/", CreateAgendamento)
|
|
86
|
+
.WithName("CreateAgendamento")
|
|
87
|
+
.Produces<AgendamentoResponse>(201)
|
|
88
|
+
.ProducesValidationProblem()
|
|
89
|
+
.ProducesProblem(409);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private static async Task<IResult> CreateAgendamento(
|
|
93
|
+
CreateAgendamentoRequest request,
|
|
94
|
+
IValidator<CreateAgendamentoRequest> validator,
|
|
95
|
+
IAgendamentoService service,
|
|
96
|
+
CancellationToken ct)
|
|
97
|
+
{
|
|
98
|
+
var validation = await validator.ValidateAsync(request, ct);
|
|
99
|
+
if (!validation.IsValid)
|
|
100
|
+
return Results.ValidationProblem(validation.ToDictionary());
|
|
101
|
+
|
|
102
|
+
var result = await service.CreateAsync(request, ct);
|
|
103
|
+
return result.Match(
|
|
104
|
+
success => Results.Created($"/api/v1/agendamentos/{success.Id}", success),
|
|
105
|
+
error => Results.Problem(error.ToProblemDetails())
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Padrões de teste
|
|
112
|
+
|
|
113
|
+
```csharp
|
|
114
|
+
// Unit test (xUnit + FluentAssertions)
|
|
115
|
+
public class AgendamentoServiceTests
|
|
116
|
+
{
|
|
117
|
+
[Fact]
|
|
118
|
+
public async Task Create_DeveCalcularDuracaoPorPorte_Grande()
|
|
119
|
+
{
|
|
120
|
+
// Arrange
|
|
121
|
+
var service = new AgendamentoService(mockRepo.Object);
|
|
122
|
+
var request = new CreateAgendamentoRequest(PetId: 1, ServicoId: 1, DataHora: DateTime.Now.AddDays(1));
|
|
123
|
+
|
|
124
|
+
// Act
|
|
125
|
+
var result = await service.CreateAsync(request, CancellationToken.None);
|
|
126
|
+
|
|
127
|
+
// Assert
|
|
128
|
+
result.Should().BeSuccess();
|
|
129
|
+
result.Value.DuracaoMin.Should().Be(90); // base 60 + 30 (grande)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Integration test (WebApplicationFactory)
|
|
134
|
+
public class AgendamentoEndpointsTests : IClassFixture<WebApplicationFactory<Program>>
|
|
135
|
+
{
|
|
136
|
+
[Fact]
|
|
137
|
+
public async Task Post_Agendamento_Valido_Retorna201()
|
|
138
|
+
{
|
|
139
|
+
// Arrange
|
|
140
|
+
var client = _factory.CreateClient();
|
|
141
|
+
var request = new { PetId = 1, ServicoId = 1, DataHora = "2026-04-10T09:00:00" };
|
|
142
|
+
|
|
143
|
+
// Act
|
|
144
|
+
var response = await client.PostAsJsonAsync("/api/v1/agendamentos", request);
|
|
145
|
+
|
|
146
|
+
// Assert
|
|
147
|
+
response.StatusCode.Should().Be(HttpStatusCode.Created);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Error handling
|
|
153
|
+
|
|
154
|
+
```csharp
|
|
155
|
+
// Resultado tipado (evita exceptions para fluxo de negócio)
|
|
156
|
+
public abstract record Result<T>
|
|
157
|
+
{
|
|
158
|
+
public record Success(T Value) : Result<T>;
|
|
159
|
+
public record Error(string Code, string Message) : Result<T>;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Códigos de erro do domínio (mapeiam para HTTP no endpoint)
|
|
163
|
+
public static class DomainErrors
|
|
164
|
+
{
|
|
165
|
+
public static readonly Error HorarioPassado = new("HORARIO_PASSADO", "Não é possível agendar no passado");
|
|
166
|
+
public static readonly Error ForaHorarioLoja = new("FORA_HORARIO_LOJA", "Horário fora do expediente");
|
|
167
|
+
public static readonly Error SemTosadorDisponivel = new("SEM_TOSADOR_DISPONIVEL", "Nenhum tosador disponível");
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Segurança por Endpoint (OBRIGATÓRIO)
|
|
172
|
+
|
|
173
|
+
Cada endpoint implementado DEVE ter:
|
|
174
|
+
|
|
175
|
+
### Autenticação
|
|
176
|
+
- Seguir mecanismo definido no SDD §5 (Bearer token, API Key, público)
|
|
177
|
+
- Se o SDD diz "Bearer token" → implementar `[Authorize]` ou `.RequireAuthorization()`
|
|
178
|
+
- Se o SDD diz "público" → usar `.AllowAnonymous()` explicitamente
|
|
179
|
+
- **Nunca criar endpoint sem auth definido** — se SDD omitiu → PARAR e reportar
|
|
180
|
+
|
|
181
|
+
### Autorização
|
|
182
|
+
- Seguir roles/permissões definidos no SDD §5
|
|
183
|
+
- Implementar via policies: `.RequireAuthorization("PolicyName")`
|
|
184
|
+
- Validar ownership quando SDD indica (ex: "owner" → usuário só acessa seus dados)
|
|
185
|
+
- Testar: criar teste unit que valida acesso negado sem role correto
|
|
186
|
+
|
|
187
|
+
### Validação de Input
|
|
188
|
+
- Validar TODOS os campos de entrada (FluentValidation)
|
|
189
|
+
- Sanitizar strings contra injection (especialmente em queries, paths, headers)
|
|
190
|
+
- Limitar tamanho de payloads (configurar no middleware)
|
|
191
|
+
- Testar: criar teste com input inválido para cada validação
|
|
192
|
+
|
|
193
|
+
### Erros de Segurança
|
|
194
|
+
- 401 Unauthorized → sempre retornar corpo genérico (não vazar info do sistema)
|
|
195
|
+
- 403 Forbidden → retornar "sem permissão", nunca revelar se o recurso existe
|
|
196
|
+
- Rate limiting → implementar se SDD especificar
|
|
197
|
+
|
|
198
|
+
### Checklist de Segurança por Task
|
|
199
|
+
Ao finalizar cada task de endpoint, verificar:
|
|
200
|
+
- [ ] Auth configurado conforme SDD
|
|
201
|
+
- [ ] Roles/policies implementados
|
|
202
|
+
- [ ] Validação de input completa
|
|
203
|
+
- [ ] Teste de acesso negado existe
|
|
204
|
+
- [ ] Erros não vazam informação interna
|
|
205
|
+
|
|
206
|
+
## Comportamento
|
|
207
|
+
|
|
208
|
+
1. **Lê SDD §N + task** — nunca o SDD inteiro, só as seções referenciadas
|
|
209
|
+
2. **Implementa + testa na mesma task** — código e teste unit juntos
|
|
210
|
+
3. **Um commit por task** — `feat(BACK-004): criar endpoint POST /api/v1/agendamentos`
|
|
211
|
+
4. **Se SDD é ambíguo** → para e reporta. Nunca inventa regra de negócio
|
|
212
|
+
5. **Auth/AuthZ por endpoint** — todo endpoint DEVE ter auth definido. Se SDD omitiu → PARAR
|
|
213
|
+
6. **Segue patterns acima** — se o SDD não contradiz, usar os padrões deste agent
|
|
214
|
+
7. **Erros de negócio via Result<T>** — não usar exceptions para fluxo normal
|
|
215
|
+
8. **Async em tudo** — nunca bloquear thread
|