adi_dev_workflow 1.1.1 → 1.3.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/bin/index.js +8 -8
- package/frameworks/agents/qa-staff-engineer.md +311 -311
- package/frameworks/agents/qa-validation-expert.md +458 -458
- package/frameworks/agents/tech-review-conformance.md +200 -200
- package/frameworks/commands/ministack/README.md +2 -0
- package/frameworks/commands/ministack/code-review.md +2 -0
- package/frameworks/commands/ministack/generate-intent.md +2 -0
- package/frameworks/commands/ministack/generate-scope.md +2 -0
- package/frameworks/commands/ministack/generate-tasks.md +2 -0
- package/frameworks/commands/ministack/generate-tech-direction.md +2 -0
- package/frameworks/commands/ministack/run-ministack-tasks.md +3 -0
- package/frameworks/commands/ministack/run-ministack-withlinear.md +2 -0
- package/frameworks/commands/ministack/status.md +2 -0
- package/frameworks/commands/sdd/code-review.md +2 -0
- package/frameworks/commands/sdd/generate-prd.md +2 -0
- package/frameworks/commands/sdd/generate-task-plan.md +2 -0
- package/frameworks/commands/sdd/generate-tech-direction.md +2 -0
- package/frameworks/commands/sdd/generate-tech-spec.md +2 -0
- package/frameworks/commands/sdd/generate-tests.md +2 -0
- package/frameworks/commands/sdd/run_tasks.md +3 -0
- package/frameworks/commands/sdd/run_tasks_withlinear.md +2 -0
- package/frameworks/commands/sdd/status.md +2 -0
- package/frameworks/commands/sdd/validate-sdd.md +2 -0
- package/frameworks/commands/sync-tasks-to-linear.md +2 -0
- package/frameworks/commands/taskcard/generate-taskcard.md +2 -0
- package/frameworks/commands/taskcard/run-taskcard.md +2 -0
- package/frameworks/config/ai-framework-config.yaml +112 -0
- package/frameworks/skills/ministack-tasks-expert/SKILL.md +204 -204
- package/frameworks/skills/ministack-tasks-expert/templates/task_plan_template.md +78 -78
- package/frameworks/skills/ministack-tasks-expert/templates/task_template.md +103 -103
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/benchmark.json +99 -99
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/benchmark.md +64 -64
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/eval_metadata.json +12 -12
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/with_skill/grading.json +32 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/with_skill/outputs/response.md +134 -134
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/with_skill/outputs/transcript.md +68 -68
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/with_skill/timing.json +5 -5
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/without_skill/grading.json +32 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/without_skill/outputs/response.md +525 -525
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/without_skill/outputs/transcript.md +30 -30
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/without_skill/timing.json +5 -5
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/eval_metadata.json +12 -12
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/with_skill/grading.json +32 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/with_skill/outputs/response.md +1126 -1126
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/with_skill/outputs/transcript.md +131 -131
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/with_skill/timing.json +5 -5
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/without_skill/grading.json +32 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/without_skill/outputs/response.md +452 -452
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/without_skill/outputs/transcript.md +78 -78
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/without_skill/timing.json +5 -5
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/eval_metadata.json +12 -12
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/with_skill/grading.json +32 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/with_skill/outputs/response.md +101 -101
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/with_skill/outputs/transcript.md +133 -133
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/with_skill/timing.json +5 -5
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/without_skill/grading.json +32 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/without_skill/outputs/response.md +248 -248
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/without_skill/outputs/transcript.md +49 -49
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/without_skill/timing.json +5 -5
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/review.html +1325 -1325
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/benchmark.json +94 -94
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/benchmark.md +67 -67
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/eval_metadata.json +12 -12
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/with_skill/grading.json +32 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/with_skill/outputs/response.md +117 -117
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/with_skill/outputs/transcript.md +91 -91
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/with_skill/timing.json +1 -1
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/without_skill/grading.json +32 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/without_skill/outputs/response.md +694 -694
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/without_skill/outputs/transcript.md +45 -45
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/without_skill/timing.json +1 -1
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/eval_metadata.json +12 -12
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/with_skill/grading.json +32 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/with_skill/outputs/response.md +1087 -1087
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/with_skill/outputs/transcript.md +124 -124
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/with_skill/timing.json +1 -1
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/without_skill/grading.json +32 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/without_skill/outputs/response.md +458 -458
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/without_skill/outputs/transcript.md +84 -84
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/without_skill/timing.json +1 -1
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/eval_metadata.json +12 -12
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/with_skill/grading.json +32 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/with_skill/outputs/response.md +70 -70
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/with_skill/outputs/transcript.md +148 -148
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/with_skill/timing.json +1 -1
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/without_skill/grading.json +32 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/without_skill/outputs/response.md +249 -249
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/without_skill/outputs/transcript.md +80 -80
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/without_skill/timing.json +1 -1
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/review.html +1325 -1325
- package/frameworks/skills/sdd-tech-spec-expert/SKILL.md +317 -317
- package/frameworks/skills/sdd-tech-spec-expert/evals/evals.json +199 -199
- package/frameworks/skills/sdd-tech-spec-expert/templates/spec_tech_template.md +290 -290
- package/frameworks/skills/sdd-tech-spec-expert/templates/tech_direction-template.md +23 -23
- package/package.json +28 -28
- package/src/cli.js +121 -121
- package/src/installer.js +155 -136
- package/src/transformer.js +86 -86
|
@@ -1,525 +1,525 @@
|
|
|
1
|
-
# TASK PLAN -- Modulo de Usuario v1
|
|
2
|
-
|
|
3
|
-
**Baseado em:** `docs/feature-user/v1/spec_tech.md`
|
|
4
|
-
**Data:** 2026-03-07
|
|
5
|
-
**Branch:** `user-feature`
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Visao Geral
|
|
10
|
-
|
|
11
|
-
Este Task Plan detalha a ordem de implementacao da feature de usuario conforme definido no SPEC_TECH v1. As tasks estao organizadas em ordem de dependencia (bottom-up), seguindo o fluxo: Infraestrutura -> Persistencia -> Repository -> Service -> Handler -> Testes de Integracao/E2E.
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## Task 1: Pacote Identity (JWT + Contexto)
|
|
16
|
-
|
|
17
|
-
**Arquivos a CRIAR:**
|
|
18
|
-
- `internal/pkg/identity/identity.go`
|
|
19
|
-
- `internal/pkg/identity/identity_test.go`
|
|
20
|
-
|
|
21
|
-
**Descricao:**
|
|
22
|
-
Criar o pacote `internal/pkg/identity` com as seguintes funcoes publicas:
|
|
23
|
-
|
|
24
|
-
1. **Tipo `Claims`** -- struct com `UserID`, `Email` e `jwt.RegisteredClaims`
|
|
25
|
-
2. **`GenerateToken(userID, email, secret string, duration time.Duration) (string, time.Time, error)`** -- gera JWT assinado com HS256
|
|
26
|
-
3. **`ParseToken(tokenString, secret string) (*Claims, error)`** -- valida e extrai claims; rejeita algoritmos que nao sejam HS256
|
|
27
|
-
4. **`WithUserID(ctx context.Context, userID string) context.Context`** -- injeta user_id no contexto via chave unexportada
|
|
28
|
-
5. **`UserIDFromContext(ctx context.Context) (string, bool)`** -- recupera user_id do contexto
|
|
29
|
-
|
|
30
|
-
**Testes unitarios (`identity_test.go`):**
|
|
31
|
-
- `TestGenerateToken_Success` -- token nao vazio, expiresAt no futuro
|
|
32
|
-
- `TestGenerateToken_TokenIsParseable` -- roundtrip generate -> parse
|
|
33
|
-
- `TestGenerateToken_ClaimsContainCorrectData` -- userID e email corretos
|
|
34
|
-
- `TestParseToken_WrongSecret` -- erro retornado
|
|
35
|
-
- `TestParseToken_ExpiredToken` -- erro retornado
|
|
36
|
-
- `TestParseToken_MalformedToken` -- erro retornado
|
|
37
|
-
- `TestContextRoundtrip_UserID` -- WithUserID + UserIDFromContext retorna valor correto
|
|
38
|
-
- `TestUserIDFromContext_Missing` -- retorna "", false
|
|
39
|
-
|
|
40
|
-
**Criterio de conclusao:** Todos os testes passando com `CGO_ENABLED=1 go test ./internal/pkg/identity/... -v`
|
|
41
|
-
|
|
42
|
-
**Dependencias:** Nenhuma (pacote isolado).
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## Task 2: Configuracao -- Adicionar JWTExpirationHours
|
|
47
|
-
|
|
48
|
-
**Arquivos a MODIFICAR:**
|
|
49
|
-
- `internal/infra/config/config.go`
|
|
50
|
-
- `configs/config.yaml`
|
|
51
|
-
|
|
52
|
-
**Descricao:**
|
|
53
|
-
|
|
54
|
-
1. Em `config.go`: adicionar campo `JWTExpirationHours int` na struct `Config` e ler via `v.GetInt("jwt.expiration_hours")`
|
|
55
|
-
2. Em `config.yaml`: adicionar `expiration_hours: 24` dentro da secao `jwt`
|
|
56
|
-
|
|
57
|
-
**Criterio de conclusao:** `make build` compila sem erros; config carrega o novo campo corretamente.
|
|
58
|
-
|
|
59
|
-
**Dependencias:** Nenhuma.
|
|
60
|
-
|
|
61
|
-
---
|
|
62
|
-
|
|
63
|
-
## Task 3: Migracao -- Adicionar coluna `endereco`
|
|
64
|
-
|
|
65
|
-
**Arquivos a CRIAR:**
|
|
66
|
-
- `internal/db/migrations/002_add_endereco_usuarios.sql`
|
|
67
|
-
|
|
68
|
-
**Descricao:**
|
|
69
|
-
|
|
70
|
-
Criar migracao com:
|
|
71
|
-
```sql
|
|
72
|
-
ALTER TABLE usuarios ADD COLUMN endereco TEXT NOT NULL DEFAULT '';
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
Seguir a convencao do projeto (arquivo unico `.sql`, sem `.up`/`.down`).
|
|
76
|
-
|
|
77
|
-
**Criterio de conclusao:** Aplicacao inicia sem erros; `PRAGMA table_info(usuarios)` lista coluna `endereco`.
|
|
78
|
-
|
|
79
|
-
**Dependencias:** Nenhuma.
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## Task 4: Queries SQLC -- Atualizar queries de usuario
|
|
84
|
-
|
|
85
|
-
**Arquivos a MODIFICAR:**
|
|
86
|
-
- `internal/db/queries/user.sql` (substituicao total do conteudo)
|
|
87
|
-
|
|
88
|
-
**Descricao:**
|
|
89
|
-
|
|
90
|
-
Substituir o conteudo do arquivo de queries por:
|
|
91
|
-
|
|
92
|
-
1. **`CreateUser :one`** -- INSERT com campos `id, nome, email, senha_hash, endereco, data_criacao, data_atualizacao` + RETURNING *
|
|
93
|
-
2. **`GetUserByID :one`** -- SELECT * WHERE id = ? LIMIT 1
|
|
94
|
-
3. **`GetUserByEmail :one`** -- SELECT * WHERE email = ? LIMIT 1
|
|
95
|
-
4. **`UpdateUser :one`** -- UPDATE SET nome, email, senha_hash, endereco, data_atualizacao WHERE id = ? RETURNING *
|
|
96
|
-
|
|
97
|
-
**Pos-execucao:** Executar `make generate` para regenerar `internal/db/sqlc/`.
|
|
98
|
-
|
|
99
|
-
**Criterio de conclusao:** `make generate` executa sem erros; codigo gerado em `internal/db/sqlc/` contem as novas queries.
|
|
100
|
-
|
|
101
|
-
**Dependencias:** Task 3 (migracao deve existir para o schema estar correto).
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## Task 5: Protobuf -- Atualizar contratos gRPC
|
|
106
|
-
|
|
107
|
-
**Arquivos a MODIFICAR:**
|
|
108
|
-
- `api/proto/v1/user.proto` (substituicao total do conteudo)
|
|
109
|
-
|
|
110
|
-
**Descricao:**
|
|
111
|
-
|
|
112
|
-
Substituir o conteudo do proto conforme SPEC_TECH secao 8.1:
|
|
113
|
-
|
|
114
|
-
1. Mensagem `User` com campos: id, name, email, address, created_at, updated_at
|
|
115
|
-
2. `CreateUserRequest` com name, email, password, address
|
|
116
|
-
3. `CreateUserResponse` com id, name, email, created_at
|
|
117
|
-
4. `LoginRequest` com email, password
|
|
118
|
-
5. `LoginResponse` com token, expires_at, id, name, email
|
|
119
|
-
6. `GetUserLoggedRequest` (vazio)
|
|
120
|
-
7. `GetUserLoggedResponse` com User
|
|
121
|
-
8. `UpdateUserRequest` com optional string para name, email, address, new_password, current_password
|
|
122
|
-
9. `UpdateUserResponse` com User
|
|
123
|
-
10. Servico `UserService` com 4 RPCs: CreateUser, Login, GetUserLogged, UpdateUser
|
|
124
|
-
|
|
125
|
-
**Pos-execucao:** Executar `make generate` para regenerar `gen/proto/v1/`.
|
|
126
|
-
|
|
127
|
-
**Criterio de conclusao:** `make generate` e `make build` executam sem erros.
|
|
128
|
-
|
|
129
|
-
**Dependencias:** Nenhuma (pode ser feita em paralelo com Tasks 1-4).
|
|
130
|
-
|
|
131
|
-
---
|
|
132
|
-
|
|
133
|
-
## Task 6: Repository -- Estender UserRepository
|
|
134
|
-
|
|
135
|
-
**Arquivos a MODIFICAR:**
|
|
136
|
-
- `internal/repository/user_repository.go`
|
|
137
|
-
|
|
138
|
-
**Descricao:**
|
|
139
|
-
|
|
140
|
-
1. Adicionar campo `Address string` ao modelo `User`
|
|
141
|
-
2. Adicionar metodos a interface `UserRepository`:
|
|
142
|
-
- `GetByEmail(ctx context.Context, email string) (*User, error)`
|
|
143
|
-
- `Update(ctx context.Context, user *User) (*User, error)`
|
|
144
|
-
3. Implementar os novos metodos na struct `userRepository`
|
|
145
|
-
4. Atualizar mapeamento SQLC->dominio no `Create` e `GetByID` para incluir `Address` (endereco -> Address)
|
|
146
|
-
5. Implementar mapeamento no `GetByEmail` e `Update`
|
|
147
|
-
|
|
148
|
-
**Criterio de conclusao:** `make build` compila sem erros.
|
|
149
|
-
|
|
150
|
-
**Dependencias:** Task 4 (queries SQLC regeneradas).
|
|
151
|
-
|
|
152
|
-
---
|
|
153
|
-
|
|
154
|
-
## Task 7: Service -- Estender UserService
|
|
155
|
-
|
|
156
|
-
**Arquivos a MODIFICAR:**
|
|
157
|
-
- `internal/service/user_service.go`
|
|
158
|
-
|
|
159
|
-
**Descricao:**
|
|
160
|
-
|
|
161
|
-
1. **Adicionar dependencias ao construtor:**
|
|
162
|
-
- `*config.Config` e `*zap.Logger` como parametros de `NewUserService`
|
|
163
|
-
- FX resolve automaticamente (sem alterar `fx.go`)
|
|
164
|
-
|
|
165
|
-
2. **Adicionar variaveis de erro exportadas:**
|
|
166
|
-
- `ErrInvalidName`, `ErrInvalidEmail`, `ErrEmailAlreadyExists`, `ErrPasswordTooShort`, `ErrAddressRequired`
|
|
167
|
-
- `ErrInvalidCredentials`, `ErrUserNotFound`, `ErrNoFieldsToUpdate`
|
|
168
|
-
- `ErrCurrentPasswordRequired`, `ErrCurrentPasswordWrong`
|
|
169
|
-
|
|
170
|
-
3. **Adicionar tipos:**
|
|
171
|
-
- `CreateUserInput` -- atualizar com campo `Address`
|
|
172
|
-
- `LoginResult` -- novo (Token, ExpiresAt, User)
|
|
173
|
-
- `UpdateUserInput` -- novo (ponteiros *string para campos opcionais)
|
|
174
|
-
|
|
175
|
-
4. **Adicionar metodos a interface `UserService`:**
|
|
176
|
-
- `Login(ctx context.Context, email, password string) (*LoginResult, error)`
|
|
177
|
-
- `GetUserLogged(ctx context.Context, userID string) (*repository.User, error)`
|
|
178
|
-
- `UpdateUser(ctx context.Context, userID string, input UpdateUserInput) (*repository.User, error)`
|
|
179
|
-
|
|
180
|
-
5. **Implementar `CreateUser` (atualizar):**
|
|
181
|
-
- Adicionar validacoes: name vazio, email (net/mail), senha >= 8 chars, address vazio
|
|
182
|
-
- Verificar email unico via `repo.GetByEmail`
|
|
183
|
-
- Hash com bcrypt, UUID, timestamps
|
|
184
|
-
- Persistir via `repo.Create`
|
|
185
|
-
- Logging: Info "usuario criado com sucesso"
|
|
186
|
-
|
|
187
|
-
6. **Implementar `Login`:**
|
|
188
|
-
- `repo.GetByEmail` -- se nao existe: `ErrInvalidCredentials`
|
|
189
|
-
- `bcrypt.CompareHashAndPassword` -- se falha: `ErrInvalidCredentials`
|
|
190
|
-
- `identity.GenerateToken(userID, email, secret, duration)`
|
|
191
|
-
- Limpar PasswordHash antes de retornar
|
|
192
|
-
- Logging: Info "login bem-sucedido" / Warn "tentativa de login falha"
|
|
193
|
-
|
|
194
|
-
7. **Implementar `GetUserLogged`:**
|
|
195
|
-
- `repo.GetByID(userID)` -- se nao encontra: `ErrUserNotFound`
|
|
196
|
-
- Limpar PasswordHash
|
|
197
|
-
- Retornar User
|
|
198
|
-
|
|
199
|
-
8. **Implementar `UpdateUser`:**
|
|
200
|
-
- Validar ao menos 1 campo nao-nil
|
|
201
|
-
- Buscar user atual via `repo.GetByID`
|
|
202
|
-
- Se email: validar formato + unicidade
|
|
203
|
-
- Se new_password: exigir current_password, validar tamanho, verificar hash, gerar novo hash
|
|
204
|
-
- Aplicar campos nao-nil sobre user atual
|
|
205
|
-
- Persistir via `repo.Update`
|
|
206
|
-
- Limpar PasswordHash antes de retornar
|
|
207
|
-
- Logging: Info "dados atualizados" / Info "senha alterada"
|
|
208
|
-
|
|
209
|
-
**Criterio de conclusao:** `make build` compila sem erros.
|
|
210
|
-
|
|
211
|
-
**Dependencias:** Task 1 (identity), Task 2 (config), Task 6 (repository).
|
|
212
|
-
|
|
213
|
-
---
|
|
214
|
-
|
|
215
|
-
## Task 8: Interceptor Auth -- Integrar com identity
|
|
216
|
-
|
|
217
|
-
**Arquivos a MODIFICAR:**
|
|
218
|
-
- `internal/infra/grpc/interceptors/auth.go`
|
|
219
|
-
|
|
220
|
-
**Descricao:**
|
|
221
|
-
|
|
222
|
-
1. Adicionar `/proto.v1.UserService/Login` em `skipMethods`
|
|
223
|
-
2. Substituir parse manual do token por `identity.ParseToken(tokenString, cfg.JWTSecret)`
|
|
224
|
-
3. Apos validacao bem-sucedida: `ctx = identity.WithUserID(ctx, claims.UserID)`
|
|
225
|
-
4. Passar ctx atualizado ao handler
|
|
226
|
-
|
|
227
|
-
**Criterio de conclusao:** `make build` compila sem erros.
|
|
228
|
-
|
|
229
|
-
**Dependencias:** Task 1 (identity).
|
|
230
|
-
|
|
231
|
-
---
|
|
232
|
-
|
|
233
|
-
## Task 9: Handler gRPC -- Estender UserHandler
|
|
234
|
-
|
|
235
|
-
**Arquivos a MODIFICAR:**
|
|
236
|
-
- `internal/handler/grpc/user_handler.go`
|
|
237
|
-
|
|
238
|
-
**Descricao:**
|
|
239
|
-
|
|
240
|
-
1. **Atualizar `CreateUser`:**
|
|
241
|
-
- Extrair `address` do request
|
|
242
|
-
- Mapear response com `CreateUserResponse{id, name, email, created_at}`
|
|
243
|
-
|
|
244
|
-
2. **Implementar `Login`:**
|
|
245
|
-
- Extrair email e password do request
|
|
246
|
-
- Chamar `service.Login`
|
|
247
|
-
- Retornar `LoginResponse{token, expires_at, id, name, email}`
|
|
248
|
-
|
|
249
|
-
3. **Implementar `GetUserLogged`:**
|
|
250
|
-
- `identity.UserIDFromContext(ctx)` -- se ausente: `codes.Unauthenticated`
|
|
251
|
-
- Chamar `service.GetUserLogged(userID)`
|
|
252
|
-
- Retornar `GetUserLoggedResponse{User{...}}`
|
|
253
|
-
|
|
254
|
-
4. **Implementar `UpdateUser`:**
|
|
255
|
-
- `identity.UserIDFromContext(ctx)` -- se ausente: `codes.Unauthenticated`
|
|
256
|
-
- Construir `UpdateUserInput` com ponteiros (nil = campo ausente)
|
|
257
|
-
- Chamar `service.UpdateUser(userID, input)`
|
|
258
|
-
- Retornar `UpdateUserResponse{User{...}}`
|
|
259
|
-
|
|
260
|
-
5. **Remover `GetUser`** (substituido por `GetUserLogged`)
|
|
261
|
-
|
|
262
|
-
6. **Atualizar `mapServiceError`:**
|
|
263
|
-
- Adicionar mapeamento para todos os novos erros conforme SPEC_TECH secao 11.2
|
|
264
|
-
|
|
265
|
-
7. **Criar funcao auxiliar `domainUserToProto`:**
|
|
266
|
-
- Converte `*repository.User` para `*pb.User`
|
|
267
|
-
|
|
268
|
-
**Criterio de conclusao:** `make build` compila sem erros.
|
|
269
|
-
|
|
270
|
-
**Dependencias:** Task 5 (proto gerado), Task 7 (service).
|
|
271
|
-
|
|
272
|
-
---
|
|
273
|
-
|
|
274
|
-
## Task 10: Configuracao de Rotas Publicas
|
|
275
|
-
|
|
276
|
-
**Arquivos a MODIFICAR:**
|
|
277
|
-
- `configs/config.yaml`
|
|
278
|
-
|
|
279
|
-
**Descricao:**
|
|
280
|
-
|
|
281
|
-
Garantir que `skip_methods` no config inclua:
|
|
282
|
-
- `/proto.v1.UserService/CreateUser`
|
|
283
|
-
- `/proto.v1.UserService/Login`
|
|
284
|
-
|
|
285
|
-
**Criterio de conclusao:** Servidor inicia sem erros; rotas publicas acessiveis sem token.
|
|
286
|
-
|
|
287
|
-
**Dependencias:** Task 8 (interceptor), Task 9 (handler).
|
|
288
|
-
|
|
289
|
-
---
|
|
290
|
-
|
|
291
|
-
## Task 11: Testes Unitarios -- Service
|
|
292
|
-
|
|
293
|
-
**Arquivos a MODIFICAR:**
|
|
294
|
-
- `internal/service/user_service_test.go`
|
|
295
|
-
|
|
296
|
-
**Descricao:**
|
|
297
|
-
|
|
298
|
-
Atualizar mock `MockUserRepository` com metodos `GetByEmail` e `Update`.
|
|
299
|
-
|
|
300
|
-
**CreateUser (atualizar existentes + novos):**
|
|
301
|
-
- `TestCreateUser_Success` -- incluir Address
|
|
302
|
-
- `TestCreateUser_PasswordIsHashed` -- bcrypt roundtrip
|
|
303
|
-
- `TestCreateUser_GeneratesValidUUID`
|
|
304
|
-
- `TestCreateUser_ErrorEmptyName`
|
|
305
|
-
- `TestCreateUser_ErrorInvalidEmailFormat` (novo)
|
|
306
|
-
- `TestCreateUser_ErrorPasswordTooShort_7Chars` (novo)
|
|
307
|
-
- `TestCreateUser_PasswordExactly8Chars` (novo)
|
|
308
|
-
- `TestCreateUser_ErrorEmptyAddress` (novo)
|
|
309
|
-
- `TestCreateUser_ErrorRepositoryFailure`
|
|
310
|
-
|
|
311
|
-
**Login (novos):**
|
|
312
|
-
- `TestLogin_Success`
|
|
313
|
-
- `TestLogin_ResultDoesNotExposePasswordHash`
|
|
314
|
-
- `TestLogin_TokenExpiresAtRespectsConfig`
|
|
315
|
-
- `TestLogin_EmailNotFound_GenericError`
|
|
316
|
-
- `TestLogin_WrongPassword_GenericError`
|
|
317
|
-
- `TestLogin_ErrorRepositoryFailure`
|
|
318
|
-
|
|
319
|
-
**GetUserLogged (novos):**
|
|
320
|
-
- `TestGetUserLogged_Success`
|
|
321
|
-
- `TestGetUserLogged_UserNotFound`
|
|
322
|
-
- `TestGetUserLogged_RepositoryError`
|
|
323
|
-
|
|
324
|
-
**UpdateUser (novos):**
|
|
325
|
-
- `TestUpdateUser_NameOnly`
|
|
326
|
-
- `TestUpdateUser_EmailOnly`
|
|
327
|
-
- `TestUpdateUser_AddressOnly`
|
|
328
|
-
- `TestUpdateUser_PasswordChange_Success`
|
|
329
|
-
- `TestUpdateUser_MultipleFields`
|
|
330
|
-
- `TestUpdateUser_NoFieldsToUpdate`
|
|
331
|
-
- `TestUpdateUser_InvalidEmailFormat`
|
|
332
|
-
- `TestUpdateUser_EmailAlreadyExists`
|
|
333
|
-
- `TestUpdateUser_CurrentPasswordMissing`
|
|
334
|
-
- `TestUpdateUser_WrongCurrentPassword`
|
|
335
|
-
- `TestUpdateUser_NewPasswordTooShort`
|
|
336
|
-
- `TestUpdateUser_UserNotFound`
|
|
337
|
-
- `TestUpdateUser_RepositoryFailure`
|
|
338
|
-
|
|
339
|
-
**Criterio de conclusao:** `CGO_ENABLED=1 go test ./internal/service/... -v` -- todos passando.
|
|
340
|
-
|
|
341
|
-
**Dependencias:** Task 7 (service implementado).
|
|
342
|
-
|
|
343
|
-
---
|
|
344
|
-
|
|
345
|
-
## Task 12: Testes Unitarios -- Handler
|
|
346
|
-
|
|
347
|
-
**Arquivos a MODIFICAR:**
|
|
348
|
-
- `internal/handler/grpc/user_handler_test.go`
|
|
349
|
-
|
|
350
|
-
**Descricao:**
|
|
351
|
-
|
|
352
|
-
Atualizar mock `MockUserService` com metodos `Login`, `GetUserLogged`, `UpdateUser`. Remover testes de `GetUser`.
|
|
353
|
-
|
|
354
|
-
**CreateUser:**
|
|
355
|
-
- `TestUserHandler_CreateUser_Success`
|
|
356
|
-
- `TestUserHandler_CreateUser_ResponseDoesNotExposePasswordHash`
|
|
357
|
-
- `TestUserHandler_CreateUser_EmptyName`
|
|
358
|
-
- `TestUserHandler_CreateUser_EmptyEmail`
|
|
359
|
-
- `TestUserHandler_CreateUser_ShortPassword`
|
|
360
|
-
- `TestUserHandler_CreateUser_EmptyAddress`
|
|
361
|
-
- `TestUserHandler_CreateUser_DuplicateEmail`
|
|
362
|
-
- `TestUserHandler_CreateUser_InternalError`
|
|
363
|
-
|
|
364
|
-
**Login:**
|
|
365
|
-
- `TestUserHandler_Login_Success`
|
|
366
|
-
- `TestUserHandler_Login_InvalidCredentials`
|
|
367
|
-
- `TestUserHandler_Login_InternalError`
|
|
368
|
-
|
|
369
|
-
**GetUserLogged:**
|
|
370
|
-
- `TestUserHandler_GetUserLogged_Success`
|
|
371
|
-
- `TestUserHandler_GetUserLogged_MissingUserID`
|
|
372
|
-
- `TestUserHandler_GetUserLogged_NotFound`
|
|
373
|
-
|
|
374
|
-
**UpdateUser:**
|
|
375
|
-
- `TestUserHandler_UpdateUser_NameOnly`
|
|
376
|
-
- `TestUserHandler_UpdateUser_EmailOnly`
|
|
377
|
-
- `TestUserHandler_UpdateUser_PasswordChange`
|
|
378
|
-
- `TestUserHandler_UpdateUser_MultipleFields`
|
|
379
|
-
- `TestUserHandler_UpdateUser_NoFields`
|
|
380
|
-
- `TestUserHandler_UpdateUser_EmailAlreadyExists`
|
|
381
|
-
- `TestUserHandler_UpdateUser_CurrentPasswordMissing`
|
|
382
|
-
- `TestUserHandler_UpdateUser_WrongCurrentPassword`
|
|
383
|
-
- `TestUserHandler_UpdateUser_NewPasswordTooShort`
|
|
384
|
-
- `TestUserHandler_UpdateUser_UserNotFound`
|
|
385
|
-
|
|
386
|
-
**Criterio de conclusao:** `CGO_ENABLED=1 go test ./internal/handler/grpc/... -v` -- todos passando.
|
|
387
|
-
|
|
388
|
-
**Dependencias:** Task 9 (handler implementado).
|
|
389
|
-
|
|
390
|
-
---
|
|
391
|
-
|
|
392
|
-
## Task 13: Testes Unitarios -- Interceptor Auth
|
|
393
|
-
|
|
394
|
-
**Arquivos a MODIFICAR:**
|
|
395
|
-
- `internal/infra/grpc/interceptors/auth_test.go`
|
|
396
|
-
|
|
397
|
-
**Descricao:**
|
|
398
|
-
|
|
399
|
-
Adicionar testes:
|
|
400
|
-
- `TestAuthInterceptor_ValidToken_InjectsUserID` -- ctx contem user_id correto
|
|
401
|
-
- `TestAuthInterceptor_SkipsLogin` -- table-driven com CreateUser e Login
|
|
402
|
-
- `TestAuthInterceptor_ProtectedMethodsRequireAuth` -- table-driven com GetUserLogged e UpdateUser
|
|
403
|
-
|
|
404
|
-
**Criterio de conclusao:** `CGO_ENABLED=1 go test ./internal/infra/grpc/interceptors/... -v` -- todos passando.
|
|
405
|
-
|
|
406
|
-
**Dependencias:** Task 8 (interceptor atualizado).
|
|
407
|
-
|
|
408
|
-
---
|
|
409
|
-
|
|
410
|
-
## Task 14: Testes de Integracao -- Repository
|
|
411
|
-
|
|
412
|
-
**Arquivos a CRIAR:**
|
|
413
|
-
- `internal/repository/user_repository_integration_test.go`
|
|
414
|
-
|
|
415
|
-
**Descricao:**
|
|
416
|
-
|
|
417
|
-
Setup com SQLite em `t.TempDir()` + migracoes aplicadas via `database.NewDatabase`.
|
|
418
|
-
|
|
419
|
-
Testes:
|
|
420
|
-
- `TestUserRepository_Create_Success` -- todos os campos persistidos
|
|
421
|
-
- `TestUserRepository_CreateAndGetByID` -- roundtrip create + get
|
|
422
|
-
- `TestUserRepository_GetByEmail` -- retorna user correto com Address
|
|
423
|
-
- `TestUserRepository_Create_DuplicateEmail` -- erro UNIQUE constraint
|
|
424
|
-
- `TestUserRepository_GetByID_NotFound` -- erro
|
|
425
|
-
- `TestUserRepository_GetByEmail_NotFound` -- erro
|
|
426
|
-
- `TestUserRepository_Update_NameOnly`
|
|
427
|
-
- `TestUserRepository_Update_Email`
|
|
428
|
-
- `TestUserRepository_Update_PasswordHash`
|
|
429
|
-
- `TestUserRepository_Update_Address`
|
|
430
|
-
- `TestUserRepository_Update_UpdatedAtChanges`
|
|
431
|
-
- `TestUserRepository_Create_GeneratesValidUUID`
|
|
432
|
-
|
|
433
|
-
**Criterio de conclusao:** `CGO_ENABLED=1 go test ./internal/repository/... -v -tags=integration` -- todos passando.
|
|
434
|
-
|
|
435
|
-
**Dependencias:** Task 6 (repository implementado), Task 3 (migracao).
|
|
436
|
-
|
|
437
|
-
---
|
|
438
|
-
|
|
439
|
-
## Task 15: Testes de Integracao -- Migracao
|
|
440
|
-
|
|
441
|
-
**Arquivos a MODIFICAR:**
|
|
442
|
-
- `internal/infra/database/sqlite_test.go`
|
|
443
|
-
|
|
444
|
-
**Descricao:**
|
|
445
|
-
|
|
446
|
-
Adicionar testes:
|
|
447
|
-
- `TestRunMigrations_TableSchema_IncludesEndereco` -- PRAGMA table_info confirma coluna
|
|
448
|
-
- `TestRunMigrations_EnderecocolumnDefaultEmpty` -- INSERT sem endereco retorna ""
|
|
449
|
-
- `TestRunMigrations_IdempotentWithEndereco` -- segunda chamada NewDatabase sem erro
|
|
450
|
-
|
|
451
|
-
**Criterio de conclusao:** `CGO_ENABLED=1 go test ./internal/infra/database/... -v` -- todos passando.
|
|
452
|
-
|
|
453
|
-
**Dependencias:** Task 3 (migracao criada).
|
|
454
|
-
|
|
455
|
-
---
|
|
456
|
-
|
|
457
|
-
## Task 16: Testes E2E
|
|
458
|
-
|
|
459
|
-
**Arquivos a CRIAR:**
|
|
460
|
-
- `internal/e2e/user_e2e_test.go`
|
|
461
|
-
|
|
462
|
-
**Descricao:**
|
|
463
|
-
|
|
464
|
-
Setup: servidor gRPC real em porta efemera + cliente gRPC + SQLite em `t.TempDir()`.
|
|
465
|
-
|
|
466
|
-
Fluxos:
|
|
467
|
-
- `TestE2E_CreateUser_FullFlow` -- cadastro completo, verifica response sem token, UUID valido
|
|
468
|
-
- `TestE2E_LoginAndGetUserLogged_FullFlow` -- login + consulta dados com Bearer token
|
|
469
|
-
- `TestE2E_UpdateUser_PartialUpdate` -- login + update nome + get confirma persistencia
|
|
470
|
-
- `TestE2E_ProtectedRoutes_RequireAuth` -- GetUserLogged e UpdateUser sem token retornam Unauthenticated
|
|
471
|
-
- `TestE2E_UpdateUser_PasswordChangeAndReauth` -- troca senha + login nova senha ok + login senha antiga falha
|
|
472
|
-
|
|
473
|
-
**Criterio de conclusao:** `CGO_ENABLED=1 go test ./internal/e2e/... -v` -- todos passando.
|
|
474
|
-
|
|
475
|
-
**Dependencias:** Todas as tasks anteriores (1-15).
|
|
476
|
-
|
|
477
|
-
---
|
|
478
|
-
|
|
479
|
-
## Task 17: Validacao Final
|
|
480
|
-
|
|
481
|
-
**Descricao:**
|
|
482
|
-
|
|
483
|
-
1. Executar `make build` -- compilacao sem erros
|
|
484
|
-
2. Executar `make test` -- todos os testes passando
|
|
485
|
-
3. Executar `make lint` -- sem problemas de lint nos protos
|
|
486
|
-
4. Verificar que `PasswordHash` e tokens JWT nao aparecem em nenhum log ou response
|
|
487
|
-
5. Verificar que rotas publicas (`CreateUser`, `Login`) funcionam sem token
|
|
488
|
-
6. Verificar que rotas protegidas (`GetUserLogged`, `UpdateUser`) exigem token valido
|
|
489
|
-
|
|
490
|
-
**Criterio de conclusao:** Todos os checks passam. Feature pronta para code review.
|
|
491
|
-
|
|
492
|
-
**Dependencias:** Task 16.
|
|
493
|
-
|
|
494
|
-
---
|
|
495
|
-
|
|
496
|
-
## Diagrama de Dependencias
|
|
497
|
-
|
|
498
|
-
```
|
|
499
|
-
Task 1 (identity) ─────────────┬──────> Task 7 (service) ──────> Task 9 (handler) ──> Task 12 (test handler)
|
|
500
|
-
│ │ │
|
|
501
|
-
Task 2 (config) ────────────────┘ │ │
|
|
502
|
-
▼ ▼
|
|
503
|
-
Task 3 (migracao) ──> Task 4 (sqlc) ──> Task 6 (repo) ──> Task 11 (test service) Task 10 (rotas publicas)
|
|
504
|
-
│ │
|
|
505
|
-
▼ ▼
|
|
506
|
-
Task 15 (test migracao) Task 14 (test integracao repo)
|
|
507
|
-
|
|
508
|
-
Task 1 ──> Task 8 (interceptor) ──> Task 13 (test interceptor)
|
|
509
|
-
|
|
510
|
-
Todas as tasks ──> Task 16 (E2E) ──> Task 17 (validacao final)
|
|
511
|
-
```
|
|
512
|
-
|
|
513
|
-
## Resumo de Execucao
|
|
514
|
-
|
|
515
|
-
| Fase | Tasks | Descricao |
|
|
516
|
-
|------|-------|-----------|
|
|
517
|
-
| **Fase 1 -- Infraestrutura** | Tasks 1, 2, 3 | Identity, Config, Migracao (paralelas) |
|
|
518
|
-
| **Fase 2 -- Persistencia** | Tasks 4, 5 | Queries SQLC, Protobuf (paralelas) |
|
|
519
|
-
| **Fase 3 -- Camadas de Negocio** | Tasks 6, 7, 8 | Repository, Service, Interceptor |
|
|
520
|
-
| **Fase 4 -- Exposicao** | Tasks 9, 10 | Handler gRPC, Rotas publicas |
|
|
521
|
-
| **Fase 5 -- Testes Unitarios** | Tasks 11, 12, 13 | Testes service, handler, interceptor (paralelas) |
|
|
522
|
-
| **Fase 6 -- Testes Integracao** | Tasks 14, 15 | Repository + Migracao (paralelas) |
|
|
523
|
-
| **Fase 7 -- Testes E2E + Validacao** | Tasks 16, 17 | Fluxos completos + validacao final |
|
|
524
|
-
|
|
525
|
-
**Total: 17 tasks organizadas em 7 fases.**
|
|
1
|
+
# TASK PLAN -- Modulo de Usuario v1
|
|
2
|
+
|
|
3
|
+
**Baseado em:** `docs/feature-user/v1/spec_tech.md`
|
|
4
|
+
**Data:** 2026-03-07
|
|
5
|
+
**Branch:** `user-feature`
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Visao Geral
|
|
10
|
+
|
|
11
|
+
Este Task Plan detalha a ordem de implementacao da feature de usuario conforme definido no SPEC_TECH v1. As tasks estao organizadas em ordem de dependencia (bottom-up), seguindo o fluxo: Infraestrutura -> Persistencia -> Repository -> Service -> Handler -> Testes de Integracao/E2E.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Task 1: Pacote Identity (JWT + Contexto)
|
|
16
|
+
|
|
17
|
+
**Arquivos a CRIAR:**
|
|
18
|
+
- `internal/pkg/identity/identity.go`
|
|
19
|
+
- `internal/pkg/identity/identity_test.go`
|
|
20
|
+
|
|
21
|
+
**Descricao:**
|
|
22
|
+
Criar o pacote `internal/pkg/identity` com as seguintes funcoes publicas:
|
|
23
|
+
|
|
24
|
+
1. **Tipo `Claims`** -- struct com `UserID`, `Email` e `jwt.RegisteredClaims`
|
|
25
|
+
2. **`GenerateToken(userID, email, secret string, duration time.Duration) (string, time.Time, error)`** -- gera JWT assinado com HS256
|
|
26
|
+
3. **`ParseToken(tokenString, secret string) (*Claims, error)`** -- valida e extrai claims; rejeita algoritmos que nao sejam HS256
|
|
27
|
+
4. **`WithUserID(ctx context.Context, userID string) context.Context`** -- injeta user_id no contexto via chave unexportada
|
|
28
|
+
5. **`UserIDFromContext(ctx context.Context) (string, bool)`** -- recupera user_id do contexto
|
|
29
|
+
|
|
30
|
+
**Testes unitarios (`identity_test.go`):**
|
|
31
|
+
- `TestGenerateToken_Success` -- token nao vazio, expiresAt no futuro
|
|
32
|
+
- `TestGenerateToken_TokenIsParseable` -- roundtrip generate -> parse
|
|
33
|
+
- `TestGenerateToken_ClaimsContainCorrectData` -- userID e email corretos
|
|
34
|
+
- `TestParseToken_WrongSecret` -- erro retornado
|
|
35
|
+
- `TestParseToken_ExpiredToken` -- erro retornado
|
|
36
|
+
- `TestParseToken_MalformedToken` -- erro retornado
|
|
37
|
+
- `TestContextRoundtrip_UserID` -- WithUserID + UserIDFromContext retorna valor correto
|
|
38
|
+
- `TestUserIDFromContext_Missing` -- retorna "", false
|
|
39
|
+
|
|
40
|
+
**Criterio de conclusao:** Todos os testes passando com `CGO_ENABLED=1 go test ./internal/pkg/identity/... -v`
|
|
41
|
+
|
|
42
|
+
**Dependencias:** Nenhuma (pacote isolado).
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Task 2: Configuracao -- Adicionar JWTExpirationHours
|
|
47
|
+
|
|
48
|
+
**Arquivos a MODIFICAR:**
|
|
49
|
+
- `internal/infra/config/config.go`
|
|
50
|
+
- `configs/config.yaml`
|
|
51
|
+
|
|
52
|
+
**Descricao:**
|
|
53
|
+
|
|
54
|
+
1. Em `config.go`: adicionar campo `JWTExpirationHours int` na struct `Config` e ler via `v.GetInt("jwt.expiration_hours")`
|
|
55
|
+
2. Em `config.yaml`: adicionar `expiration_hours: 24` dentro da secao `jwt`
|
|
56
|
+
|
|
57
|
+
**Criterio de conclusao:** `make build` compila sem erros; config carrega o novo campo corretamente.
|
|
58
|
+
|
|
59
|
+
**Dependencias:** Nenhuma.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Task 3: Migracao -- Adicionar coluna `endereco`
|
|
64
|
+
|
|
65
|
+
**Arquivos a CRIAR:**
|
|
66
|
+
- `internal/db/migrations/002_add_endereco_usuarios.sql`
|
|
67
|
+
|
|
68
|
+
**Descricao:**
|
|
69
|
+
|
|
70
|
+
Criar migracao com:
|
|
71
|
+
```sql
|
|
72
|
+
ALTER TABLE usuarios ADD COLUMN endereco TEXT NOT NULL DEFAULT '';
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Seguir a convencao do projeto (arquivo unico `.sql`, sem `.up`/`.down`).
|
|
76
|
+
|
|
77
|
+
**Criterio de conclusao:** Aplicacao inicia sem erros; `PRAGMA table_info(usuarios)` lista coluna `endereco`.
|
|
78
|
+
|
|
79
|
+
**Dependencias:** Nenhuma.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Task 4: Queries SQLC -- Atualizar queries de usuario
|
|
84
|
+
|
|
85
|
+
**Arquivos a MODIFICAR:**
|
|
86
|
+
- `internal/db/queries/user.sql` (substituicao total do conteudo)
|
|
87
|
+
|
|
88
|
+
**Descricao:**
|
|
89
|
+
|
|
90
|
+
Substituir o conteudo do arquivo de queries por:
|
|
91
|
+
|
|
92
|
+
1. **`CreateUser :one`** -- INSERT com campos `id, nome, email, senha_hash, endereco, data_criacao, data_atualizacao` + RETURNING *
|
|
93
|
+
2. **`GetUserByID :one`** -- SELECT * WHERE id = ? LIMIT 1
|
|
94
|
+
3. **`GetUserByEmail :one`** -- SELECT * WHERE email = ? LIMIT 1
|
|
95
|
+
4. **`UpdateUser :one`** -- UPDATE SET nome, email, senha_hash, endereco, data_atualizacao WHERE id = ? RETURNING *
|
|
96
|
+
|
|
97
|
+
**Pos-execucao:** Executar `make generate` para regenerar `internal/db/sqlc/`.
|
|
98
|
+
|
|
99
|
+
**Criterio de conclusao:** `make generate` executa sem erros; codigo gerado em `internal/db/sqlc/` contem as novas queries.
|
|
100
|
+
|
|
101
|
+
**Dependencias:** Task 3 (migracao deve existir para o schema estar correto).
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Task 5: Protobuf -- Atualizar contratos gRPC
|
|
106
|
+
|
|
107
|
+
**Arquivos a MODIFICAR:**
|
|
108
|
+
- `api/proto/v1/user.proto` (substituicao total do conteudo)
|
|
109
|
+
|
|
110
|
+
**Descricao:**
|
|
111
|
+
|
|
112
|
+
Substituir o conteudo do proto conforme SPEC_TECH secao 8.1:
|
|
113
|
+
|
|
114
|
+
1. Mensagem `User` com campos: id, name, email, address, created_at, updated_at
|
|
115
|
+
2. `CreateUserRequest` com name, email, password, address
|
|
116
|
+
3. `CreateUserResponse` com id, name, email, created_at
|
|
117
|
+
4. `LoginRequest` com email, password
|
|
118
|
+
5. `LoginResponse` com token, expires_at, id, name, email
|
|
119
|
+
6. `GetUserLoggedRequest` (vazio)
|
|
120
|
+
7. `GetUserLoggedResponse` com User
|
|
121
|
+
8. `UpdateUserRequest` com optional string para name, email, address, new_password, current_password
|
|
122
|
+
9. `UpdateUserResponse` com User
|
|
123
|
+
10. Servico `UserService` com 4 RPCs: CreateUser, Login, GetUserLogged, UpdateUser
|
|
124
|
+
|
|
125
|
+
**Pos-execucao:** Executar `make generate` para regenerar `gen/proto/v1/`.
|
|
126
|
+
|
|
127
|
+
**Criterio de conclusao:** `make generate` e `make build` executam sem erros.
|
|
128
|
+
|
|
129
|
+
**Dependencias:** Nenhuma (pode ser feita em paralelo com Tasks 1-4).
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Task 6: Repository -- Estender UserRepository
|
|
134
|
+
|
|
135
|
+
**Arquivos a MODIFICAR:**
|
|
136
|
+
- `internal/repository/user_repository.go`
|
|
137
|
+
|
|
138
|
+
**Descricao:**
|
|
139
|
+
|
|
140
|
+
1. Adicionar campo `Address string` ao modelo `User`
|
|
141
|
+
2. Adicionar metodos a interface `UserRepository`:
|
|
142
|
+
- `GetByEmail(ctx context.Context, email string) (*User, error)`
|
|
143
|
+
- `Update(ctx context.Context, user *User) (*User, error)`
|
|
144
|
+
3. Implementar os novos metodos na struct `userRepository`
|
|
145
|
+
4. Atualizar mapeamento SQLC->dominio no `Create` e `GetByID` para incluir `Address` (endereco -> Address)
|
|
146
|
+
5. Implementar mapeamento no `GetByEmail` e `Update`
|
|
147
|
+
|
|
148
|
+
**Criterio de conclusao:** `make build` compila sem erros.
|
|
149
|
+
|
|
150
|
+
**Dependencias:** Task 4 (queries SQLC regeneradas).
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Task 7: Service -- Estender UserService
|
|
155
|
+
|
|
156
|
+
**Arquivos a MODIFICAR:**
|
|
157
|
+
- `internal/service/user_service.go`
|
|
158
|
+
|
|
159
|
+
**Descricao:**
|
|
160
|
+
|
|
161
|
+
1. **Adicionar dependencias ao construtor:**
|
|
162
|
+
- `*config.Config` e `*zap.Logger` como parametros de `NewUserService`
|
|
163
|
+
- FX resolve automaticamente (sem alterar `fx.go`)
|
|
164
|
+
|
|
165
|
+
2. **Adicionar variaveis de erro exportadas:**
|
|
166
|
+
- `ErrInvalidName`, `ErrInvalidEmail`, `ErrEmailAlreadyExists`, `ErrPasswordTooShort`, `ErrAddressRequired`
|
|
167
|
+
- `ErrInvalidCredentials`, `ErrUserNotFound`, `ErrNoFieldsToUpdate`
|
|
168
|
+
- `ErrCurrentPasswordRequired`, `ErrCurrentPasswordWrong`
|
|
169
|
+
|
|
170
|
+
3. **Adicionar tipos:**
|
|
171
|
+
- `CreateUserInput` -- atualizar com campo `Address`
|
|
172
|
+
- `LoginResult` -- novo (Token, ExpiresAt, User)
|
|
173
|
+
- `UpdateUserInput` -- novo (ponteiros *string para campos opcionais)
|
|
174
|
+
|
|
175
|
+
4. **Adicionar metodos a interface `UserService`:**
|
|
176
|
+
- `Login(ctx context.Context, email, password string) (*LoginResult, error)`
|
|
177
|
+
- `GetUserLogged(ctx context.Context, userID string) (*repository.User, error)`
|
|
178
|
+
- `UpdateUser(ctx context.Context, userID string, input UpdateUserInput) (*repository.User, error)`
|
|
179
|
+
|
|
180
|
+
5. **Implementar `CreateUser` (atualizar):**
|
|
181
|
+
- Adicionar validacoes: name vazio, email (net/mail), senha >= 8 chars, address vazio
|
|
182
|
+
- Verificar email unico via `repo.GetByEmail`
|
|
183
|
+
- Hash com bcrypt, UUID, timestamps
|
|
184
|
+
- Persistir via `repo.Create`
|
|
185
|
+
- Logging: Info "usuario criado com sucesso"
|
|
186
|
+
|
|
187
|
+
6. **Implementar `Login`:**
|
|
188
|
+
- `repo.GetByEmail` -- se nao existe: `ErrInvalidCredentials`
|
|
189
|
+
- `bcrypt.CompareHashAndPassword` -- se falha: `ErrInvalidCredentials`
|
|
190
|
+
- `identity.GenerateToken(userID, email, secret, duration)`
|
|
191
|
+
- Limpar PasswordHash antes de retornar
|
|
192
|
+
- Logging: Info "login bem-sucedido" / Warn "tentativa de login falha"
|
|
193
|
+
|
|
194
|
+
7. **Implementar `GetUserLogged`:**
|
|
195
|
+
- `repo.GetByID(userID)` -- se nao encontra: `ErrUserNotFound`
|
|
196
|
+
- Limpar PasswordHash
|
|
197
|
+
- Retornar User
|
|
198
|
+
|
|
199
|
+
8. **Implementar `UpdateUser`:**
|
|
200
|
+
- Validar ao menos 1 campo nao-nil
|
|
201
|
+
- Buscar user atual via `repo.GetByID`
|
|
202
|
+
- Se email: validar formato + unicidade
|
|
203
|
+
- Se new_password: exigir current_password, validar tamanho, verificar hash, gerar novo hash
|
|
204
|
+
- Aplicar campos nao-nil sobre user atual
|
|
205
|
+
- Persistir via `repo.Update`
|
|
206
|
+
- Limpar PasswordHash antes de retornar
|
|
207
|
+
- Logging: Info "dados atualizados" / Info "senha alterada"
|
|
208
|
+
|
|
209
|
+
**Criterio de conclusao:** `make build` compila sem erros.
|
|
210
|
+
|
|
211
|
+
**Dependencias:** Task 1 (identity), Task 2 (config), Task 6 (repository).
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Task 8: Interceptor Auth -- Integrar com identity
|
|
216
|
+
|
|
217
|
+
**Arquivos a MODIFICAR:**
|
|
218
|
+
- `internal/infra/grpc/interceptors/auth.go`
|
|
219
|
+
|
|
220
|
+
**Descricao:**
|
|
221
|
+
|
|
222
|
+
1. Adicionar `/proto.v1.UserService/Login` em `skipMethods`
|
|
223
|
+
2. Substituir parse manual do token por `identity.ParseToken(tokenString, cfg.JWTSecret)`
|
|
224
|
+
3. Apos validacao bem-sucedida: `ctx = identity.WithUserID(ctx, claims.UserID)`
|
|
225
|
+
4. Passar ctx atualizado ao handler
|
|
226
|
+
|
|
227
|
+
**Criterio de conclusao:** `make build` compila sem erros.
|
|
228
|
+
|
|
229
|
+
**Dependencias:** Task 1 (identity).
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Task 9: Handler gRPC -- Estender UserHandler
|
|
234
|
+
|
|
235
|
+
**Arquivos a MODIFICAR:**
|
|
236
|
+
- `internal/handler/grpc/user_handler.go`
|
|
237
|
+
|
|
238
|
+
**Descricao:**
|
|
239
|
+
|
|
240
|
+
1. **Atualizar `CreateUser`:**
|
|
241
|
+
- Extrair `address` do request
|
|
242
|
+
- Mapear response com `CreateUserResponse{id, name, email, created_at}`
|
|
243
|
+
|
|
244
|
+
2. **Implementar `Login`:**
|
|
245
|
+
- Extrair email e password do request
|
|
246
|
+
- Chamar `service.Login`
|
|
247
|
+
- Retornar `LoginResponse{token, expires_at, id, name, email}`
|
|
248
|
+
|
|
249
|
+
3. **Implementar `GetUserLogged`:**
|
|
250
|
+
- `identity.UserIDFromContext(ctx)` -- se ausente: `codes.Unauthenticated`
|
|
251
|
+
- Chamar `service.GetUserLogged(userID)`
|
|
252
|
+
- Retornar `GetUserLoggedResponse{User{...}}`
|
|
253
|
+
|
|
254
|
+
4. **Implementar `UpdateUser`:**
|
|
255
|
+
- `identity.UserIDFromContext(ctx)` -- se ausente: `codes.Unauthenticated`
|
|
256
|
+
- Construir `UpdateUserInput` com ponteiros (nil = campo ausente)
|
|
257
|
+
- Chamar `service.UpdateUser(userID, input)`
|
|
258
|
+
- Retornar `UpdateUserResponse{User{...}}`
|
|
259
|
+
|
|
260
|
+
5. **Remover `GetUser`** (substituido por `GetUserLogged`)
|
|
261
|
+
|
|
262
|
+
6. **Atualizar `mapServiceError`:**
|
|
263
|
+
- Adicionar mapeamento para todos os novos erros conforme SPEC_TECH secao 11.2
|
|
264
|
+
|
|
265
|
+
7. **Criar funcao auxiliar `domainUserToProto`:**
|
|
266
|
+
- Converte `*repository.User` para `*pb.User`
|
|
267
|
+
|
|
268
|
+
**Criterio de conclusao:** `make build` compila sem erros.
|
|
269
|
+
|
|
270
|
+
**Dependencias:** Task 5 (proto gerado), Task 7 (service).
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Task 10: Configuracao de Rotas Publicas
|
|
275
|
+
|
|
276
|
+
**Arquivos a MODIFICAR:**
|
|
277
|
+
- `configs/config.yaml`
|
|
278
|
+
|
|
279
|
+
**Descricao:**
|
|
280
|
+
|
|
281
|
+
Garantir que `skip_methods` no config inclua:
|
|
282
|
+
- `/proto.v1.UserService/CreateUser`
|
|
283
|
+
- `/proto.v1.UserService/Login`
|
|
284
|
+
|
|
285
|
+
**Criterio de conclusao:** Servidor inicia sem erros; rotas publicas acessiveis sem token.
|
|
286
|
+
|
|
287
|
+
**Dependencias:** Task 8 (interceptor), Task 9 (handler).
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Task 11: Testes Unitarios -- Service
|
|
292
|
+
|
|
293
|
+
**Arquivos a MODIFICAR:**
|
|
294
|
+
- `internal/service/user_service_test.go`
|
|
295
|
+
|
|
296
|
+
**Descricao:**
|
|
297
|
+
|
|
298
|
+
Atualizar mock `MockUserRepository` com metodos `GetByEmail` e `Update`.
|
|
299
|
+
|
|
300
|
+
**CreateUser (atualizar existentes + novos):**
|
|
301
|
+
- `TestCreateUser_Success` -- incluir Address
|
|
302
|
+
- `TestCreateUser_PasswordIsHashed` -- bcrypt roundtrip
|
|
303
|
+
- `TestCreateUser_GeneratesValidUUID`
|
|
304
|
+
- `TestCreateUser_ErrorEmptyName`
|
|
305
|
+
- `TestCreateUser_ErrorInvalidEmailFormat` (novo)
|
|
306
|
+
- `TestCreateUser_ErrorPasswordTooShort_7Chars` (novo)
|
|
307
|
+
- `TestCreateUser_PasswordExactly8Chars` (novo)
|
|
308
|
+
- `TestCreateUser_ErrorEmptyAddress` (novo)
|
|
309
|
+
- `TestCreateUser_ErrorRepositoryFailure`
|
|
310
|
+
|
|
311
|
+
**Login (novos):**
|
|
312
|
+
- `TestLogin_Success`
|
|
313
|
+
- `TestLogin_ResultDoesNotExposePasswordHash`
|
|
314
|
+
- `TestLogin_TokenExpiresAtRespectsConfig`
|
|
315
|
+
- `TestLogin_EmailNotFound_GenericError`
|
|
316
|
+
- `TestLogin_WrongPassword_GenericError`
|
|
317
|
+
- `TestLogin_ErrorRepositoryFailure`
|
|
318
|
+
|
|
319
|
+
**GetUserLogged (novos):**
|
|
320
|
+
- `TestGetUserLogged_Success`
|
|
321
|
+
- `TestGetUserLogged_UserNotFound`
|
|
322
|
+
- `TestGetUserLogged_RepositoryError`
|
|
323
|
+
|
|
324
|
+
**UpdateUser (novos):**
|
|
325
|
+
- `TestUpdateUser_NameOnly`
|
|
326
|
+
- `TestUpdateUser_EmailOnly`
|
|
327
|
+
- `TestUpdateUser_AddressOnly`
|
|
328
|
+
- `TestUpdateUser_PasswordChange_Success`
|
|
329
|
+
- `TestUpdateUser_MultipleFields`
|
|
330
|
+
- `TestUpdateUser_NoFieldsToUpdate`
|
|
331
|
+
- `TestUpdateUser_InvalidEmailFormat`
|
|
332
|
+
- `TestUpdateUser_EmailAlreadyExists`
|
|
333
|
+
- `TestUpdateUser_CurrentPasswordMissing`
|
|
334
|
+
- `TestUpdateUser_WrongCurrentPassword`
|
|
335
|
+
- `TestUpdateUser_NewPasswordTooShort`
|
|
336
|
+
- `TestUpdateUser_UserNotFound`
|
|
337
|
+
- `TestUpdateUser_RepositoryFailure`
|
|
338
|
+
|
|
339
|
+
**Criterio de conclusao:** `CGO_ENABLED=1 go test ./internal/service/... -v` -- todos passando.
|
|
340
|
+
|
|
341
|
+
**Dependencias:** Task 7 (service implementado).
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## Task 12: Testes Unitarios -- Handler
|
|
346
|
+
|
|
347
|
+
**Arquivos a MODIFICAR:**
|
|
348
|
+
- `internal/handler/grpc/user_handler_test.go`
|
|
349
|
+
|
|
350
|
+
**Descricao:**
|
|
351
|
+
|
|
352
|
+
Atualizar mock `MockUserService` com metodos `Login`, `GetUserLogged`, `UpdateUser`. Remover testes de `GetUser`.
|
|
353
|
+
|
|
354
|
+
**CreateUser:**
|
|
355
|
+
- `TestUserHandler_CreateUser_Success`
|
|
356
|
+
- `TestUserHandler_CreateUser_ResponseDoesNotExposePasswordHash`
|
|
357
|
+
- `TestUserHandler_CreateUser_EmptyName`
|
|
358
|
+
- `TestUserHandler_CreateUser_EmptyEmail`
|
|
359
|
+
- `TestUserHandler_CreateUser_ShortPassword`
|
|
360
|
+
- `TestUserHandler_CreateUser_EmptyAddress`
|
|
361
|
+
- `TestUserHandler_CreateUser_DuplicateEmail`
|
|
362
|
+
- `TestUserHandler_CreateUser_InternalError`
|
|
363
|
+
|
|
364
|
+
**Login:**
|
|
365
|
+
- `TestUserHandler_Login_Success`
|
|
366
|
+
- `TestUserHandler_Login_InvalidCredentials`
|
|
367
|
+
- `TestUserHandler_Login_InternalError`
|
|
368
|
+
|
|
369
|
+
**GetUserLogged:**
|
|
370
|
+
- `TestUserHandler_GetUserLogged_Success`
|
|
371
|
+
- `TestUserHandler_GetUserLogged_MissingUserID`
|
|
372
|
+
- `TestUserHandler_GetUserLogged_NotFound`
|
|
373
|
+
|
|
374
|
+
**UpdateUser:**
|
|
375
|
+
- `TestUserHandler_UpdateUser_NameOnly`
|
|
376
|
+
- `TestUserHandler_UpdateUser_EmailOnly`
|
|
377
|
+
- `TestUserHandler_UpdateUser_PasswordChange`
|
|
378
|
+
- `TestUserHandler_UpdateUser_MultipleFields`
|
|
379
|
+
- `TestUserHandler_UpdateUser_NoFields`
|
|
380
|
+
- `TestUserHandler_UpdateUser_EmailAlreadyExists`
|
|
381
|
+
- `TestUserHandler_UpdateUser_CurrentPasswordMissing`
|
|
382
|
+
- `TestUserHandler_UpdateUser_WrongCurrentPassword`
|
|
383
|
+
- `TestUserHandler_UpdateUser_NewPasswordTooShort`
|
|
384
|
+
- `TestUserHandler_UpdateUser_UserNotFound`
|
|
385
|
+
|
|
386
|
+
**Criterio de conclusao:** `CGO_ENABLED=1 go test ./internal/handler/grpc/... -v` -- todos passando.
|
|
387
|
+
|
|
388
|
+
**Dependencias:** Task 9 (handler implementado).
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## Task 13: Testes Unitarios -- Interceptor Auth
|
|
393
|
+
|
|
394
|
+
**Arquivos a MODIFICAR:**
|
|
395
|
+
- `internal/infra/grpc/interceptors/auth_test.go`
|
|
396
|
+
|
|
397
|
+
**Descricao:**
|
|
398
|
+
|
|
399
|
+
Adicionar testes:
|
|
400
|
+
- `TestAuthInterceptor_ValidToken_InjectsUserID` -- ctx contem user_id correto
|
|
401
|
+
- `TestAuthInterceptor_SkipsLogin` -- table-driven com CreateUser e Login
|
|
402
|
+
- `TestAuthInterceptor_ProtectedMethodsRequireAuth` -- table-driven com GetUserLogged e UpdateUser
|
|
403
|
+
|
|
404
|
+
**Criterio de conclusao:** `CGO_ENABLED=1 go test ./internal/infra/grpc/interceptors/... -v` -- todos passando.
|
|
405
|
+
|
|
406
|
+
**Dependencias:** Task 8 (interceptor atualizado).
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
## Task 14: Testes de Integracao -- Repository
|
|
411
|
+
|
|
412
|
+
**Arquivos a CRIAR:**
|
|
413
|
+
- `internal/repository/user_repository_integration_test.go`
|
|
414
|
+
|
|
415
|
+
**Descricao:**
|
|
416
|
+
|
|
417
|
+
Setup com SQLite em `t.TempDir()` + migracoes aplicadas via `database.NewDatabase`.
|
|
418
|
+
|
|
419
|
+
Testes:
|
|
420
|
+
- `TestUserRepository_Create_Success` -- todos os campos persistidos
|
|
421
|
+
- `TestUserRepository_CreateAndGetByID` -- roundtrip create + get
|
|
422
|
+
- `TestUserRepository_GetByEmail` -- retorna user correto com Address
|
|
423
|
+
- `TestUserRepository_Create_DuplicateEmail` -- erro UNIQUE constraint
|
|
424
|
+
- `TestUserRepository_GetByID_NotFound` -- erro
|
|
425
|
+
- `TestUserRepository_GetByEmail_NotFound` -- erro
|
|
426
|
+
- `TestUserRepository_Update_NameOnly`
|
|
427
|
+
- `TestUserRepository_Update_Email`
|
|
428
|
+
- `TestUserRepository_Update_PasswordHash`
|
|
429
|
+
- `TestUserRepository_Update_Address`
|
|
430
|
+
- `TestUserRepository_Update_UpdatedAtChanges`
|
|
431
|
+
- `TestUserRepository_Create_GeneratesValidUUID`
|
|
432
|
+
|
|
433
|
+
**Criterio de conclusao:** `CGO_ENABLED=1 go test ./internal/repository/... -v -tags=integration` -- todos passando.
|
|
434
|
+
|
|
435
|
+
**Dependencias:** Task 6 (repository implementado), Task 3 (migracao).
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
## Task 15: Testes de Integracao -- Migracao
|
|
440
|
+
|
|
441
|
+
**Arquivos a MODIFICAR:**
|
|
442
|
+
- `internal/infra/database/sqlite_test.go`
|
|
443
|
+
|
|
444
|
+
**Descricao:**
|
|
445
|
+
|
|
446
|
+
Adicionar testes:
|
|
447
|
+
- `TestRunMigrations_TableSchema_IncludesEndereco` -- PRAGMA table_info confirma coluna
|
|
448
|
+
- `TestRunMigrations_EnderecocolumnDefaultEmpty` -- INSERT sem endereco retorna ""
|
|
449
|
+
- `TestRunMigrations_IdempotentWithEndereco` -- segunda chamada NewDatabase sem erro
|
|
450
|
+
|
|
451
|
+
**Criterio de conclusao:** `CGO_ENABLED=1 go test ./internal/infra/database/... -v` -- todos passando.
|
|
452
|
+
|
|
453
|
+
**Dependencias:** Task 3 (migracao criada).
|
|
454
|
+
|
|
455
|
+
---
|
|
456
|
+
|
|
457
|
+
## Task 16: Testes E2E
|
|
458
|
+
|
|
459
|
+
**Arquivos a CRIAR:**
|
|
460
|
+
- `internal/e2e/user_e2e_test.go`
|
|
461
|
+
|
|
462
|
+
**Descricao:**
|
|
463
|
+
|
|
464
|
+
Setup: servidor gRPC real em porta efemera + cliente gRPC + SQLite em `t.TempDir()`.
|
|
465
|
+
|
|
466
|
+
Fluxos:
|
|
467
|
+
- `TestE2E_CreateUser_FullFlow` -- cadastro completo, verifica response sem token, UUID valido
|
|
468
|
+
- `TestE2E_LoginAndGetUserLogged_FullFlow` -- login + consulta dados com Bearer token
|
|
469
|
+
- `TestE2E_UpdateUser_PartialUpdate` -- login + update nome + get confirma persistencia
|
|
470
|
+
- `TestE2E_ProtectedRoutes_RequireAuth` -- GetUserLogged e UpdateUser sem token retornam Unauthenticated
|
|
471
|
+
- `TestE2E_UpdateUser_PasswordChangeAndReauth` -- troca senha + login nova senha ok + login senha antiga falha
|
|
472
|
+
|
|
473
|
+
**Criterio de conclusao:** `CGO_ENABLED=1 go test ./internal/e2e/... -v` -- todos passando.
|
|
474
|
+
|
|
475
|
+
**Dependencias:** Todas as tasks anteriores (1-15).
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## Task 17: Validacao Final
|
|
480
|
+
|
|
481
|
+
**Descricao:**
|
|
482
|
+
|
|
483
|
+
1. Executar `make build` -- compilacao sem erros
|
|
484
|
+
2. Executar `make test` -- todos os testes passando
|
|
485
|
+
3. Executar `make lint` -- sem problemas de lint nos protos
|
|
486
|
+
4. Verificar que `PasswordHash` e tokens JWT nao aparecem em nenhum log ou response
|
|
487
|
+
5. Verificar que rotas publicas (`CreateUser`, `Login`) funcionam sem token
|
|
488
|
+
6. Verificar que rotas protegidas (`GetUserLogged`, `UpdateUser`) exigem token valido
|
|
489
|
+
|
|
490
|
+
**Criterio de conclusao:** Todos os checks passam. Feature pronta para code review.
|
|
491
|
+
|
|
492
|
+
**Dependencias:** Task 16.
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
## Diagrama de Dependencias
|
|
497
|
+
|
|
498
|
+
```
|
|
499
|
+
Task 1 (identity) ─────────────┬──────> Task 7 (service) ──────> Task 9 (handler) ──> Task 12 (test handler)
|
|
500
|
+
│ │ │
|
|
501
|
+
Task 2 (config) ────────────────┘ │ │
|
|
502
|
+
▼ ▼
|
|
503
|
+
Task 3 (migracao) ──> Task 4 (sqlc) ──> Task 6 (repo) ──> Task 11 (test service) Task 10 (rotas publicas)
|
|
504
|
+
│ │
|
|
505
|
+
▼ ▼
|
|
506
|
+
Task 15 (test migracao) Task 14 (test integracao repo)
|
|
507
|
+
|
|
508
|
+
Task 1 ──> Task 8 (interceptor) ──> Task 13 (test interceptor)
|
|
509
|
+
|
|
510
|
+
Todas as tasks ──> Task 16 (E2E) ──> Task 17 (validacao final)
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
## Resumo de Execucao
|
|
514
|
+
|
|
515
|
+
| Fase | Tasks | Descricao |
|
|
516
|
+
|------|-------|-----------|
|
|
517
|
+
| **Fase 1 -- Infraestrutura** | Tasks 1, 2, 3 | Identity, Config, Migracao (paralelas) |
|
|
518
|
+
| **Fase 2 -- Persistencia** | Tasks 4, 5 | Queries SQLC, Protobuf (paralelas) |
|
|
519
|
+
| **Fase 3 -- Camadas de Negocio** | Tasks 6, 7, 8 | Repository, Service, Interceptor |
|
|
520
|
+
| **Fase 4 -- Exposicao** | Tasks 9, 10 | Handler gRPC, Rotas publicas |
|
|
521
|
+
| **Fase 5 -- Testes Unitarios** | Tasks 11, 12, 13 | Testes service, handler, interceptor (paralelas) |
|
|
522
|
+
| **Fase 6 -- Testes Integracao** | Tasks 14, 15 | Repository + Migracao (paralelas) |
|
|
523
|
+
| **Fase 7 -- Testes E2E + Validacao** | Tasks 16, 17 | Fluxos completos + validacao final |
|
|
524
|
+
|
|
525
|
+
**Total: 17 tasks organizadas em 7 fases.**
|