spec-first-copilot 0.5.0-beta.1 → 0.5.0-beta.2
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/package.json +1 -1
- package/templates/.github/agents/backend-coder.md +215 -215
- package/templates/.github/agents/db-coder.md +165 -165
- 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 +219 -218
- 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 +209 -209
- package/templates/.github/skills/sf-dev/SKILL.md +354 -354
- package/templates/.github/skills/sf-feature/SKILL.md +130 -130
- package/templates/.github/skills/sf-plan/SKILL.md +180 -180
- package/templates/.github/skills/sf-setup-projeto/SKILL.md +123 -123
- package/templates/.github/templates/feature/PRD.template.md +256 -256
- package/templates/.github/templates/feature/Progresso.template.md +136 -136
- package/templates/.github/templates/specs/tasks.template.md +61 -61
- /package/templates/{docs/specs → specs}/.gitkeep +0 -0
package/package.json
CHANGED
|
@@ -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ê | `
|
|
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ê | `specs/{nome}/contracts.md` (API, dados, regras) + `scenarios.md` (fluxos, CAs) + 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
|