@brunosps00/dev-workflow 0.0.3 → 0.0.5
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 +42 -42
- package/bin/dev-workflow.js +1 -1
- package/lib/constants.js +42 -40
- package/lib/init.js +40 -10
- package/package.json +1 -1
- package/scaffold/en/commands/{analyze-project.md → dw-analyze-project.md} +69 -40
- package/scaffold/en/commands/{brainstorm.md → dw-brainstorm.md} +31 -4
- package/scaffold/en/commands/{bugfix.md → dw-bugfix.md} +63 -19
- package/scaffold/en/commands/{code-review.md → dw-code-review.md} +38 -15
- package/scaffold/en/commands/{commit.md → dw-commit.md} +25 -0
- package/scaffold/en/commands/{create-prd.md → dw-create-prd.md} +24 -10
- package/scaffold/en/commands/{create-tasks.md → dw-create-tasks.md} +11 -4
- package/scaffold/en/commands/{create-techspec.md → dw-create-techspec.md} +38 -11
- package/scaffold/en/commands/{deep-research.md → dw-deep-research.md} +18 -17
- package/scaffold/en/commands/{fix-qa.md → dw-fix-qa.md} +20 -3
- package/scaffold/en/commands/dw-functional-doc.md +276 -0
- package/scaffold/en/commands/{generate-pr.md → dw-generate-pr.md} +20 -5
- package/scaffold/en/commands/dw-help.md +309 -0
- package/scaffold/en/commands/{refactoring-analysis.md → dw-refactoring-analysis.md} +50 -26
- package/scaffold/en/commands/{review-implementation.md → dw-review-implementation.md} +25 -6
- package/scaffold/en/commands/{run-plan.md → dw-run-plan.md} +21 -6
- package/scaffold/en/commands/{run-qa.md → dw-run-qa.md} +32 -13
- package/scaffold/en/commands/{run-task.md → dw-run-task.md} +17 -7
- package/scaffold/en/references/playwright-patterns.md +136 -0
- package/scaffold/en/references/refactoring-catalog.md +167 -0
- package/scaffold/en/templates/brainstorm-matrix.md +44 -0
- package/scaffold/en/templates/functional-doc/case-matrix.md +5 -0
- package/scaffold/en/templates/functional-doc/e2e-runbook.md +3 -0
- package/scaffold/en/templates/functional-doc/features.md +3 -0
- package/scaffold/en/templates/functional-doc/overview.md +21 -0
- package/scaffold/en/templates/functional-doc/playwright.spec.ts.tpl +19 -0
- package/scaffold/en/templates/pr-bugfix-template.md +28 -0
- package/scaffold/en/templates/qa-test-credentials.md +37 -0
- package/scaffold/en/templates/tasks-template.md +1 -1
- package/scaffold/en/templates/techspec-template.md +1 -1
- package/scaffold/pt-br/commands/{analyze-project.md → dw-analyze-project.md} +91 -41
- package/scaffold/pt-br/commands/{brainstorm.md → dw-brainstorm.md} +32 -5
- package/scaffold/pt-br/commands/{bugfix.md → dw-bugfix.md} +70 -13
- package/scaffold/pt-br/commands/{code-review.md → dw-code-review.md} +78 -15
- package/scaffold/pt-br/commands/{commit.md → dw-commit.md} +45 -1
- package/scaffold/pt-br/commands/{create-prd.md → dw-create-prd.md} +25 -10
- package/scaffold/pt-br/commands/{create-tasks.md → dw-create-tasks.md} +20 -13
- package/scaffold/pt-br/commands/{create-techspec.md → dw-create-techspec.md} +40 -13
- package/scaffold/pt-br/commands/{deep-research.md → dw-deep-research.md} +19 -11
- package/scaffold/pt-br/commands/{fix-qa.md → dw-fix-qa.md} +30 -1
- package/scaffold/pt-br/commands/dw-functional-doc.md +276 -0
- package/scaffold/pt-br/commands/{generate-pr.md → dw-generate-pr.md} +58 -3
- package/scaffold/pt-br/commands/{help.md → dw-help.md} +81 -59
- package/scaffold/pt-br/commands/{refactoring-analysis.md → dw-refactoring-analysis.md} +49 -25
- package/scaffold/pt-br/commands/{review-implementation.md → dw-review-implementation.md} +50 -2
- package/scaffold/pt-br/commands/{run-plan.md → dw-run-plan.md} +98 -10
- package/scaffold/pt-br/commands/{run-qa.md → dw-run-qa.md} +93 -18
- package/scaffold/pt-br/commands/{run-task.md → dw-run-task.md} +32 -7
- package/scaffold/pt-br/references/playwright-patterns.md +133 -0
- package/scaffold/pt-br/references/refactoring-catalog.md +166 -0
- package/scaffold/pt-br/templates/brainstorm-matrix.md +44 -0
- package/scaffold/pt-br/templates/functional-doc/case-matrix.md +5 -0
- package/scaffold/pt-br/templates/functional-doc/e2e-runbook.md +3 -0
- package/scaffold/pt-br/templates/functional-doc/features.md +3 -0
- package/scaffold/pt-br/templates/functional-doc/overview.md +21 -0
- package/scaffold/pt-br/templates/functional-doc/playwright.spec.ts.tpl +19 -0
- package/scaffold/pt-br/templates/pr-bugfix-template.md +28 -0
- package/scaffold/pt-br/templates/qa-test-credentials.md +37 -0
- package/scaffold/pt-br/templates/techspec-template.md +1 -1
- package/scaffold/rules-readme.md +3 -3
- package/scaffold/scripts/functional-doc/generate-dossier.mjs +821 -0
- package/scaffold/scripts/functional-doc/run-playwright-flow.mjs +275 -0
- package/scaffold/en/commands/help.md +0 -289
|
@@ -4,12 +4,30 @@ Você é um assistente IA responsável por implementar tasks de desenvolvimento
|
|
|
4
4
|
<critical>Você não deve se apressar para finalizar a tarefa. Sempre verifique os arquivos necessários, verifique os testes, faça um processo de reasoning para garantir tanto a compreensão quanto a execução correta.</critical>
|
|
5
5
|
<critical>A TAREFA NÃO PODE SER CONSIDERADA COMPLETA ENQUANTO TODOS OS TESTES NÃO ESTIVEREM PASSANDO</critical>
|
|
6
6
|
|
|
7
|
+
## Quando Usar
|
|
8
|
+
- Use para executar uma única task do tasks.md de um PRD com validação Nível 1 integrada
|
|
9
|
+
- NÃO use quando precisar executar TODAS as tasks sequencialmente (use `/dw-run-plan` em vez disso)
|
|
10
|
+
- NÃO use para corrigir um bug report (use `/dw-bugfix` em vez disso)
|
|
11
|
+
|
|
12
|
+
## Posição no Pipeline
|
|
13
|
+
**Antecessor:** `/dw-create-tasks` | **Sucessor:** `/dw-run-task` (próxima task) ou `/dw-review-implementation`
|
|
14
|
+
|
|
15
|
+
## Skills Complementares
|
|
16
|
+
|
|
17
|
+
Quando disponíveis no projeto em `./.agents/skills/`, use estas skills como suporte especializado sem substituir este comando:
|
|
18
|
+
|
|
19
|
+
| Skill | Gatilho |
|
|
20
|
+
|-------|---------|
|
|
21
|
+
| `vercel-react-best-practices` | Task envolve renderização React, hidratação, data fetching, bundle, cache ou performance |
|
|
22
|
+
| `webapp-testing` | Task tem frontend interativo que necessita validação E2E em navegador real |
|
|
23
|
+
| `agent-browser` | Validação de UI requer sessão persistente, inspeção de navegação operacional ou evidência visual complementar |
|
|
24
|
+
|
|
7
25
|
## Localização dos Arquivos
|
|
8
26
|
|
|
9
|
-
- PRD:
|
|
10
|
-
- Tech Spec:
|
|
11
|
-
- Tasks:
|
|
12
|
-
- Rules do Projeto:
|
|
27
|
+
- PRD: `.dw/spec/prd-[nome-funcionalidade]/prd.md`
|
|
28
|
+
- Tech Spec: `.dw/spec/prd-[nome-funcionalidade]/techspec.md`
|
|
29
|
+
- Tasks: `.dw/spec/prd-[nome-funcionalidade]/tasks.md`
|
|
30
|
+
- Rules do Projeto: `.dw/rules/`
|
|
13
31
|
|
|
14
32
|
## Etapas para Executar
|
|
15
33
|
|
|
@@ -27,8 +45,9 @@ Você é um assistente IA responsável por implementar tasks de desenvolvimento
|
|
|
27
45
|
Analise considerando:
|
|
28
46
|
- Objetivos principais da tarefa
|
|
29
47
|
- Como a tarefa se encaixa no contexto do projeto
|
|
30
|
-
- Alinhamento com regras e padrões do projeto (
|
|
48
|
+
- Alinhamento com regras e padrões do projeto (`.dw/rules/`)
|
|
31
49
|
- Possíveis soluções ou abordagens
|
|
50
|
+
- Se React/Next.js estiver no escopo, incorporar explicitamente heurísticas relevantes do `vercel-react-best-practices`
|
|
32
51
|
|
|
33
52
|
### 3. Resumo da Tarefa
|
|
34
53
|
|
|
@@ -58,7 +77,8 @@ Após fornecer o resumo e abordagem, **comece imediatamente** a implementar a ta
|
|
|
58
77
|
- **Implementar testes unitários** (obrigatório para backend)
|
|
59
78
|
- Seguir padrões estabelecidos do projeto
|
|
60
79
|
- Garantir que todos os requisitos sejam atendidos
|
|
61
|
-
- **Rodar testes
|
|
80
|
+
- **Rodar testes**: use o comando de teste do projeto
|
|
81
|
+
- Se houver frontend interativo, valide também o comportamento real com `webapp-testing` ou `agent-browser` quando isso reduzir o risco de regressão invisível nos testes unitários
|
|
62
82
|
|
|
63
83
|
**VOCÊ DEVE** iniciar a implementação logo após o processo acima.
|
|
64
84
|
|
|
@@ -82,6 +102,10 @@ Para cada critério de aceitação definido na task:
|
|
|
82
102
|
- Se algum critério não foi atendido: **CORRIJA antes de prosseguir**
|
|
83
103
|
|
|
84
104
|
### Execução de Testes
|
|
105
|
+
```bash
|
|
106
|
+
# Rodar testes do projeto impactado
|
|
107
|
+
pnpm test # ou npm test
|
|
108
|
+
```
|
|
85
109
|
- [ ] Todos os testes passam (existentes + novos)
|
|
86
110
|
- [ ] Novos testes foram criados para código novo
|
|
87
111
|
- Se algum teste falha: **CORRIJA antes de prosseguir**
|
|
@@ -90,7 +114,8 @@ Para cada critério de aceitação definido na task:
|
|
|
90
114
|
- [ ] Tipos explícitos (sem `any`)
|
|
91
115
|
- [ ] Código compila sem erros
|
|
92
116
|
- [ ] Lint passa
|
|
93
|
-
- [ ]
|
|
117
|
+
- [ ] Multi-tenancy respeitado (se aplicável)
|
|
118
|
+
- [ ] Padrões do projeto seguidos (`.dw/rules/`)
|
|
94
119
|
|
|
95
120
|
### Verificação de UI Funcional (para tasks com frontend)
|
|
96
121
|
<critical>Páginas placeholder/stub NÃO são entrega aceitável para RFs de interação do usuário.</critical>
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Padrões de Teste Playwright
|
|
2
|
+
|
|
3
|
+
Referência para `/dw-run-qa` e `/dw-functional-doc`. Padrões E2E comuns.
|
|
4
|
+
|
|
5
|
+
## 1. Navegação Autenticada
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { test, expect } from "@playwright/test";
|
|
9
|
+
|
|
10
|
+
test("navegar rota autenticada", async ({ page }) => {
|
|
11
|
+
// Login
|
|
12
|
+
await page.goto("/login");
|
|
13
|
+
await page.getByLabel("Email").fill("user@test.com");
|
|
14
|
+
await page.getByLabel("Senha").fill("password123");
|
|
15
|
+
await page.getByRole("button", { name: "Entrar" }).click();
|
|
16
|
+
|
|
17
|
+
// Aguardar redirect
|
|
18
|
+
await page.waitForURL("/dashboard");
|
|
19
|
+
await expect(page.getByRole("heading", { name: /dashboard/i })).toBeVisible();
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 2. Submissão de Formulário com Validação
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
test("submeter formulário com erros de validação", async ({ page }) => {
|
|
27
|
+
await page.goto("/users/new");
|
|
28
|
+
|
|
29
|
+
// Submeter vazio → erros de validação
|
|
30
|
+
await page.getByRole("button", { name: "Salvar" }).click();
|
|
31
|
+
await expect(page.getByText("Nome é obrigatório")).toBeVisible();
|
|
32
|
+
await expect(page.getByText("Email é obrigatório")).toBeVisible();
|
|
33
|
+
|
|
34
|
+
// Preencher e submeter → sucesso
|
|
35
|
+
await page.getByLabel("Nome").fill("Maria Silva");
|
|
36
|
+
await page.getByLabel("Email").fill("maria@example.com");
|
|
37
|
+
await page.getByRole("button", { name: "Salvar" }).click();
|
|
38
|
+
|
|
39
|
+
await expect(page.getByText("Usuário criado com sucesso")).toBeVisible();
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 3. Tabela com Filtro e Paginação
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
test("filtrar e paginar tabela", async ({ page }) => {
|
|
47
|
+
await page.goto("/users");
|
|
48
|
+
|
|
49
|
+
// Verificar carregamento inicial
|
|
50
|
+
const rows = page.locator("table tbody tr");
|
|
51
|
+
await expect(rows).toHaveCount(10);
|
|
52
|
+
|
|
53
|
+
// Filtrar
|
|
54
|
+
await page.getByPlaceholder("Buscar...").fill("admin");
|
|
55
|
+
await expect(rows).toHaveCount(2);
|
|
56
|
+
|
|
57
|
+
// Limpar e paginar
|
|
58
|
+
await page.getByPlaceholder("Buscar...").clear();
|
|
59
|
+
await page.getByRole("button", { name: "Próxima" }).click();
|
|
60
|
+
await expect(page.getByText("Página 2")).toBeVisible();
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 4. Interação com Modal / Dialog
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
test("abrir modal, preencher e confirmar", async ({ page }) => {
|
|
68
|
+
await page.goto("/projects");
|
|
69
|
+
|
|
70
|
+
// Abrir modal
|
|
71
|
+
await page.getByRole("button", { name: "Novo Projeto" }).click();
|
|
72
|
+
const dialog = page.getByRole("dialog");
|
|
73
|
+
await expect(dialog).toBeVisible();
|
|
74
|
+
|
|
75
|
+
// Preencher formulário do modal
|
|
76
|
+
await dialog.getByLabel("Nome do Projeto").fill("Meu Projeto");
|
|
77
|
+
await dialog.getByRole("button", { name: "Criar" }).click();
|
|
78
|
+
|
|
79
|
+
// Modal fecha, item aparece na lista
|
|
80
|
+
await expect(dialog).not.toBeVisible();
|
|
81
|
+
await expect(page.getByText("Meu Projeto")).toBeVisible();
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## 5. Permissão / Acesso Negado
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
test("usuário restrito vê acesso negado", async ({ page }) => {
|
|
89
|
+
// Login como usuário restrito
|
|
90
|
+
await page.goto("/login");
|
|
91
|
+
await page.getByLabel("Email").fill("restricted@test.com");
|
|
92
|
+
await page.getByLabel("Senha").fill("password123");
|
|
93
|
+
await page.getByRole("button", { name: "Entrar" }).click();
|
|
94
|
+
|
|
95
|
+
// Tentar acessar rota admin
|
|
96
|
+
await page.goto("/admin/settings");
|
|
97
|
+
|
|
98
|
+
// Verificar acesso negado
|
|
99
|
+
await expect(page.getByText(/acesso negado|proibido|não autorizado/i)).toBeVisible();
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## 6. Tratamento de Erro de API
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
test("trata erro de API graciosamente", async ({ page }) => {
|
|
107
|
+
// Interceptar API para simular erro
|
|
108
|
+
await page.route("**/api/users", (route) =>
|
|
109
|
+
route.fulfill({ status: 500, body: "Internal Server Error" })
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
await page.goto("/users");
|
|
113
|
+
|
|
114
|
+
// Verificar estado de erro
|
|
115
|
+
await expect(page.getByText(/erro|algo deu errado/i)).toBeVisible();
|
|
116
|
+
|
|
117
|
+
// Verificar que botão de retry funciona
|
|
118
|
+
await page.unroute("**/api/users");
|
|
119
|
+
await page.getByRole("button", { name: /tentar novamente/i }).click();
|
|
120
|
+
await expect(page.locator("table tbody tr")).toHaveCount(10);
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Padrão de Captura de Evidência
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
await test.step("Capturar evidência", async () => {
|
|
128
|
+
await page.screenshot({
|
|
129
|
+
path: `evidence/screenshots/${testInfo.title}-${Date.now()}.png`,
|
|
130
|
+
fullPage: true
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
```
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Catálogo de Refatoração — Exemplos Antes/Depois
|
|
2
|
+
|
|
3
|
+
Referência para `/dw-refactoring-analysis`. Baseado no catálogo de Fowler.
|
|
4
|
+
|
|
5
|
+
## 1. Função Longa → Extract Function
|
|
6
|
+
|
|
7
|
+
**Smell:** Função com >15 linhas de lógica, múltiplas responsabilidades.
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// ❌ ANTES: 30+ linhas fazendo validação, transformação e persistência
|
|
11
|
+
async function processOrder(order: Order) {
|
|
12
|
+
if (!order.items.length) throw new Error("Empty order");
|
|
13
|
+
if (order.total < 0) throw new Error("Invalid total");
|
|
14
|
+
if (!order.customer) throw new Error("No customer");
|
|
15
|
+
|
|
16
|
+
const discount = order.customer.isPremium
|
|
17
|
+
? order.total * 0.1
|
|
18
|
+
: order.total > 100 ? order.total * 0.05 : 0;
|
|
19
|
+
const tax = (order.total - discount) * 0.15;
|
|
20
|
+
const finalTotal = order.total - discount + tax;
|
|
21
|
+
|
|
22
|
+
order.discount = discount;
|
|
23
|
+
order.tax = tax;
|
|
24
|
+
order.total = finalTotal;
|
|
25
|
+
order.status = "processed";
|
|
26
|
+
|
|
27
|
+
await db.orders.update(order.id, order);
|
|
28
|
+
await emailService.send(order.customer.email, "Order processed", { order });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ✅ DEPOIS: Cada função com uma responsabilidade
|
|
32
|
+
async function processOrder(order: Order) {
|
|
33
|
+
validateOrder(order);
|
|
34
|
+
const pricing = calculatePricing(order);
|
|
35
|
+
const processed = applyPricing(order, pricing);
|
|
36
|
+
await persistOrder(processed);
|
|
37
|
+
await notifyCustomer(processed);
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## 2. Feature Envy → Move Method
|
|
42
|
+
|
|
43
|
+
**Smell:** Função acessa dados de outro objeto mais que os próprios.
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// ❌ ANTES: calculateShipping conhece demais sobre Address
|
|
47
|
+
function calculateShipping(order: Order) {
|
|
48
|
+
const addr = order.address;
|
|
49
|
+
if (addr.country === "BR" && addr.state === "SP") return 5.99;
|
|
50
|
+
if (addr.country === "BR") return 9.99;
|
|
51
|
+
return 19.99 + (addr.isRemote ? 10 : 0);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ✅ DEPOIS: Address é dono da lógica de frete
|
|
55
|
+
class Address {
|
|
56
|
+
getShippingCost(): number {
|
|
57
|
+
if (this.country === "BR" && this.state === "SP") return 5.99;
|
|
58
|
+
if (this.country === "BR") return 9.99;
|
|
59
|
+
return 19.99 + (this.isRemote ? 10 : 0);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 3. Obsessão por Primitivos → Value Object
|
|
65
|
+
|
|
66
|
+
**Smell:** Usar strings/números crus para conceitos do domínio (emails, dinheiro, datas).
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// ❌ ANTES: email é apenas uma string em todo lugar
|
|
70
|
+
function sendEmail(to: string, subject: string) {
|
|
71
|
+
if (!to.includes("@")) throw new Error("Invalid email");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ✅ DEPOIS: Email é um value object com validação embutida
|
|
75
|
+
class Email {
|
|
76
|
+
constructor(private readonly value: string) {
|
|
77
|
+
if (!value.includes("@")) throw new Error("Invalid email");
|
|
78
|
+
}
|
|
79
|
+
toString() { return this.value; }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function sendEmail(to: Email, subject: string) { /* ... */ }
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## 4. Lógica Duplicada → Extrair Utilitário Compartilhado
|
|
86
|
+
|
|
87
|
+
**Smell:** Mesmas 3+ linhas de lógica aparecem em múltiplos locais.
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
// ❌ ANTES: formatação de data repetida em 4 componentes
|
|
91
|
+
const formatted = `${date.getFullYear()}-${String(date.getMonth()+1).padStart(2,"0")}-${String(date.getDate()).padStart(2,"0")}`;
|
|
92
|
+
|
|
93
|
+
// ✅ DEPOIS: utilitário único
|
|
94
|
+
function formatDate(date: Date): string {
|
|
95
|
+
return date.toISOString().split("T")[0];
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## 5. God Component → Dividir por Responsabilidade
|
|
100
|
+
|
|
101
|
+
**Smell:** Componente React com 200+ linhas, múltiplos useEffects, responsabilidades misturadas.
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
// ❌ ANTES: UserDashboard faz fetch, filtragem, renderização e modais
|
|
105
|
+
function UserDashboard() {
|
|
106
|
+
// 50 linhas de state + effects
|
|
107
|
+
// 30 linhas de handlers
|
|
108
|
+
// 120 linhas de JSX com condições inline
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ✅ DEPOIS: container + presentation + hook
|
|
112
|
+
function useUserDashboard() { /* data fetching + state */ }
|
|
113
|
+
function UserFilters({ filters, onChange }) { /* UI de filtros */ }
|
|
114
|
+
function UserTable({ users, onSelect }) { /* UI de tabela */ }
|
|
115
|
+
function UserDashboard() {
|
|
116
|
+
const { users, filters, setFilters } = useUserDashboard();
|
|
117
|
+
return (
|
|
118
|
+
<>
|
|
119
|
+
<UserFilters filters={filters} onChange={setFilters} />
|
|
120
|
+
<UserTable users={users} />
|
|
121
|
+
</>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## 6. Condicional Complexa → Strategy Pattern / Early Return
|
|
127
|
+
|
|
128
|
+
**Smell:** Cadeia de if/else aninhados com 4+ branches.
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
// ❌ ANTES: condicionais aninhadas
|
|
132
|
+
function getPrice(user: User, product: Product) {
|
|
133
|
+
if (user.type === "premium") {
|
|
134
|
+
if (product.category === "electronics") {
|
|
135
|
+
return product.price * 0.8;
|
|
136
|
+
} else {
|
|
137
|
+
return product.price * 0.9;
|
|
138
|
+
}
|
|
139
|
+
} else if (user.type === "wholesale") {
|
|
140
|
+
return product.price * 0.7;
|
|
141
|
+
} else {
|
|
142
|
+
return product.price;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ✅ DEPOIS: mapa de estratégias + early return
|
|
147
|
+
const DISCOUNT_STRATEGIES: Record<string, (p: Product) => number> = {
|
|
148
|
+
premium: (p) => p.category === "electronics" ? 0.8 : 0.9,
|
|
149
|
+
wholesale: () => 0.7,
|
|
150
|
+
standard: () => 1.0,
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
function getPrice(user: User, product: Product) {
|
|
154
|
+
const discount = DISCOUNT_STRATEGIES[user.type] ?? DISCOUNT_STRATEGIES.standard;
|
|
155
|
+
return product.price * discount(product);
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Guia de Priorização
|
|
160
|
+
|
|
161
|
+
| Severidade | Critério | Ação |
|
|
162
|
+
|------------|----------|------|
|
|
163
|
+
| **P0 - Crítico** | Risco de segurança, corrupção de dados, contrato de API quebrado | Corrigir imediatamente |
|
|
164
|
+
| **P1 - Alto** | >3 duplicações, god objects, código não-testável | Corrigir no sprint atual |
|
|
165
|
+
| **P2 - Médio** | Funções longas, obsessão por primitivos, feature envy | Agendar para refatoração |
|
|
166
|
+
| **P3 - Baixo** | Problemas menores de naming, pequenas duplicações, estilo | Corrigir oportunisticamente |
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Brainstorm: {{TOPIC}}
|
|
2
|
+
|
|
3
|
+
## Contexto
|
|
4
|
+
|
|
5
|
+
{{CONTEXT_DESCRIPTION}}
|
|
6
|
+
|
|
7
|
+
## Matriz de Opções
|
|
8
|
+
|
|
9
|
+
| Critério | Opção A: {{NAME_A}} | Opção B: {{NAME_B}} | Opção C: {{NAME_C}} |
|
|
10
|
+
|----------|---------------------|---------------------|---------------------|
|
|
11
|
+
| **Abordagem** | | | |
|
|
12
|
+
| **Esforço** | Baixo / Médio / Alto | Baixo / Médio / Alto | Baixo / Médio / Alto |
|
|
13
|
+
| **Risco** | Baixo / Médio / Alto | Baixo / Médio / Alto | Baixo / Médio / Alto |
|
|
14
|
+
| **Escalabilidade** | | | |
|
|
15
|
+
| **Manutenibilidade** | | | |
|
|
16
|
+
| **Dependências** | | | |
|
|
17
|
+
|
|
18
|
+
## Trade-offs
|
|
19
|
+
|
|
20
|
+
### Opção A: {{NAME_A}}
|
|
21
|
+
- **Prós:**
|
|
22
|
+
- **Contras:**
|
|
23
|
+
- **Melhor quando:**
|
|
24
|
+
|
|
25
|
+
### Opção B: {{NAME_B}}
|
|
26
|
+
- **Prós:**
|
|
27
|
+
- **Contras:**
|
|
28
|
+
- **Melhor quando:**
|
|
29
|
+
|
|
30
|
+
### Opção C: {{NAME_C}}
|
|
31
|
+
- **Prós:**
|
|
32
|
+
- **Contras:**
|
|
33
|
+
- **Melhor quando:**
|
|
34
|
+
|
|
35
|
+
## Recomendação
|
|
36
|
+
|
|
37
|
+
**Recomendada:** Opção {{X}}
|
|
38
|
+
|
|
39
|
+
**Justificativa:** {{WHY}}
|
|
40
|
+
|
|
41
|
+
## Próximos Passos
|
|
42
|
+
|
|
43
|
+
- [ ] Validar com stakeholders
|
|
44
|
+
- [ ] Criar PRD: `/dw-create-prd`
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Matriz de Casos
|
|
2
|
+
|
|
3
|
+
| ID | Funcionalidade | Tipo de caso | Pré-condições | Ações | Resultado esperado | Mensagem esperada | Status | Evidência |
|
|
4
|
+
|----|----------------|--------------|---------------|-------|--------------------|-------------------|--------|-----------|
|
|
5
|
+
{{rows}}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Dossiê Funcional
|
|
2
|
+
|
|
3
|
+
- **Projeto:** {{projectName}}
|
|
4
|
+
- **Target:** {{target}}
|
|
5
|
+
- **Tipo:** {{targetType}}
|
|
6
|
+
- **Framework detectado:** {{framework}}
|
|
7
|
+
- **Base URL:** {{baseUrl}}
|
|
8
|
+
- **Runner E2E:** {{playwrightStatus}}
|
|
9
|
+
- **Gerado em:** {{generatedAt}}
|
|
10
|
+
|
|
11
|
+
## Resumo
|
|
12
|
+
|
|
13
|
+
{{summary}}
|
|
14
|
+
|
|
15
|
+
## Fontes analisadas
|
|
16
|
+
|
|
17
|
+
{{sources}}
|
|
18
|
+
|
|
19
|
+
## Bloqueios
|
|
20
|
+
|
|
21
|
+
{{blockers}}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { test, expect } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
const BASE_URL = process.env.BASE_URL ?? "{{baseUrl}}";
|
|
4
|
+
|
|
5
|
+
test("{{testTitle}}", async ({ page }) => {
|
|
6
|
+
const evidence = [] as string[];
|
|
7
|
+
|
|
8
|
+
await test.step("Abrir rota alvo", async () => {
|
|
9
|
+
await page.goto(`${BASE_URL}{{routePath}}`);
|
|
10
|
+
await expect(page).toHaveURL(new RegExp("{{routeRegex}}"));
|
|
11
|
+
evidence.push("navigation");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
{{testSteps}}
|
|
15
|
+
|
|
16
|
+
await test.step("Registrar contexto final", async () => {
|
|
17
|
+
expect(evidence.length).toBeGreaterThan(0);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
## Resumo
|
|
2
|
+
|
|
3
|
+
- **Bug:** {{ORIGINAL_PROBLEM}}
|
|
4
|
+
- **Causa raiz:** {{WHY_IT_HAPPENED}}
|
|
5
|
+
- **Solução:** {{WHAT_WAS_FIXED}}
|
|
6
|
+
|
|
7
|
+
## Mudanças
|
|
8
|
+
|
|
9
|
+
{{CHANGES_LIST}}
|
|
10
|
+
|
|
11
|
+
## Evidências de Teste
|
|
12
|
+
|
|
13
|
+
- **Antes do fix:** {{SCREENSHOT_OR_ERROR_BEFORE}}
|
|
14
|
+
- **Depois do fix:** {{SCREENSHOT_OR_RETEST_PASS}}
|
|
15
|
+
- **Testes unitários relacionados:** {{TEST_LIST}}
|
|
16
|
+
|
|
17
|
+
## Plano de Teste
|
|
18
|
+
|
|
19
|
+
- [ ] Testes unitários passando
|
|
20
|
+
- [ ] Build com sucesso
|
|
21
|
+
- [ ] Lint passando
|
|
22
|
+
- [ ] Fix testado manualmente
|
|
23
|
+
- [ ] Verificado que não há regressão em features relacionadas
|
|
24
|
+
|
|
25
|
+
## Relacionados
|
|
26
|
+
|
|
27
|
+
- Issue: {{ISSUE_LINK}}
|
|
28
|
+
- Análise do bugfix: `.dw/spec/bugfix-{{NAME}}/prd.md` (se aplicável)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Credenciais de Teste QA
|
|
2
|
+
|
|
3
|
+
## Perfis de Credenciais
|
|
4
|
+
|
|
5
|
+
| Perfil | Login | Senha | Role | Escopo | Usar Quando |
|
|
6
|
+
|--------|-------|-------|------|--------|-------------|
|
|
7
|
+
| **Admin** | admin@test.com | {{PASSWORD}} | Administrador | Acesso total | Testar fluxos admin, gestão de usuários, configurações |
|
|
8
|
+
| **Usuário Padrão** | user@test.com | {{PASSWORD}} | Usuário | Acesso padrão | Testar happy paths, fluxos principais |
|
|
9
|
+
| **Restrito** | restricted@test.com | {{PASSWORD}} | Visualizador | Somente leitura | Testar bloqueios de permissão, acesso negado |
|
|
10
|
+
| **Multi-tenant A** | tenant-a@test.com | {{PASSWORD}} | Usuário | Tenant A | Testar isolamento de tenant, segregação de dados |
|
|
11
|
+
| **Multi-tenant B** | tenant-b@test.com | {{PASSWORD}} | Usuário | Tenant B | Testar bloqueio de acesso cross-tenant |
|
|
12
|
+
|
|
13
|
+
## Ordem de Fallback de Senha
|
|
14
|
+
|
|
15
|
+
Se a senha primária falhar, tente nesta ordem:
|
|
16
|
+
1. `{{PRIMARY_PASSWORD}}`
|
|
17
|
+
2. `{{FALLBACK_1}}`
|
|
18
|
+
3. `{{FALLBACK_2}}`
|
|
19
|
+
|
|
20
|
+
Se todas falharem, marcar autenticação como **BLOQUEADA** no manifesto.
|
|
21
|
+
|
|
22
|
+
## Método de Login
|
|
23
|
+
|
|
24
|
+
- **URL:** {{LOGIN_URL}}
|
|
25
|
+
- **Provedor de autenticação:** {{AUTH_PROVIDER}} (ex: Keycloak, Auth0, NextAuth)
|
|
26
|
+
- **Campo de login:** Email / Usuário / CPF (escolher baseado no provedor)
|
|
27
|
+
- **Observações:** {{NOTES}}
|
|
28
|
+
|
|
29
|
+
## Guia de Seleção
|
|
30
|
+
|
|
31
|
+
| Tipo de Bug / Fluxo | Perfil Recomendado | Motivo |
|
|
32
|
+
|---------------------|-------------------|--------|
|
|
33
|
+
| Teste de happy path | Usuário Padrão | Representa uso típico |
|
|
34
|
+
| Teste de permissão negada | Restrito | Valida controle de acesso |
|
|
35
|
+
| Funcionalidades admin | Admin | Acesso total necessário |
|
|
36
|
+
| Isolamento multi-tenant | Tenant A + Tenant B | Testa fronteiras de dados |
|
|
37
|
+
| Fluxo de auth/login | Todos os perfis | Testa cada nível de acesso |
|
|
@@ -116,7 +116,7 @@ type NomeServico interface {
|
|
|
116
116
|
|
|
117
117
|
### Conformidade com Padrões
|
|
118
118
|
|
|
119
|
-
[Pesquise as rules em
|
|
119
|
+
[Pesquise as rules em `.dw/rules/` que se encaixam nesta techspec e liste-as abaixo:]
|
|
120
120
|
|
|
121
121
|
### Arquivos Relevantes
|
|
122
122
|
|
package/scaffold/rules-readme.md
CHANGED
|
@@ -4,7 +4,7 @@ This directory contains auto-generated project rules created by the `analyze-pro
|
|
|
4
4
|
|
|
5
5
|
## How to populate
|
|
6
6
|
|
|
7
|
-
Run the `/analyze-project` command inside your AI assistant to scan your codebase and generate:
|
|
7
|
+
Run the `/dw-analyze-project` command inside your AI assistant to scan your codebase and generate:
|
|
8
8
|
|
|
9
9
|
- `index.md` — Project overview, stack summary, quick reference
|
|
10
10
|
- `{module}.md` — Per-module detailed rules with patterns and conventions
|
|
@@ -12,7 +12,7 @@ Run the `/analyze-project` command inside your AI assistant to scan your codebas
|
|
|
12
12
|
## Structure
|
|
13
13
|
|
|
14
14
|
```
|
|
15
|
-
|
|
15
|
+
.dw/rules/
|
|
16
16
|
├── README.md # This file
|
|
17
17
|
├── index.md # Project overview (auto-generated)
|
|
18
18
|
└── {module}.md # Per-module rules (auto-generated)
|
|
@@ -22,4 +22,4 @@ ai/rules/
|
|
|
22
22
|
|
|
23
23
|
These rules are automatically read by workflow commands (`create-prd`, `create-techspec`, `run-task`, etc.) to ensure generated artifacts follow your project's conventions.
|
|
24
24
|
|
|
25
|
-
Re-run `/analyze-project` whenever your stack or conventions change significantly.
|
|
25
|
+
Re-run `/dw-analyze-project` whenever your stack or conventions change significantly.
|