jarvis-ai-framework 1.0.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +66 -64
- package/README.md +24 -10
- package/agents/AGENTS.md +12 -8
- package/agents/README.md +14 -16
- package/agents/engineering/data/eng.data-engineer.agent.md +6 -6
- package/agents/engineering/eng.agent.md +19 -36
- package/agents/engineering/eng.bug-hunter.md +13 -12
- package/agents/engineering/eng.cybersecurity.agent.md +20 -35
- package/agents/engineering/eng.docs-writer.md +2 -2
- package/agents/engineering/eng.frontend.agent.md +17 -22
- package/agents/engineering/eng.rpa.agent.md +5 -15
- package/agents/engineering/qa/eng.qa.test-architect.md +4 -4
- package/agents/engineering/qa/eng.qa.test-planner.md +3 -3
- package/agents/engineering/qa/eng.qa.testing-engineer.md +3 -3
- package/agents/product/prod.discovery-interviewer.md +86 -0
- package/bin/commands/init.js +6 -6
- package/bin/jarvis.js +1 -1
- package/bin/lib/config/constants.js +47 -0
- package/bin/lib/core/sync-engine.js +12 -0
- package/package.json +2 -5
- package/rules/AGENTS.md +6 -4
- package/rules/engineering/eng-rules.md +5 -3
- package/rules/engineering/eng-security-rules.md +4 -4
- package/rules/engineering/eng.breakdown-subtasks-rules.md +208 -37
- package/rules/engineering/eng.docs-scraping-rules.md +1 -1
- package/rules/engineering/eng.downstream-flow-rules.md +1 -1
- package/rules/engineering/eng.integrations-rules.md +2 -2
- package/rules/engineering/eng.pre-pr-rules.md +1 -1
- package/rules/engineering/eng.skills-rules.md +60 -0
- package/rules/engineering/eng.specializations-rules.md +69 -0
- package/rules/engineering/eng.start-rules.md +11 -11
- package/rules/engineering/eng.work-rules.md +19 -14
- package/rules/engineering/frontend/eng.frontend-rules.md +70 -69
- package/rules/product/README.md +2 -0
- package/rules/product/prod-rules.md +7 -5
- package/{skills/prod-specs/rules/prod-spec-rules.md → rules/product/prod.spec-rules.md} +55 -50
- package/skills/AGENTS.md +111 -47
- package/skills/SKILLS-ROADMAP.md +26 -45
- package/skills/eng-ai-engineer/SKILL.md +1 -0
- package/skills/eng-backend/SKILL.md +142 -644
- package/skills/eng-backend/references/1-fundamentos-programacao.md +41 -0
- package/skills/eng-backend/references/10-seguranca.md +61 -0
- package/skills/eng-backend/references/11-performance.md +49 -0
- package/skills/eng-backend/references/12-erros-logging.md +42 -0
- package/skills/eng-backend/references/13-qualidade-codigo.md +51 -0
- package/skills/eng-backend/references/2-design-arquitetura.md +48 -0
- package/skills/eng-backend/references/3-design-patterns.md +50 -0
- package/skills/eng-backend/references/4-algoritmos-estruturas.md +43 -0
- package/skills/eng-backend/references/5-banco-dados.md +53 -0
- package/skills/eng-backend/references/6-api-comunicacao.md +42 -0
- package/skills/eng-backend/references/7-concorrencia-async.md +49 -0
- package/skills/eng-backend/references/8-arquitetura-servidor.md +49 -0
- package/skills/eng-backend/references/9-testes.md +43 -0
- package/skills/{eng-arch-c4 → eng-backend-arch-c4}/SKILL.md +12 -7
- package/skills/{eng-ms-trace → eng-backend-microservices-trace}/SKILL.md +6 -4
- package/skills/{eng-nestjs → eng-backend-nestjs}/SKILL.md +3 -1
- package/skills/{eng-rabbitmq → eng-backend-rabbitmq}/SKILL.md +3 -1
- package/skills/eng-data-bi/SKILL.md +1 -0
- package/skills/eng-data-debug/SKILL.md +2 -1
- package/skills/eng-data-engineer/SKILL.md +1 -0
- package/skills/eng-data-onboard/SKILL.md +1 -0
- package/skills/eng-data-orchestrator/SKILL.md +1 -0
- package/skills/{eng-performance-engineer → eng-devops-performance-engineer}/SKILL.md +2 -1
- package/skills/eng-frontend/SKILL.md +145 -782
- package/skills/eng-frontend/references/1-fundamentos-programacao.md +37 -0
- package/skills/eng-frontend/references/10-testes.md +47 -0
- package/skills/eng-frontend/references/11-seguranca.md +56 -0
- package/skills/eng-frontend/references/12-qualidade-codigo.md +51 -0
- package/skills/eng-frontend/references/2-html-fundamentals.md +51 -0
- package/skills/eng-frontend/references/3-css-responsive.md +61 -0
- package/skills/eng-frontend/references/4-javascript-dom.md +60 -0
- package/skills/eng-frontend/references/5-state-management.md +55 -0
- package/skills/eng-frontend/references/6-uiux-design.md +59 -0
- package/skills/eng-frontend/references/7-acessibilidade.md +46 -0
- package/skills/eng-frontend/references/8-performance.md +58 -0
- package/skills/eng-frontend/references/9-browser-apis.md +54 -0
- package/skills/{eng-design-system → eng-frontend-design-system}/SKILL.md +4 -2
- package/skills/{eng-microfrontend → eng-frontend-microfrontend}/SKILL.md +4 -2
- package/skills/{eng-browser-extension-builder → eng-global-browser-extension-builder}/SKILL.md +2 -1
- package/skills/{eng-docs-write → eng-global-docs-write}/SKILL.md +8 -4
- package/skills/eng-global-jira-comment/SKILL.md +21 -0
- package/skills/{eng-pr → eng-global-pr}/SKILL.md +7 -3
- package/skills/{eng-task-comment → eng-global-task-comment}/SKILL.md +6 -2
- package/skills/eng-qa-a11y-audit/SKILL.md +1 -0
- package/skills/eng-qa-bug-report/SKILL.md +2 -1
- package/skills/eng-qa-bug-report/TASK_MANAGERS.md +1 -1
- package/skills/eng-qa-cypress-e2e/SKILL.md +1 -0
- package/skills/eng-qa-dev-guide/SKILL.md +1 -0
- package/skills/eng-qa-e2e/SKILL.md +1 -0
- package/skills/eng-qa-e2e-spec-writer/SKILL.md +1 -0
- package/skills/eng-qa-exploratory/SKILL.md +1 -0
- package/skills/eng-qa-gate/SKILL.md +3 -2
- package/skills/eng-qa-graphql-contract/SKILL.md +1 -0
- package/skills/eng-qa-quality-report/SKILL.md +3 -2
- package/skills/eng-qa-test-plan/SKILL.md +1 -0
- package/skills/eng-qa-testsprite/SKILL.md +2 -1
- package/skills/eng-qa-unit-test/SKILL.md +1 -0
- package/skills/eng-scraper/SKILL.md +1 -0
- package/skills/eng-scraper-robot-builder/SKILL.md +1 -0
- package/skills/{eng-cybersecurity → eng-security-cybersecurity}/SKILL.md +3 -2
- package/skills/eng-security-patch/SKILL.md +6 -2
- package/skills/{eng-threat-model → eng-security-threat-model}/SKILL.md +6 -2
- package/skills/eng-security-triage/SKILL.md +4 -0
- package/skills/{context-detect → jarvis-context-detect}/SKILL.md +6 -5
- package/skills/{context-detect → jarvis-context-detect}/assets/context-profile-template.md +3 -3
- package/skills/jarvis-create-specialization/SKILL.md +230 -0
- package/skills/jarvis-create-specialization/assets/referencia-template.md +39 -0
- package/skills/jarvis-create-specialization/assets/skill-especializacao-template.md +78 -0
- package/skills/{docs-central → jarvis-docs-central}/README.md +1 -1
- package/skills/{docs-central → jarvis-docs-central}/SKILL.md +3 -40
- package/skills/{docs-index → jarvis-docs-index}/SKILL.md +8 -4
- package/skills/{init-jarvis → jarvis-init}/SKILL.md +42 -19
- package/skills/{init-jarvis → jarvis-init}/assets/mcp-configs.md +3 -3
- package/skills/{init-jarvis → jarvis-init}/assets/onboarding-checklist.md +1 -1
- package/skills/jarvis-init/assets/passo-adicionar-stacks.md +163 -0
- package/skills/{init-jarvis → jarvis-init}/assets/setup-guide.md +1 -1
- package/skills/jarvis-init/assets/sinais-de-stack.md +54 -0
- package/skills/jarvis-list-specializations/SKILL.md +148 -0
- package/skills/{report-issue → jarvis-report-issue}/SKILL.md +3 -2
- package/skills/{prod-roadmap-report → product-roadmap-report}/SKILL.md +2 -1
- package/skills/product-specs/SKILL.md +45 -0
- package/skills/{prod-specs-update → product-specs-update}/SKILL.md +3 -2
- package/taxonomy.md +3 -21
- package/templates/AGENTS.md +7 -6
- package/templates/CDD aplicado a Prompts.md +5 -5
- package/templates/ENV-template.md +12 -9
- package/templates/engineering/AGENTS-template.md +1 -1
- package/templates/engineering/CONTACTS-template.md +1 -1
- package/templates/product/prod-discovery-template.md +98 -0
- package/{skills/prod-specs/templates → templates/product}/prod-epic-template.md +1 -0
- package/{skills/prod-specs/templates → templates/product}/prod-frd-template.md +1 -0
- package/{skills/prod-specs/templates → templates/product}/prod-issue-template.md +1 -0
- package/{skills/prod-specs/templates → templates/product}/prod-prd-template.md +1 -0
- package/workflows/AGENTS.md +3 -1
- package/workflows/README.md +2 -0
- package/workflows/engineering/eng.bug-audit.md +2 -2
- package/workflows/engineering/eng.build-tech-spec.md +38 -49
- package/workflows/engineering/eng.debug.md +10 -10
- package/workflows/engineering/eng.docs.md +2 -2
- package/workflows/engineering/eng.plan.md +5 -5
- package/workflows/engineering/eng.pr.md +8 -8
- package/workflows/engineering/eng.pre-pr.md +16 -20
- package/workflows/engineering/eng.review.md +5 -10
- package/workflows/engineering/eng.rpa.robot.md +3 -3
- package/workflows/engineering/eng.security-audit.md +5 -5
- package/workflows/engineering/eng.security-incident.md +2 -2
- package/workflows/engineering/eng.security-pipeline.md +2 -2
- package/workflows/engineering/eng.start.md +16 -50
- package/workflows/engineering/eng.work.md +9 -12
- package/workflows/engineering/frontend/eng.frontend-component.md +68 -96
- package/workflows/engineering/frontend/eng.frontend-perf-audit.md +90 -220
- package/workflows/engineering/frontend/eng.frontend-review.md +57 -63
- package/workflows/engineering/qa/eng.qa-quality-report.md +0 -5
- package/workflows/product/prod.roadmap.preview.md +2 -2
- package/workflows/product/prod.spec.breakdown.md +3 -8
- package/workflows/product/prod.spec.discovery.md +152 -0
- package/workflows/product/prod.spec.epic.md +3 -0
- package/workflows/product/prod.spec.frd.md +123 -8
- package/workflows/product/prod.spec.issue.md +3 -2
- package/workflows/product/prod.spec.md +2 -0
- package/workflows/product/prod.spec.prd.md +105 -6
- package/workflows/taxonomy.md +1 -1
- package/workflows/warm-up.md +5 -26
- package/agents/engineering/eng.tech-analyst.agent.md +0 -102
- package/skills/churn-audit/SKILL.md +0 -385
- package/skills/eng-jira-comment/SKILL.md +0 -17
- package/skills/eng-tech-analyst/SKILL.md +0 -529
- package/skills/lovable-prompt-generator/SKILL.md +0 -304
- package/skills/prod-specs/SKILL.md +0 -108
- package/skills/prod-specs/references/prod.spec.clarify.md +0 -176
- package/skills/prod-specs/references/prod.spec.epic.md +0 -107
- package/skills/prod-specs/references/prod.spec.frd.md +0 -135
- package/skills/prod-specs/references/prod.spec.issue.md +0 -145
- package/skills/prod-specs/references/prod.spec.prd.md +0 -118
- package/skills/prod-specs/templates/prod-prd-full-template.md +0 -159
- package/workflows/engineering/ta/eng.ta.atendimento.md +0 -93
- /package/skills/{eng-arch-c4 → eng-backend-arch-c4}/assets/example-code.md +0 -0
- /package/skills/{eng-arch-c4 → eng-backend-arch-c4}/assets/example-component.md +0 -0
- /package/skills/{eng-arch-c4 → eng-backend-arch-c4}/assets/example-container.md +0 -0
- /package/skills/{eng-arch-c4 → eng-backend-arch-c4}/assets/example-context.md +0 -0
- /package/skills/{prod-roadmap-report → product-roadmap-report}/README.md +0 -0
- /package/skills/{prod-roadmap-report → product-roadmap-report}/commands/status.compiled.single.team.md +0 -0
- /package/skills/{prod-roadmap-report → product-roadmap-report}/commands/status.list.projects.md +0 -0
- /package/skills/{prod-roadmap-report → product-roadmap-report}/commands/status.memory.md +0 -0
- /package/skills/{prod-roadmap-report → product-roadmap-report}/commands/status.roadmap.preview.md +0 -0
- /package/skills/{prod-roadmap-report → product-roadmap-report}/references/detailed-guide.md +0 -0
- /package/skills/{prod-roadmap-report → product-roadmap-report}/rules/detailed-guide.md +0 -0
- /package/skills/{prod-roadmap-report → product-roadmap-report}/rules/status-report-rules.md +0 -0
- /package/skills/{prod-roadmap-report → product-roadmap-report}/templates/template-multiple-teams-compiled-status.md +0 -0
- /package/skills/{prod-roadmap-report → product-roadmap-report}/templates/template-projects-list.md +0 -0
- /package/skills/{prod-roadmap-report → product-roadmap-report}/templates/template-single-team-compiled-status.md +0 -0
- /package/skills/{prod-roadmap-report → product-roadmap-report}/templates/template-single-team-status.md +0 -0
- /package/{skills/prod-specs/templates → templates/product}/prod-breakdown-template.md +0 -0
|
@@ -1,891 +1,242 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: eng-frontend
|
|
3
3
|
description: >
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
Skill base de desenvolvimento frontend para a plataforma web, válida em qualquer framework:
|
|
5
|
+
HTML semântico, CSS e design responsivo, JavaScript e DOM, estado e componentes, UI e UX,
|
|
6
|
+
acessibilidade, performance, APIs do navegador, testes e segurança do cliente.
|
|
7
|
+
Pode ser complementada por skills especializados de uma stack.
|
|
8
|
+
Trigger: Use para componentes, interface, estado, bundle, renderização, Core Web Vitals,
|
|
9
|
+
acessibilidade (WCAG), design system, testes de interface ou frontend em geral.
|
|
8
10
|
license: AGPL-3.0
|
|
9
11
|
compatibility: Designed for Claude Code (or similar products)
|
|
10
12
|
allowed-tools: Read Write Edit Glob Grep Bash
|
|
11
13
|
metadata:
|
|
12
14
|
author: jarvis-team
|
|
13
|
-
version: "
|
|
15
|
+
version: "2.0"
|
|
16
|
+
area: frontend
|
|
14
17
|
# Campos Claude Code-specific (não fazem parte da spec oficial agentskills.io):
|
|
15
|
-
argument-hint: "[
|
|
18
|
+
argument-hint: "[componente|feature|problema|performance|acessibilidade|estado] [contexto]"
|
|
16
19
|
disable-model-invocation: false
|
|
17
20
|
---
|
|
18
21
|
|
|
19
|
-
# Eng Frontend -
|
|
22
|
+
# Eng Frontend - Skill Base de Desenvolvimento de Interface
|
|
20
23
|
|
|
21
|
-
Você é
|
|
22
|
-
|
|
23
|
-
- **Frontend React**: React 19 + Next.js 15 App Router (SPA/SSR/RSC)
|
|
24
|
-
- **Frontend PHP**: Laravel Blade templates + JavaScript via Babel (SSR clássico)
|
|
24
|
+
Você é uma **pessoa desenvolvedora frontend sênior**, com domínio dos princípios que valem em qualquer framework: HTML semântico, CSS, JavaScript e DOM, acessibilidade, performance, testes e segurança do cliente.
|
|
25
25
|
|
|
26
26
|
## Objetivo
|
|
27
27
|
|
|
28
|
-
Construir interfaces corretas, performáticas e acessíveis em
|
|
29
|
-
|
|
30
|
-
## Contextos de Frontend do Projeto
|
|
31
|
-
|
|
32
|
-
| Contexto | Stack | Quando usar |
|
|
33
|
-
|----------|-------|-------------|
|
|
34
|
-
| **React** | React 19, Next.js 15, TypeScript, Tailwind, Zustand, React Query | SPAs, SSR com RSC, dashboards, apps interativos |
|
|
35
|
-
| **PHP/Blade** | Laravel Blade, PHP, Babel, JavaScript (sem bundler moderno ou com Laravel Mix/Vite) | Páginas server-rendered clássicas, apps Laravel existentes |
|
|
28
|
+
Construir interfaces corretas, performáticas e acessíveis, com foco em qualidade, manutenibilidade e experiência de quem usa. Este skill não presume um framework: ele descobre o framework e o sistema de estilos do projeto pelo próprio código e segue o padrão que encontra.
|
|
36
29
|
|
|
37
30
|
## Entrada
|
|
38
31
|
|
|
39
|
-
- `$ARGUMENTS` - Componente,
|
|
32
|
+
- `$ARGUMENTS` - Componente, funcionalidade, problema ou objetivo de frontend (ex: `criar-componente-tabela`, `otimizar-bundle`, `corrigir-acessibilidade`, `melhorar-formulario`)
|
|
40
33
|
|
|
41
34
|
## Recursos
|
|
42
35
|
|
|
43
36
|
- **ENV**: `$IDE/ENV.md` (variáveis e configurações do projeto)
|
|
37
|
+
- **Base universal**: os 12 temas em [references/](references/), carregados sob demanda
|
|
44
38
|
- **Saída**: código e testes no repositório atual
|
|
45
39
|
|
|
46
40
|
---
|
|
47
41
|
|
|
48
42
|
## Pré-requisito
|
|
49
43
|
|
|
50
|
-
Verificar se o `ENV.md` existe e está completo antes de executar
|
|
44
|
+
Verificar se o `ENV.md` existe e está completo antes de executar:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
cat $IDE/ENV.md
|
|
48
|
+
```
|
|
51
49
|
|
|
52
50
|
---
|
|
53
51
|
|
|
54
52
|
## Quando Usar
|
|
55
53
|
|
|
56
54
|
Use este skill quando:
|
|
57
|
-
- Criar ou refatorar componentes
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
- Otimizar
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
- Escrever testes de frontend (Vitest, Testing Library, Playwright, Dusk)
|
|
55
|
+
- Criar ou refatorar componentes e telas
|
|
56
|
+
- Estruturar HTML e CSS, inclusive layout responsivo
|
|
57
|
+
- Implementar interatividade com JavaScript e o DOM
|
|
58
|
+
- Gerenciar estado e o fluxo de dados da interface
|
|
59
|
+
- Otimizar o desempenho da interface (carregamento, renderização, Core Web Vitals)
|
|
60
|
+
- Revisar ou implementar acessibilidade (WCAG, ARIA, semântica, teclado)
|
|
61
|
+
- Construir ou evoluir um design system (componentes e tokens)
|
|
62
|
+
- Escrever testes de interface e tratar a segurança do lado do cliente
|
|
66
63
|
|
|
67
64
|
**NÃO usar quando:**
|
|
68
65
|
- A tarefa é exclusivamente de backend, banco de dados ou infraestrutura
|
|
69
|
-
- Não há contexto de interface
|
|
66
|
+
- Não há contexto de interface envolvido
|
|
70
67
|
|
|
71
68
|
---
|
|
72
69
|
|
|
73
70
|
## Validação de Entrada
|
|
74
71
|
|
|
75
|
-
Se
|
|
72
|
+
Se `$ARGUMENTS` está vazio, o skill funciona em modo interativo: pergunte à pessoa o contexto da tarefa de frontend antes de prosseguir.
|
|
76
73
|
|
|
77
74
|
---
|
|
78
75
|
|
|
79
76
|
## Padrões Críticos
|
|
80
77
|
|
|
81
|
-
### Padrão 1:
|
|
82
|
-
|
|
83
|
-
Antes de implementar, entender o contexto:
|
|
84
|
-
|
|
85
|
-
```
|
|
86
|
-
1. Qual o framework do projeto? (React, Next.js, Vue, Svelte)
|
|
87
|
-
2. Qual o sistema de estilização? (Tailwind, CSS Modules, Styled Components)
|
|
88
|
-
3. Existe design system já em uso?
|
|
89
|
-
4. Qual a estratégia de estado? (local, global, server state)
|
|
90
|
-
5. Qual o target de acessibilidade? (WCAG 2.1 AA por padrão)
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### Padrão 2: Performance por Padrão
|
|
94
|
-
|
|
95
|
-
Nunca ignorar performance. Sempre considerar:
|
|
96
|
-
|
|
97
|
-
```
|
|
98
|
-
- Code splitting → dynamic imports, lazy loading de rotas e componentes pesados
|
|
99
|
-
- Bundle size → analisar impacto de novas dependências antes de adicionar
|
|
100
|
-
- Rendering strategy → SSR/SSG/ISR para Next.js, hidratação parcial quando possível
|
|
101
|
-
- Imagens → next/image ou lazy loading nativo, formatos modernos (WebP, AVIF)
|
|
102
|
-
- Core Web Vitals → LCP < 2.5s, FID < 100ms, CLS < 0.1
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Padrão 3: Acessibilidade Não é Opcional
|
|
78
|
+
### Padrão 1: Entender o contexto antes de implementar
|
|
106
79
|
|
|
107
|
-
|
|
80
|
+
Antes de escrever, descubra como o projeto já funciona:
|
|
108
81
|
|
|
109
82
|
```
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
83
|
+
1. Qual é o framework (ou a ausência dele)? (pelos arquivos de manifesto e de dependências)
|
|
84
|
+
2. Qual é o sistema de estilos em uso?
|
|
85
|
+
3. Existe um design system ou uma biblioteca de componentes?
|
|
86
|
+
4. Qual é a estratégia de estado? (local, global, dados do servidor)
|
|
87
|
+
5. Qual é a meta de acessibilidade? (WCAG 2.1 AA por padrão)
|
|
115
88
|
```
|
|
116
89
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
```
|
|
120
|
-
- Testing Library → testar comportamento, não implementação
|
|
121
|
-
- Queries por acessibilidade → getByRole, getByLabelText (não getByTestId como primeiro recurso)
|
|
122
|
-
- Playwright → e2e para fluxos críticos de usuário
|
|
123
|
-
- Vitest → unitários para lógica pura e hooks
|
|
124
|
-
```
|
|
90
|
+
Siga o padrão existente do projeto, **não** o padrão genérico deste skill. Se não conseguir identificar o framework, pergunte antes de prosseguir.
|
|
125
91
|
|
|
126
|
-
|
|
92
|
+
### Padrão 2: Performance por padrão
|
|
127
93
|
|
|
128
|
-
|
|
94
|
+
Nunca ignore a performance. Considere sempre:
|
|
129
95
|
|
|
130
96
|
```
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
│ ├── Problema de performance? → Seção: Otimização de Performance
|
|
137
|
-
│ ├── Problema de acessibilidade? → Seção: Acessibilidade
|
|
138
|
-
│ ├── Gerenciar estado? → Seção: Gerenciamento de Estado
|
|
139
|
-
│ ├── Criar/expandir design system? → Seção: Design System
|
|
140
|
-
│ └── Escrever testes? → Seção: Testes
|
|
141
|
-
└── PHP / Blade
|
|
142
|
-
├── Criar/modificar layout ou partial? → Seção: PHP/Blade — Templates e Layouts
|
|
143
|
-
├── Adicionar interatividade com JS? → Seção: PHP/Blade — JavaScript com Babel
|
|
144
|
-
├── Gerenciar assets (CSS/JS)? → Seção: PHP/Blade — Build com Laravel Vite/Mix
|
|
145
|
-
└── Submissão de formulários? → Seção: PHP/Blade — Formulários e CSRF
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
---
|
|
149
|
-
|
|
150
|
-
## Fluxo de Trabalho
|
|
151
|
-
|
|
152
|
-
### 1. Ler o Contexto do Projeto
|
|
153
|
-
|
|
154
|
-
```bash
|
|
155
|
-
# Verificar framework e dependências principais
|
|
156
|
-
cat package.json | grep -E '"react|next|vue|svelte|tailwind|zustand|redux|vitest|playwright"'
|
|
157
|
-
|
|
158
|
-
# Verificar estrutura de componentes
|
|
159
|
-
ls src/components/ 2>/dev/null || ls components/ 2>/dev/null
|
|
160
|
-
|
|
161
|
-
# Verificar configuração de estilos
|
|
162
|
-
ls tailwind.config* 2>/dev/null
|
|
97
|
+
- Divisão de código → carregamento sob demanda de rotas e de componentes pesados
|
|
98
|
+
- Tamanho do pacote → medir o impacto antes de adicionar uma dependência
|
|
99
|
+
- Estratégia de renderização → a mais simples que atenda ao caso
|
|
100
|
+
- Imagens → dimensões definidas, carregamento sob demanda e formatos modernos
|
|
101
|
+
- Core Web Vitals → LCP < 2,5 s, CLS < 0,1 e INP < 200 ms
|
|
163
102
|
```
|
|
164
103
|
|
|
165
|
-
###
|
|
104
|
+
### Padrão 3: Acessibilidade não é opcional
|
|
166
105
|
|
|
167
|
-
|
|
168
|
-
- Padrões de nomenclatura em uso
|
|
169
|
-
- Como outros componentes são estruturados
|
|
170
|
-
- Onde o estado é gerenciado
|
|
171
|
-
- Quais utilitários/hooks já existem
|
|
172
|
-
|
|
173
|
-
---
|
|
174
|
-
|
|
175
|
-
## React 19 — RSC e Server Actions
|
|
176
|
-
|
|
177
|
-
### Server Components vs Client Components
|
|
178
|
-
|
|
179
|
-
```tsx
|
|
180
|
-
// ✅ Server Component (padrão no App Router — sem 'use client')
|
|
181
|
-
// Pode fazer fetch direto, acessar DB, ler env vars
|
|
182
|
-
export default async function ProductList() {
|
|
183
|
-
const products = await db.product.findMany() // fetch no servidor
|
|
184
|
-
return <ul>{products.map(p => <li key={p.id}>{p.name}</li>)}</ul>
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// ✅ Client Component — somente quando necessário
|
|
188
|
-
'use client'
|
|
189
|
-
import { useState } from 'react'
|
|
190
|
-
|
|
191
|
-
export function AddToCartButton({ productId }: { productId: string }) {
|
|
192
|
-
const [loading, setLoading] = useState(false)
|
|
193
|
-
return <button onClick={() => handleAdd(productId, setLoading)}>Adicionar</button>
|
|
194
|
-
}
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
**Regra**: componentes são Server por padrão. Usar `'use client'` somente quando:
|
|
198
|
-
- Usa hooks React (`useState`, `useEffect`, `useRef`, etc.)
|
|
199
|
-
- Usa eventos do browser (`onClick`, `onChange`, etc.)
|
|
200
|
-
- Usa APIs do browser (`localStorage`, `window`, etc.)
|
|
201
|
-
|
|
202
|
-
### Server Actions
|
|
203
|
-
|
|
204
|
-
```tsx
|
|
205
|
-
// app/actions/product.ts
|
|
206
|
-
'use server'
|
|
207
|
-
import { revalidatePath } from 'next/cache'
|
|
208
|
-
|
|
209
|
-
export async function createProduct(formData: FormData) {
|
|
210
|
-
const name = formData.get('name') as string
|
|
211
|
-
await db.product.create({ data: { name } })
|
|
212
|
-
revalidatePath('/products')
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Uso no componente (Server ou Client)
|
|
216
|
-
import { createProduct } from '@/app/actions/product'
|
|
217
|
-
|
|
218
|
-
export function ProductForm() {
|
|
219
|
-
return (
|
|
220
|
-
<form action={createProduct}>
|
|
221
|
-
<input name="name" required />
|
|
222
|
-
<button type="submit">Criar</button>
|
|
223
|
-
</form>
|
|
224
|
-
)
|
|
225
|
-
}
|
|
226
|
-
```
|
|
106
|
+
Toda interface deve ser acessível por padrão:
|
|
227
107
|
|
|
228
|
-
### Hooks avançados React 19
|
|
229
|
-
|
|
230
|
-
```tsx
|
|
231
|
-
// useActionState — estado de form com Server Actions
|
|
232
|
-
'use client'
|
|
233
|
-
import { useActionState } from 'react'
|
|
234
|
-
import { createProduct } from '@/app/actions/product'
|
|
235
|
-
|
|
236
|
-
export function ProductForm() {
|
|
237
|
-
const [state, action, isPending] = useActionState(createProduct, null)
|
|
238
|
-
return (
|
|
239
|
-
<form action={action}>
|
|
240
|
-
<input name="name" required />
|
|
241
|
-
<button disabled={isPending}>{isPending ? 'Salvando...' : 'Criar'}</button>
|
|
242
|
-
{state?.error && <p role="alert">{state.error}</p>}
|
|
243
|
-
</form>
|
|
244
|
-
)
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// useOptimistic — UI otimista
|
|
248
|
-
'use client'
|
|
249
|
-
import { useOptimistic } from 'react'
|
|
250
|
-
|
|
251
|
-
export function LikeButton({ count, onLike }: { count: number; onLike: () => Promise<void> }) {
|
|
252
|
-
const [optimisticCount, addOptimistic] = useOptimistic(count, (state) => state + 1)
|
|
253
|
-
return (
|
|
254
|
-
<button onClick={async () => {
|
|
255
|
-
addOptimistic(null)
|
|
256
|
-
await onLike()
|
|
257
|
-
}}>
|
|
258
|
-
❤️ {optimisticCount}
|
|
259
|
-
</button>
|
|
260
|
-
)
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// useTransition — manter UI responsiva durante atualizações lentas
|
|
264
|
-
'use client'
|
|
265
|
-
import { useTransition } from 'react'
|
|
266
|
-
|
|
267
|
-
export function FilterPanel({ onFilter }: { onFilter: (value: string) => void }) {
|
|
268
|
-
const [isPending, startTransition] = useTransition()
|
|
269
|
-
return (
|
|
270
|
-
<input
|
|
271
|
-
onChange={(e) => startTransition(() => onFilter(e.target.value))}
|
|
272
|
-
placeholder={isPending ? 'Filtrando...' : 'Filtrar...'}
|
|
273
|
-
/>
|
|
274
|
-
)
|
|
275
|
-
}
|
|
276
108
|
```
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
### Padrão React (TypeScript)
|
|
283
|
-
|
|
284
|
-
```tsx
|
|
285
|
-
// ✅ Componente bem estruturado
|
|
286
|
-
interface ButtonProps {
|
|
287
|
-
label: string
|
|
288
|
-
variant?: 'primary' | 'secondary' | 'ghost'
|
|
289
|
-
size?: 'sm' | 'md' | 'lg'
|
|
290
|
-
disabled?: boolean
|
|
291
|
-
onClick?: () => void
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
export function Button({
|
|
295
|
-
label,
|
|
296
|
-
variant = 'primary',
|
|
297
|
-
size = 'md',
|
|
298
|
-
disabled = false,
|
|
299
|
-
onClick,
|
|
300
|
-
}: ButtonProps) {
|
|
301
|
-
return (
|
|
302
|
-
<button
|
|
303
|
-
type="button"
|
|
304
|
-
disabled={disabled}
|
|
305
|
-
onClick={onClick}
|
|
306
|
-
aria-label={label}
|
|
307
|
-
className={cn(
|
|
308
|
-
'rounded font-medium transition-colors focus-visible:outline-none focus-visible:ring-2',
|
|
309
|
-
variants[variant],
|
|
310
|
-
sizes[size],
|
|
311
|
-
disabled && 'opacity-50 cursor-not-allowed'
|
|
312
|
-
)}
|
|
313
|
-
>
|
|
314
|
-
{label}
|
|
315
|
-
</button>
|
|
316
|
-
)
|
|
317
|
-
}
|
|
109
|
+
- Semântica HTML → usar o elemento certo (botão, navegação, principal, artigo)
|
|
110
|
+
- ARIA → somente quando a semântica nativa não basta
|
|
111
|
+
- Teclado → todos os fluxos navegáveis pelo teclado, com foco visível
|
|
112
|
+
- Contraste → WCAG AA no mínimo (4,5:1 para texto normal, 3:1 para texto grande)
|
|
113
|
+
- Leitores de tela → testar em funcionalidades críticas
|
|
318
114
|
```
|
|
319
115
|
|
|
320
|
-
###
|
|
116
|
+
### Padrão 4: Testes como documentação
|
|
321
117
|
|
|
322
|
-
-
|
|
323
|
-
-
|
|
324
|
-
-
|
|
325
|
-
- [ ] Estados visuais: normal, hover, focus, disabled, loading
|
|
326
|
-
- [ ] `aria-label` ou texto visível acessível
|
|
327
|
-
- [ ] Responsivo (mobile-first com Tailwind)
|
|
328
|
-
- [ ] Testável (sem lógica de negócio acoplada)
|
|
118
|
+
- Testar o **comportamento**, não a implementação
|
|
119
|
+
- Localizar elementos pelo papel e pelo rótulo acessível, não por identificadores de teste, como primeira opção
|
|
120
|
+
- Fluxos críticos de ponta a ponta; lógica pura com testes unitários
|
|
329
121
|
|
|
330
122
|
---
|
|
331
123
|
|
|
332
|
-
##
|
|
333
|
-
|
|
334
|
-
### Quando usar cada abordagem
|
|
335
|
-
|
|
336
|
-
| Situação | Solução |
|
|
337
|
-
|----------|---------|
|
|
338
|
-
| Estado local do componente | `useState`, `useReducer` |
|
|
339
|
-
| Estado compartilhado entre poucos componentes | Lift state up + props |
|
|
340
|
-
| Estado global simples | Zustand |
|
|
341
|
-
| Estado global complexo com devtools | Redux Toolkit |
|
|
342
|
-
| Dados do servidor (fetch, cache, mutations) | React Query / TanStack Query |
|
|
343
|
-
| Estado de URL | `useSearchParams`, `useRouter` |
|
|
344
|
-
|
|
345
|
-
### Zustand — padrão recomendado para estado global simples
|
|
346
|
-
|
|
347
|
-
```typescript
|
|
348
|
-
import { create } from 'zustand'
|
|
349
|
-
|
|
350
|
-
interface UserStore {
|
|
351
|
-
user: User | null
|
|
352
|
-
setUser: (user: User) => void
|
|
353
|
-
clearUser: () => void
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
export const useUserStore = create<UserStore>((set) => ({
|
|
357
|
-
user: null,
|
|
358
|
-
setUser: (user) => set({ user }),
|
|
359
|
-
clearUser: () => set({ user: null }),
|
|
360
|
-
}))
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
### React Query — padrão para dados do servidor
|
|
364
|
-
|
|
365
|
-
```typescript
|
|
366
|
-
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
|
367
|
-
|
|
368
|
-
export function useProducts() {
|
|
369
|
-
return useQuery({
|
|
370
|
-
queryKey: ['products'],
|
|
371
|
-
queryFn: fetchProducts,
|
|
372
|
-
staleTime: 5 * 60 * 1000, // 5 minutos
|
|
373
|
-
})
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
export function useCreateProduct() {
|
|
377
|
-
const queryClient = useQueryClient()
|
|
378
|
-
|
|
379
|
-
return useMutation({
|
|
380
|
-
mutationFn: createProduct,
|
|
381
|
-
onSuccess: () => {
|
|
382
|
-
queryClient.invalidateQueries({ queryKey: ['products'] })
|
|
383
|
-
},
|
|
384
|
-
})
|
|
385
|
-
}
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
---
|
|
389
|
-
|
|
390
|
-
## Otimização de Performance
|
|
391
|
-
|
|
392
|
-
### Análise de Bundle
|
|
393
|
-
|
|
394
|
-
```bash
|
|
395
|
-
# Next.js — analisar bundle
|
|
396
|
-
ANALYZE=true npm run build
|
|
397
|
-
|
|
398
|
-
# Vite — usar rollup-plugin-visualizer
|
|
399
|
-
npx vite-bundle-visualizer
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
### Code Splitting e Lazy Loading
|
|
403
|
-
|
|
404
|
-
```tsx
|
|
405
|
-
// ✅ Lazy loading de componentes pesados
|
|
406
|
-
import { lazy, Suspense } from 'react'
|
|
407
|
-
|
|
408
|
-
const HeavyChart = lazy(() => import('./HeavyChart'))
|
|
409
|
-
const RichTextEditor = lazy(() => import('./RichTextEditor'))
|
|
410
|
-
|
|
411
|
-
function Dashboard() {
|
|
412
|
-
return (
|
|
413
|
-
<Suspense fallback={<Skeleton />}>
|
|
414
|
-
<HeavyChart />
|
|
415
|
-
</Suspense>
|
|
416
|
-
)
|
|
417
|
-
}
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
### Memoização — usar com critério
|
|
421
|
-
|
|
422
|
-
```tsx
|
|
423
|
-
// ✅ Memo justificado: componente com re-renders caros e props estáveis
|
|
424
|
-
const DataTable = memo(({ rows, columns }: DataTableProps) => {
|
|
425
|
-
// renderização pesada
|
|
426
|
-
})
|
|
124
|
+
## Base ou especialização?
|
|
427
125
|
|
|
428
|
-
|
|
429
|
-
const handleRowClick = useCallback((id: string) => {
|
|
430
|
-
navigate(`/item/${id}`)
|
|
431
|
-
}, [navigate])
|
|
126
|
+
Pergunta-chave para decidir onde um conhecimento mora:
|
|
432
127
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
() => rows.filter((r) => r.status === activeFilter),
|
|
436
|
-
[rows, activeFilter]
|
|
437
|
-
)
|
|
438
|
-
|
|
439
|
-
// ❌ Evitar: memo/useCallback sem necessidade comprovada → overhead desnecessário
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
### Core Web Vitals — checklist
|
|
443
|
-
|
|
444
|
-
```
|
|
445
|
-
LCP (Largest Contentful Paint) < 2.5s:
|
|
446
|
-
- Pré-carregar imagens acima da dobra (priority no next/image)
|
|
447
|
-
- Evitar render-blocking resources
|
|
448
|
-
- Server-render conteúdo principal (SSR/SSG)
|
|
449
|
-
|
|
450
|
-
CLS (Cumulative Layout Shift) < 0.1:
|
|
451
|
-
- Sempre definir width/height em imagens
|
|
452
|
-
- Reservar espaço para elementos dinâmicos (skeleton loaders)
|
|
453
|
-
- Evitar inserir conteúdo acima de conteúdo existente
|
|
454
|
-
|
|
455
|
-
FID/INP (Interaction to Next Paint) < 200ms:
|
|
456
|
-
- Evitar JavaScript longo no main thread
|
|
457
|
-
- Usar web workers para processamento pesado
|
|
458
|
-
- Debounce em inputs e scroll handlers
|
|
459
|
-
```
|
|
128
|
+
> **Esse conhecimento continua válido quando eu mudo de framework?**
|
|
129
|
+
> **Sim** → pertence à base universal (este skill). **Não** → pertence a uma especialização de stack.
|
|
460
130
|
|
|
461
131
|
---
|
|
462
132
|
|
|
463
|
-
##
|
|
464
|
-
|
|
465
|
-
### Semântica HTML — usar sempre
|
|
466
|
-
|
|
467
|
-
```html
|
|
468
|
-
<!-- ✅ Semântica correta -->
|
|
469
|
-
<main>
|
|
470
|
-
<article>
|
|
471
|
-
<header>
|
|
472
|
-
<h1>Título principal</h1>
|
|
473
|
-
</header>
|
|
474
|
-
<section aria-label="Resumo">
|
|
475
|
-
<p>Conteúdo</p>
|
|
476
|
-
</section>
|
|
477
|
-
</article>
|
|
478
|
-
<nav aria-label="Paginação">
|
|
479
|
-
<a href="/pagina/1">Próxima página</a>
|
|
480
|
-
</nav>
|
|
481
|
-
</main>
|
|
482
|
-
|
|
483
|
-
<!-- ❌ Evitar: divs para tudo -->
|
|
484
|
-
<div class="main">
|
|
485
|
-
<div class="article">
|
|
486
|
-
<div class="title">Título principal</div>
|
|
487
|
-
</div>
|
|
488
|
-
</div>
|
|
489
|
-
```
|
|
490
|
-
|
|
491
|
-
### ARIA — somente quando necessário
|
|
492
|
-
|
|
493
|
-
```tsx
|
|
494
|
-
// ✅ Modal com ARIA correto
|
|
495
|
-
<div
|
|
496
|
-
role="dialog"
|
|
497
|
-
aria-modal="true"
|
|
498
|
-
aria-labelledby="modal-title"
|
|
499
|
-
aria-describedby="modal-description"
|
|
500
|
-
>
|
|
501
|
-
<h2 id="modal-title">Confirmar ação</h2>
|
|
502
|
-
<p id="modal-description">Esta ação não pode ser desfeita.</p>
|
|
503
|
-
</div>
|
|
504
|
-
|
|
505
|
-
// ✅ Botão com ícone sem texto visível
|
|
506
|
-
<button aria-label="Fechar modal" onClick={onClose}>
|
|
507
|
-
<XIcon aria-hidden="true" />
|
|
508
|
-
</button>
|
|
509
|
-
```
|
|
510
|
-
|
|
511
|
-
### Navegação por teclado
|
|
512
|
-
|
|
513
|
-
```tsx
|
|
514
|
-
// ✅ Focus trap em modais
|
|
515
|
-
import { FocusTrap } from '@headlessui/react'
|
|
516
|
-
|
|
517
|
-
// ✅ Ordem de foco lógica (tabIndex apenas quando necessário)
|
|
518
|
-
// ✅ Skip links para conteúdo principal
|
|
519
|
-
<a href="#main-content" className="sr-only focus:not-sr-only">
|
|
520
|
-
Pular para o conteúdo principal
|
|
521
|
-
</a>
|
|
522
|
-
```
|
|
523
|
-
|
|
524
|
-
---
|
|
133
|
+
## Árvore de Decisão
|
|
525
134
|
|
|
526
|
-
## Design System
|
|
527
|
-
|
|
528
|
-
### Estrutura de tokens com Tailwind
|
|
529
|
-
|
|
530
|
-
```javascript
|
|
531
|
-
// tailwind.config.js
|
|
532
|
-
module.exports = {
|
|
533
|
-
theme: {
|
|
534
|
-
extend: {
|
|
535
|
-
colors: {
|
|
536
|
-
brand: {
|
|
537
|
-
50: '#eff6ff',
|
|
538
|
-
500: '#3b82f6',
|
|
539
|
-
900: '#1e3a8a',
|
|
540
|
-
},
|
|
541
|
-
},
|
|
542
|
-
fontFamily: {
|
|
543
|
-
sans: ['Inter var', ...defaultTheme.fontFamily.sans],
|
|
544
|
-
},
|
|
545
|
-
spacing: {
|
|
546
|
-
18: '4.5rem',
|
|
547
|
-
88: '22rem',
|
|
548
|
-
},
|
|
549
|
-
},
|
|
550
|
-
},
|
|
551
|
-
}
|
|
552
135
|
```
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
primary: 'bg-brand-500 text-white hover:bg-brand-600',
|
|
565
|
-
secondary: 'border border-gray-300 bg-white text-gray-700 hover:bg-gray-50',
|
|
566
|
-
ghost: 'text-gray-700 hover:bg-gray-100',
|
|
567
|
-
destructive: 'bg-red-500 text-white hover:bg-red-600',
|
|
568
|
-
},
|
|
569
|
-
size: {
|
|
570
|
-
sm: 'h-8 px-3 text-sm',
|
|
571
|
-
md: 'h-10 px-4',
|
|
572
|
-
lg: 'h-12 px-6 text-lg',
|
|
573
|
-
},
|
|
574
|
-
},
|
|
575
|
-
defaultVariants: {
|
|
576
|
-
variant: 'primary',
|
|
577
|
-
size: 'md',
|
|
578
|
-
},
|
|
579
|
-
}
|
|
580
|
-
)
|
|
581
|
-
|
|
582
|
-
export interface ButtonProps
|
|
583
|
-
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
584
|
-
VariantProps<typeof button> {}
|
|
585
|
-
|
|
586
|
-
export function Button({ variant, size, className, ...props }: ButtonProps) {
|
|
587
|
-
return <button className={cn(button({ variant, size }), className)} {...props} />
|
|
588
|
-
}
|
|
136
|
+
Estruturar a página ou o conteúdo? → tema 2 (HTML) e tema 7 (acessibilidade)
|
|
137
|
+
Estilizar, alinhar ou tornar responsivo? → tema 3 (CSS e design responsivo)
|
|
138
|
+
Interatividade, eventos ou formulários? → tema 4 (JavaScript e DOM)
|
|
139
|
+
Dividir em componentes ou gerenciar estado? → tema 5 (estado e componentes)
|
|
140
|
+
Decisão de usabilidade ou de design? → tema 6 (UI e UX)
|
|
141
|
+
Problema de acessibilidade? → tema 7 (acessibilidade)
|
|
142
|
+
Interface lenta ou instável? → tema 8 (performance)
|
|
143
|
+
Usar um recurso nativo do navegador? → tema 9 (APIs do navegador)
|
|
144
|
+
Escrever testes? → tema 10 (testes)
|
|
145
|
+
Entrada de dados, cookies ou terceiros? → tema 11 (segurança do cliente)
|
|
146
|
+
Refatorar ou revisar código? → tema 12 (qualidade de código)
|
|
589
147
|
```
|
|
590
148
|
|
|
591
149
|
---
|
|
592
150
|
|
|
593
|
-
##
|
|
594
|
-
|
|
595
|
-
### Testing Library — boas práticas
|
|
596
|
-
|
|
597
|
-
```tsx
|
|
598
|
-
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
|
|
599
|
-
import userEvent from '@testing-library/user-event'
|
|
600
|
-
import { describe, it, expect, vi } from 'vitest'
|
|
601
|
-
import { ProductForm } from './ProductForm'
|
|
602
|
-
|
|
603
|
-
describe('ProductForm', () => {
|
|
604
|
-
it('chama onSubmit com os dados corretos ao preencher e enviar', async () => {
|
|
605
|
-
const user = userEvent.setup()
|
|
606
|
-
const onSubmit = vi.fn()
|
|
607
|
-
|
|
608
|
-
render(<ProductForm onSubmit={onSubmit} />)
|
|
609
|
-
|
|
610
|
-
// ✅ Queries por acessibilidade (role, label)
|
|
611
|
-
await user.type(screen.getByLabelText('Nome do produto'), 'Camiseta Azul')
|
|
612
|
-
await user.type(screen.getByLabelText('Preço'), '49.90')
|
|
613
|
-
await user.click(screen.getByRole('button', { name: 'Salvar produto' }))
|
|
614
|
-
|
|
615
|
-
await waitFor(() => {
|
|
616
|
-
expect(onSubmit).toHaveBeenCalledWith({
|
|
617
|
-
name: 'Camiseta Azul',
|
|
618
|
-
price: 49.9,
|
|
619
|
-
})
|
|
620
|
-
})
|
|
621
|
-
})
|
|
622
|
-
|
|
623
|
-
it('exibe erro de validação quando nome está vazio', async () => {
|
|
624
|
-
const user = userEvent.setup()
|
|
625
|
-
render(<ProductForm onSubmit={vi.fn()} />)
|
|
626
|
-
|
|
627
|
-
await user.click(screen.getByRole('button', { name: 'Salvar produto' }))
|
|
628
|
-
|
|
629
|
-
expect(screen.getByRole('alert')).toHaveTextContent('Nome é obrigatório')
|
|
630
|
-
})
|
|
631
|
-
})
|
|
632
|
-
```
|
|
633
|
-
|
|
634
|
-
### Playwright — e2e para fluxos críticos
|
|
635
|
-
|
|
636
|
-
```typescript
|
|
637
|
-
import { test, expect } from '@playwright/test'
|
|
638
|
-
|
|
639
|
-
test('fluxo de checkout completo', async ({ page }) => {
|
|
640
|
-
await page.goto('/produtos')
|
|
641
|
-
|
|
642
|
-
await page.getByRole('button', { name: 'Adicionar ao carrinho' }).first().click()
|
|
643
|
-
await page.getByRole('link', { name: 'Ver carrinho' }).click()
|
|
644
|
-
|
|
645
|
-
await expect(page.getByRole('heading', { name: 'Seu carrinho' })).toBeVisible()
|
|
646
|
-
await expect(page.getByText('1 item')).toBeVisible()
|
|
151
|
+
## Fluxo de Trabalho
|
|
647
152
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
153
|
+
1. **Entender**: ler o contexto do projeto (Padrão 1) e os componentes e utilitários que já existem
|
|
154
|
+
2. **Projetar**: escolher a abordagem na base universal; definir estados visuais, responsividade e acessibilidade antes de codar
|
|
155
|
+
3. **Implementar**: reutilizar o que existe e seguir os padrões do projeto
|
|
156
|
+
4. **Testar**: cobrir o comportamento, os estados de erro e os casos limite
|
|
157
|
+
5. **Validar**: percorrer o checklist de conclusão abaixo
|
|
652
158
|
|
|
653
159
|
---
|
|
654
160
|
|
|
655
|
-
##
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
</main>
|
|
674
|
-
|
|
675
|
-
@stack('scripts')
|
|
676
|
-
</body>
|
|
677
|
-
</html>
|
|
678
|
-
|
|
679
|
-
{{-- resources/views/products/index.blade.php --}}
|
|
680
|
-
@extends('layouts.app')
|
|
681
|
-
|
|
682
|
-
@section('title', 'Produtos')
|
|
683
|
-
|
|
684
|
-
@section('content')
|
|
685
|
-
<div class="container">
|
|
686
|
-
@foreach($products as $product)
|
|
687
|
-
<x-product-card :product="$product" />
|
|
688
|
-
@endforeach
|
|
689
|
-
</div>
|
|
690
|
-
@endsection
|
|
691
|
-
```
|
|
692
|
-
|
|
693
|
-
### Componentes Blade (Class-based)
|
|
694
|
-
|
|
695
|
-
```php
|
|
696
|
-
// app/View/Components/ProductCard.php
|
|
697
|
-
namespace App\View\Components;
|
|
698
|
-
|
|
699
|
-
use Illuminate\View\Component;
|
|
700
|
-
use App\Models\Product;
|
|
701
|
-
|
|
702
|
-
class ProductCard extends Component
|
|
703
|
-
{
|
|
704
|
-
public function __construct(public readonly Product $product) {}
|
|
705
|
-
|
|
706
|
-
public function render()
|
|
707
|
-
{
|
|
708
|
-
return view('components.product-card');
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
{{-- resources/views/components/product-card.blade.php --}}
|
|
713
|
-
<article class="card" aria-label="{{ $product->name }}">
|
|
714
|
-
<h2>{{ $product->name }}</h2>
|
|
715
|
-
<p>{{ Number::currency($product->price, 'BRL') }}</p>
|
|
716
|
-
<button
|
|
717
|
-
type="button"
|
|
718
|
-
class="btn btn-primary"
|
|
719
|
-
data-product-id="{{ $product->id }}"
|
|
720
|
-
x-data
|
|
721
|
-
@click="$dispatch('add-to-cart', { id: {{ $product->id }} })"
|
|
722
|
-
>
|
|
723
|
-
Adicionar ao carrinho
|
|
724
|
-
</button>
|
|
725
|
-
</article>
|
|
726
|
-
```
|
|
727
|
-
|
|
728
|
-
### Formulários e CSRF
|
|
729
|
-
|
|
730
|
-
```php
|
|
731
|
-
{{-- Formulário com CSRF obrigatório --}}
|
|
732
|
-
<form method="POST" action="{{ route('products.store') }}">
|
|
733
|
-
@csrf
|
|
734
|
-
|
|
735
|
-
<div>
|
|
736
|
-
<label for="name">Nome do produto</label>
|
|
737
|
-
<input
|
|
738
|
-
type="text"
|
|
739
|
-
id="name"
|
|
740
|
-
name="name"
|
|
741
|
-
value="{{ old('name') }}"
|
|
742
|
-
aria-describedby="{{ $errors->has('name') ? 'name-error' : '' }}"
|
|
743
|
-
>
|
|
744
|
-
@error('name')
|
|
745
|
-
<p id="name-error" role="alert">{{ $message }}</p>
|
|
746
|
-
@enderror
|
|
747
|
-
</div>
|
|
748
|
-
|
|
749
|
-
<button type="submit">Criar produto</button>
|
|
750
|
-
</form>
|
|
751
|
-
```
|
|
752
|
-
|
|
753
|
-
### PHP/Blade — JavaScript com Babel
|
|
754
|
-
|
|
755
|
-
```javascript
|
|
756
|
-
// resources/js/app.js — entry point compilado via Babel (Laravel Vite ou Mix)
|
|
757
|
-
import './bootstrap' // axios, CSRF header
|
|
758
|
-
import './components' // componentes JS
|
|
759
|
-
|
|
760
|
-
// resources/js/components/add-to-cart.js
|
|
761
|
-
// Vanilla JS com Babel — sem framework
|
|
762
|
-
export function initAddToCart() {
|
|
763
|
-
document.querySelectorAll('[data-product-id]').forEach((button) => {
|
|
764
|
-
button.addEventListener('click', async (e) => {
|
|
765
|
-
const productId = e.currentTarget.dataset.productId
|
|
766
|
-
try {
|
|
767
|
-
const response = await window.axios.post('/cart/add', { product_id: productId })
|
|
768
|
-
updateCartCount(response.data.count)
|
|
769
|
-
} catch (error) {
|
|
770
|
-
console.error('Erro ao adicionar ao carrinho:', error)
|
|
771
|
-
}
|
|
772
|
-
})
|
|
773
|
-
})
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
document.addEventListener('DOMContentLoaded', initAddToCart)
|
|
777
|
-
```
|
|
778
|
-
|
|
779
|
-
### PHP/Blade — Build com Laravel Vite
|
|
780
|
-
|
|
781
|
-
```javascript
|
|
782
|
-
// vite.config.js
|
|
783
|
-
import { defineConfig } from 'vite'
|
|
784
|
-
import laravel from 'laravel-vite-plugin'
|
|
785
|
-
|
|
786
|
-
export default defineConfig({
|
|
787
|
-
plugins: [
|
|
788
|
-
laravel({
|
|
789
|
-
input: ['resources/css/app.css', 'resources/js/app.js'],
|
|
790
|
-
refresh: true, // hot reload para Blade
|
|
791
|
-
}),
|
|
792
|
-
],
|
|
793
|
-
})
|
|
794
|
-
```
|
|
795
|
-
|
|
796
|
-
```php
|
|
797
|
-
{{-- No layout Blade, usar diretiva @vite --}}
|
|
798
|
-
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
|
799
|
-
```
|
|
800
|
-
|
|
801
|
-
### Checklist PHP/Blade
|
|
802
|
-
|
|
803
|
-
- [ ] CSRF em todos os formulários (`@csrf`)
|
|
804
|
-
- [ ] Escape de output com `{{ }}` (nunca `{!! !!}` sem sanitização explícita)
|
|
805
|
-
- [ ] Acessibilidade: `<label>` associado a inputs, `role="alert"` em erros
|
|
806
|
-
- [ ] Usar `old()` para re-popular formulários após erro de validação
|
|
807
|
-
- [ ] Diretiva `@error` para exibir erros de validação
|
|
808
|
-
- [ ] Assets compilados via `@vite` (não links manuais para arquivos em `public/`)
|
|
809
|
-
- [ ] Componentes Blade reutilizáveis em `app/View/Components/` + `resources/views/components/`
|
|
161
|
+
## Base Universal
|
|
162
|
+
|
|
163
|
+
Carregue **só o tema necessário** para a tarefa, em vez de todos de uma vez.
|
|
164
|
+
|
|
165
|
+
| # | Tema | Nível | Carregue quando |
|
|
166
|
+
|---|------|-------|-----------------|
|
|
167
|
+
| 1 | [Fundamentos de programação](references/1-fundamentos-programacao.md) | Fundamental | Precisar revisar conceitos da linguagem do navegador |
|
|
168
|
+
| 2 | [HTML](references/2-html-fundamentals.md) | Fundamental | Estruturar conteúdo, formulários e metadados |
|
|
169
|
+
| 3 | [CSS e design responsivo](references/3-css-responsive.md) | Fundamental | Estilizar, montar layout e adaptar a vários tamanhos de tela |
|
|
170
|
+
| 4 | [JavaScript e DOM](references/4-javascript-dom.md) | Fundamental | Manipular o DOM, tratar eventos e operações assíncronas |
|
|
171
|
+
| 5 | [Estado e componentes](references/5-state-management.md) | Importante | Organizar estado, efeitos e arquitetura de componentes |
|
|
172
|
+
| 6 | [UI e UX](references/6-uiux-design.md) | Importante | Decidir hierarquia visual, usabilidade e padrões de interface |
|
|
173
|
+
| 7 | [Acessibilidade](references/7-acessibilidade.md) | Fundamental | Garantir WCAG, teclado, leitores de tela e contraste |
|
|
174
|
+
| 8 | [Performance](references/8-performance.md) | Importante | Medir e otimizar carregamento e renderização |
|
|
175
|
+
| 9 | [APIs do navegador](references/9-browser-apis.md) | Importante | Usar rede, armazenamento, service workers ou observers |
|
|
176
|
+
| 10 | [Testes](references/10-testes.md) | Fundamental | Definir a estratégia e a qualidade dos testes |
|
|
177
|
+
| 11 | [Segurança do cliente](references/11-seguranca.md) | Fundamental | Evitar XSS, CSRF e tratar armazenamento, CORS e dependências |
|
|
178
|
+
| 12 | [Qualidade de código](references/12-qualidade-codigo.md) | Fundamental | Refatorar, revisar código e documentar |
|
|
810
179
|
|
|
811
180
|
---
|
|
812
181
|
|
|
813
182
|
## Regras
|
|
814
183
|
|
|
815
184
|
### Nunca
|
|
816
|
-
-
|
|
817
|
-
-
|
|
818
|
-
-
|
|
819
|
-
-
|
|
820
|
-
-
|
|
821
|
-
- Esquecer
|
|
185
|
+
- Ignorar os estados de carregamento, erro e vazio em componentes com dados assíncronos
|
|
186
|
+
- Criar componentes com mais de uma responsabilidade
|
|
187
|
+
- Usar `!important` em CSS sem documentar o motivo
|
|
188
|
+
- Fazer requisições diretamente em componentes de UI quando o projeto tem uma camada de dados
|
|
189
|
+
- Contornar o sistema de tipos do projeto sem justificativa
|
|
190
|
+
- Esquecer os casos limite (lista vazia, falha de rede)
|
|
822
191
|
|
|
823
192
|
### Sempre
|
|
824
|
-
-
|
|
825
|
-
- Considerar mobile-first (Tailwind: base → sm → md → lg)
|
|
193
|
+
- Considerar mobile-first
|
|
826
194
|
- Testar comportamento, não implementação
|
|
827
|
-
- Verificar acessibilidade ao criar componentes interativos
|
|
195
|
+
- Verificar a acessibilidade ao criar componentes interativos
|
|
828
196
|
- Ler o código existente antes de escrever código novo
|
|
829
197
|
- Seguir os padrões já estabelecidos no projeto
|
|
830
|
-
-
|
|
831
|
-
- Em React 19: preferir Server Components por padrão, `'use client'` somente quando necessário
|
|
198
|
+
- Escapar a saída e validar a entrada também no servidor
|
|
832
199
|
|
|
833
200
|
---
|
|
834
201
|
|
|
835
202
|
## Tratamento de Erros
|
|
836
203
|
|
|
837
204
|
### Framework ou dependência não identificada
|
|
838
|
-
-
|
|
839
|
-
- Se não
|
|
205
|
+
- Procurar o manifesto de dependências e a estrutura do projeto
|
|
206
|
+
- Se não encontrar, perguntar à pessoa antes de prosseguir
|
|
840
207
|
|
|
841
208
|
### Componente existente com padrão diferente
|
|
842
|
-
- Seguir o padrão
|
|
843
|
-
-
|
|
209
|
+
- Seguir o padrão estabelecido no projeto, não o genérico deste skill
|
|
210
|
+
- Registrar a divergência quando relevante
|
|
844
211
|
|
|
845
|
-
### Teste
|
|
846
|
-
- Verificar se o teste
|
|
847
|
-
- Isolar a causa antes de ajustar código ou teste
|
|
212
|
+
### Teste falha depois de uma mudança
|
|
213
|
+
- Verificar se o teste já falhava antes
|
|
214
|
+
- Isolar a causa antes de ajustar o código ou o teste
|
|
848
215
|
|
|
849
216
|
---
|
|
850
217
|
|
|
851
218
|
## Checklist de Conclusão
|
|
852
219
|
|
|
853
|
-
### React / Next.js
|
|
854
|
-
- [ ] Componentes tipados com TypeScript
|
|
855
|
-
- [ ] Server vs Client Component decidido corretamente (`'use client'` somente quando necessário)
|
|
856
220
|
- [ ] Semântica HTML correta
|
|
857
|
-
- [ ] Estados visuais: normal,
|
|
221
|
+
- [ ] Estados visuais tratados: normal, foco, desabilitado, carregando, erro e vazio
|
|
858
222
|
- [ ] Responsivo (mobile-first)
|
|
859
|
-
- [ ] Acessível:
|
|
860
|
-
- [ ] Performance: sem
|
|
861
|
-
- [ ]
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
- [ ] `@csrf` em todos os formulários
|
|
865
|
-
- [ ] Output escapado com `{{ }}` (XSS prevention)
|
|
866
|
-
- [ ] `old()` e `@error` para UX de validação
|
|
867
|
-
- [ ] Labels associados a inputs
|
|
868
|
-
- [ ] Assets via `@vite` (não links hardcoded)
|
|
869
|
-
- [ ] Componentes reutilizáveis em `app/View/Components/`
|
|
870
|
-
|
|
871
|
-
### Geral
|
|
872
|
-
- [ ] Código seguindo padrões existentes no projeto
|
|
873
|
-
- [ ] Acessibilidade verificada (WCAG 2.1 AA)
|
|
223
|
+
- [ ] Acessível: teclado, rótulos, contraste e ARIA quando necessário (WCAG 2.1 AA)
|
|
224
|
+
- [ ] Performance: sem renderizações desnecessárias e carregamento sob demanda quando aplicável
|
|
225
|
+
- [ ] Segurança do cliente: saída escapada, sem segredos no frontend
|
|
226
|
+
- [ ] Testes cobrindo o comportamento e os estados de erro
|
|
227
|
+
- [ ] Código seguindo os padrões existentes do projeto
|
|
874
228
|
|
|
875
229
|
---
|
|
876
230
|
|
|
877
231
|
## Output
|
|
878
232
|
|
|
879
|
-
| Artefato |
|
|
880
|
-
|
|
881
|
-
| Componente(s)
|
|
882
|
-
|
|
|
883
|
-
|
|
|
884
|
-
|
|
|
885
|
-
|
|
|
886
|
-
| Testes | React | Arquivo de teste com Testing Library ou Playwright |
|
|
887
|
-
| Tokens/Variantes | React | Configuração Tailwind ou `cva` se design system envolvido |
|
|
888
|
-
| Documentação inline | Ambos | Comentários apenas onde lógica não é autoevidente |
|
|
233
|
+
| Artefato | Descrição |
|
|
234
|
+
|----------|-----------|
|
|
235
|
+
| Componente(s) ou tela(s) | Código com estados visuais tratados, no padrão do projeto |
|
|
236
|
+
| Estilos | CSS responsivo no sistema de estilos do projeto |
|
|
237
|
+
| Interatividade | Lógica de eventos e de estado isolada e testável |
|
|
238
|
+
| Testes | Cobrindo o comportamento e os estados de erro |
|
|
239
|
+
| Documentação inline | Comentários apenas onde a lógica não é autoevidente |
|
|
889
240
|
|
|
890
241
|
---
|
|
891
242
|
|
|
@@ -894,20 +245,32 @@ export default defineConfig({
|
|
|
894
245
|
```
|
|
895
246
|
Implementação frontend concluída!
|
|
896
247
|
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
Artefatos: {lista do que foi criado/modificado}
|
|
901
|
-
Testes: {criados/atualizados ou pendente}
|
|
248
|
+
Stack do projeto: {framework e estilos identificados no código}
|
|
249
|
+
Artefatos: {lista do que foi criado ou modificado}
|
|
250
|
+
Testes: {criados ou atualizados / pendentes}
|
|
902
251
|
|
|
903
|
-
Acessibilidade: {WCAG 2.1 AA verificado / pendente revisão}
|
|
904
|
-
Performance: {otimizações aplicadas
|
|
252
|
+
Acessibilidade: {WCAG 2.1 AA verificado / pendente de revisão}
|
|
253
|
+
Performance: {otimizações aplicadas / nenhuma necessária}
|
|
905
254
|
|
|
906
|
-
Próximo passo: {revisar no
|
|
255
|
+
Próximo passo: {revisar no navegador / rodar os testes / integrar com a API}
|
|
907
256
|
```
|
|
908
257
|
|
|
909
258
|
---
|
|
910
259
|
|
|
260
|
+
## Aviso: uso só da skill base
|
|
261
|
+
|
|
262
|
+
Quando o trabalho usar **só a skill base** e envolver uma tecnologia, framework ou ferramenta para a qual **não há skill especializado** disponível, avise a pessoa de forma explícita:
|
|
263
|
+
|
|
264
|
+
```
|
|
265
|
+
ℹ️ Estou usando só a skill base de frontend.
|
|
266
|
+
Não há skill especializado para {tecnologia}; vou seguir os princípios universais
|
|
267
|
+
e o padrão que encontrei no projeto.
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Não invente convenções nem comandos específicos da tecnologia: siga o código do projeto e a base universal.
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
911
274
|
## Recursos Adicionais
|
|
912
275
|
|
|
913
|
-
- **
|
|
276
|
+
- **Base universal**: os 12 temas em [references/](references/)
|