nexus-core-v3 3.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/LICENSE +21 -0
- package/README.md +134 -0
- package/agents/README.md +133 -0
- package/agents/_protocol.md +107 -0
- package/agents/analyst.md +138 -0
- package/agents/architect.md +146 -0
- package/agents/data-engineer.md +170 -0
- package/agents/dev.md +134 -0
- package/agents/devops.md +141 -0
- package/agents/nexus-master.md +147 -0
- package/agents/pm.md +133 -0
- package/agents/po.md +138 -0
- package/agents/qa.md +192 -0
- package/agents/sm.md +122 -0
- package/agents/squad-creator.md +121 -0
- package/agents/ux-design-expert.md +165 -0
- package/artifact-manifest.json +903 -0
- package/bin/nexus.mjs +37 -0
- package/checklists/README.md +49 -0
- package/checklists/architect-checklist.md +47 -0
- package/checklists/change-checklist.md +61 -0
- package/checklists/db-predeploy-checklist.md +57 -0
- package/checklists/design-quality-checklist.md +57 -0
- package/checklists/discovery-checklist.md +36 -0
- package/checklists/foundation-checklist.md +39 -0
- package/checklists/launch-checklist.md +39 -0
- package/checklists/pm-checklist.md +48 -0
- package/checklists/po-master-checklist.md +64 -0
- package/checklists/reality-check-checklist.md +49 -0
- package/checklists/story-dod-checklist.md +52 -0
- package/checklists/story-draft-checklist.md +36 -0
- package/dist/bin/dashboard.html +279 -0
- package/dist/bin/nexus.mjs +20008 -0
- package/dist/constitution.yaml +76 -0
- package/knowledge/README.md +57 -0
- package/knowledge/architecture/architectural-styles-map.md +182 -0
- package/knowledge/architecture/design-patterns-gof.md +192 -0
- package/knowledge/architecture/distributed-patterns-cheatsheet.md +201 -0
- package/knowledge/architecture/saas-subscription-blueprint.md +355 -0
- package/knowledge/architecture/system-design-tradeoffs.md +231 -0
- package/knowledge/architecture/t3-fullstack-typesafe-stack.md +273 -0
- package/knowledge/copy/landing-copy-that-converts.md +168 -0
- package/knowledge/data/postgres-indexing-and-tuning.md +263 -0
- package/knowledge/data/schema-modeling-decisions.md +273 -0
- package/knowledge/data/supabase-rls-patterns.md +316 -0
- package/knowledge/data/zero-downtime-migrations.md +308 -0
- package/knowledge/devops/cicd-pipeline-best-practices.md +318 -0
- package/knowledge/devops/production-dockerfile.md +283 -0
- package/knowledge/devops/twelve-factor-app.md +398 -0
- package/knowledge/engineering/clean-code-principles.md +429 -0
- package/knowledge/engineering/effective-code-review.md +204 -0
- package/knowledge/engineering/testing-strategy-beyond-unit.md +307 -0
- package/knowledge/governance/risk-matrix.md +56 -0
- package/knowledge/integration/mcp-server-selection-matrix.md +235 -0
- package/knowledge/marketing/copy-que-converte.md +43 -0
- package/knowledge/marketing/funil-e-jornada.md +36 -0
- package/knowledge/negocios/proposta-vencedora.md +38 -0
- package/knowledge/negocios/roi-e-unit-economics.md +46 -0
- package/knowledge/pipeline/1-descobrir.md +26 -0
- package/knowledge/pipeline/2-estrategizar.md +26 -0
- package/knowledge/pipeline/3-estruturar.md +27 -0
- package/knowledge/pipeline/4-construir.md +27 -0
- package/knowledge/pipeline/5-endurecer.md +28 -0
- package/knowledge/pipeline/6-lancar.md +27 -0
- package/knowledge/pipeline/7-operar.md +27 -0
- package/knowledge/security/lgpd-conformidade-basica.md +35 -0
- package/knowledge/security/owasp-secure-coding-gates.md +220 -0
- package/knowledge/security/owasp-top10-threat-assessment.md +287 -0
- package/knowledge/security/threat-modeling-stride.md +34 -0
- package/knowledge/web-craft/a11y-audit-checklist.md +251 -0
- package/knowledge/web-craft/accessible-component-patterns.md +383 -0
- package/knowledge/web-craft/anti-ai-look.md +114 -0
- package/knowledge/web-craft/design-system-from-code.md +195 -0
- package/knowledge/web-craft/intrinsic-css-layout.md +420 -0
- package/knowledge/web-craft/style-cloning.md +185 -0
- package/knowledge/web-craft/visual-polish-review.md +183 -0
- package/package.json +55 -0
- package/runbooks/campanha-de-conteudo.md +36 -0
- package/runbooks/feature-em-projeto-existente.md +37 -0
- package/runbooks/mvp-startup.md +38 -0
- package/runbooks/resposta-a-incidente.md +37 -0
- package/squads/exemplo-conteudo/agents/editor-chefe.md +48 -0
- package/squads/exemplo-conteudo/agents/pesquisador.md +44 -0
- package/squads/exemplo-conteudo/agents/redator.md +45 -0
- package/squads/exemplo-conteudo/knowledge/estilo-editorial.md +21 -0
- package/squads/exemplo-conteudo/squad.yaml +19 -0
- package/squads/exemplo-conteudo/tasks/pesquisar-fontes.md +26 -0
- package/squads/exemplo-conteudo/tasks/planejar-pauta.md +27 -0
- package/squads/exemplo-conteudo/tasks/redigir-artigo.md +26 -0
- package/squads/exemplo-conteudo/tasks/revisar-artigo.md +27 -0
- package/squads/marketing/agents/analista.md +56 -0
- package/squads/marketing/agents/chefe-marketing.md +65 -0
- package/squads/marketing/agents/conteudo.md +55 -0
- package/squads/marketing/agents/copy.md +55 -0
- package/squads/marketing/agents/growth.md +56 -0
- package/squads/marketing/agents/social.md +55 -0
- package/squads/marketing/squad.yaml +17 -0
- package/squads/marketing/tasks/aprovar-campanha.md +43 -0
- package/squads/negocios/agents/chefe-negocios.md +65 -0
- package/squads/negocios/agents/financas-roi.md +55 -0
- package/squads/negocios/agents/suporte.md +55 -0
- package/squads/negocios/agents/vendas-proposta.md +56 -0
- package/squads/negocios/squad.yaml +17 -0
- package/squads/negocios/tasks/aprovar-proposta.md +40 -0
- package/squads/security/agents/appsec-reviewer.md +59 -0
- package/squads/security/agents/chefe-seguranca.md +65 -0
- package/squads/security/agents/compliance-auditor.md +60 -0
- package/squads/security/agents/threat-modeler.md +60 -0
- package/squads/security/squad.yaml +20 -0
- package/squads/security/tasks/aprovar-gate-seguranca.md +42 -0
- package/squads/security/tasks/emitir-parecer-conformidade.md +42 -0
- package/tasks/README.md +72 -0
- package/tasks/accessibility-wcag-checklist.md +69 -0
- package/tasks/advanced-elicitation.md +42 -0
- package/tasks/analyze-performance.md +54 -0
- package/tasks/analyze-project-structure.md +59 -0
- package/tasks/apply-qa-fixes.md +57 -0
- package/tasks/architect-analyze-impact.md +62 -0
- package/tasks/archive-squad.md +52 -0
- package/tasks/audit-codebase.md +53 -0
- package/tasks/build-component.md +61 -0
- package/tasks/calculate-roi.md +63 -0
- package/tasks/ci-cd-configuration.md +51 -0
- package/tasks/collect-visual-evidence.md +62 -0
- package/tasks/compose-molecule.md +57 -0
- package/tasks/consolidate-patterns.md +54 -0
- package/tasks/create-brownfield-prd.md +54 -0
- package/tasks/create-competitor-analysis.md +42 -0
- package/tasks/create-deep-research-prompt.md +62 -0
- package/tasks/create-doc.md +62 -0
- package/tasks/create-epic.md +49 -0
- package/tasks/create-front-end-spec.md +56 -0
- package/tasks/create-migration-plan.md +57 -0
- package/tasks/create-next-story.md +66 -0
- package/tasks/create-prd.md +53 -0
- package/tasks/create-project-brief.md +47 -0
- package/tasks/create-rls-policies.md +59 -0
- package/tasks/create-schema.md +57 -0
- package/tasks/create-service.md +55 -0
- package/tasks/create-squad.md +100 -0
- package/tasks/create-suite.md +62 -0
- package/tasks/db-apply-migration.md +56 -0
- package/tasks/db-domain-modeling.md +57 -0
- package/tasks/db-dry-run.md +50 -0
- package/tasks/db-env-check.md +57 -0
- package/tasks/db-load-csv.md +54 -0
- package/tasks/db-policy-apply.md +58 -0
- package/tasks/db-rollback.md +51 -0
- package/tasks/db-run-sql.md +61 -0
- package/tasks/db-seed.md +52 -0
- package/tasks/db-smoke-test.md +51 -0
- package/tasks/db-snapshot.md +48 -0
- package/tasks/db-verify-order.md +49 -0
- package/tasks/deliberate.md +46 -0
- package/tasks/design-indexes.md +59 -0
- package/tasks/dev-develop-story.md +61 -0
- package/tasks/document-project.md +59 -0
- package/tasks/execute-checklist.md +57 -0
- package/tasks/execute-epic-plan.md +52 -0
- package/tasks/execute-subtask.md +51 -0
- package/tasks/extend-pattern.md +63 -0
- package/tasks/extend-squad.md +60 -0
- package/tasks/extract-patterns.md +64 -0
- package/tasks/extract-tokens.md +59 -0
- package/tasks/facilitate-brainstorming-session.md +42 -0
- package/tasks/generate-ai-frontend-prompt.md +57 -0
- package/tasks/generate-documentation.md +60 -0
- package/tasks/generate-migration-strategy.md +57 -0
- package/tasks/generate-shock-report.md +56 -0
- package/tasks/mcp-management.md +66 -0
- package/tasks/orchestrate.md +50 -0
- package/tasks/perform-market-research.md +42 -0
- package/tasks/plan-create-context.md +57 -0
- package/tasks/plan-create-implementation.md +58 -0
- package/tasks/po-close-story.md +60 -0
- package/tasks/po-manage-story-backlog.md +59 -0
- package/tasks/po-pull-story.md +60 -0
- package/tasks/po-sync-story.md +59 -0
- package/tasks/pr-automation.md +50 -0
- package/tasks/pre-push-quality-gate.md +54 -0
- package/tasks/push.md +53 -0
- package/tasks/qa-browser-console-check.md +52 -0
- package/tasks/qa-create-fix-request.md +58 -0
- package/tasks/qa-evidence-requirements.md +55 -0
- package/tasks/qa-false-positive-detection.md +55 -0
- package/tasks/qa-fix-issues.md +55 -0
- package/tasks/qa-gate.md +53 -0
- package/tasks/qa-migration-validation.md +58 -0
- package/tasks/qa-nfr-assess.md +45 -0
- package/tasks/qa-review-story.md +56 -0
- package/tasks/qa-risk-profile.md +45 -0
- package/tasks/qa-security-checklist.md +64 -0
- package/tasks/qa-test-design.md +47 -0
- package/tasks/qa-trace-requirements.md +48 -0
- package/tasks/release-management.md +53 -0
- package/tasks/repository-cleanup.md +61 -0
- package/tasks/route.md +44 -0
- package/tasks/run-tests.md +50 -0
- package/tasks/security-audit.md +54 -0
- package/tasks/setup-database.md +60 -0
- package/tasks/setup-design-system.md +60 -0
- package/tasks/shard-doc.md +60 -0
- package/tasks/spec-assess-complexity.md +55 -0
- package/tasks/spec-critique.md +64 -0
- package/tasks/spec-gather-requirements.md +48 -0
- package/tasks/spec-research-dependencies.md +42 -0
- package/tasks/spec-write-spec.md +50 -0
- package/tasks/test-as-user.md +52 -0
- package/tasks/ux-create-wireframe.md +54 -0
- package/tasks/ux-user-research.md +55 -0
- package/tasks/validate-next-story.md +61 -0
- package/tasks/validate-squad.md +55 -0
- package/tasks/verify-subtask.md +52 -0
- package/tasks/version-management.md +45 -0
- package/templates/README.md +47 -0
- package/templates/architecture-tmpl.md +115 -0
- package/templates/competitor-analysis-tmpl.md +87 -0
- package/templates/epic-tmpl.md +83 -0
- package/templates/front-end-spec-tmpl.md +110 -0
- package/templates/market-research-tmpl.md +98 -0
- package/templates/migration-plan-tmpl.md +92 -0
- package/templates/prd-tmpl.md +95 -0
- package/templates/project-brief-tmpl.md +100 -0
- package/templates/qa-verdict-tmpl.md +73 -0
- package/templates/rls-policies-tmpl.md +93 -0
- package/templates/schema-design-tmpl.md +107 -0
- package/templates/spec-tmpl.md +88 -0
- package/templates/squad/agent-dna-tmpl.md +72 -0
- package/templates/squad/chief-dna-tmpl.md +98 -0
- package/templates/squad/squad-task-tmpl.md +50 -0
- package/templates/squad/squad-yaml-tmpl.md +47 -0
- package/templates/story-tmpl.md +63 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: testing-strategy-beyond-unit
|
|
3
|
+
domain: engineering
|
|
4
|
+
agents: [qa, dev]
|
|
5
|
+
when: "ao desenhar a estratégia de testes de uma feature ou avaliar a cobertura de uma story"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Testing strategy beyond unit — testes que pegam bug, não que decoram cobertura
|
|
9
|
+
|
|
10
|
+
Suíte de teste medíocre tem uma "cara": ela é verde, tem 85% de cobertura, e mesmo assim
|
|
11
|
+
bugs escapam pra produção. O motivo é quase sempre o mesmo — os testes visitam o código
|
|
12
|
+
sem testar nada, ou estão tão acoplados aos internos que quebram a cada refactor e ninguém
|
|
13
|
+
mais confia neles. Este pack ensina a **escolher o tipo de teste certo, escrevê-lo pra pegar
|
|
14
|
+
bug de verdade, e medir se ele presta** — destilado do
|
|
15
|
+
[goldbergyoni/javascript-testing-best-practices](https://github.com/goldbergyoni/javascript-testing-best-practices)
|
|
16
|
+
(Yoni Goldberg). A regra-mãe (o "Golden Rule" do repo): **código de teste não é código de
|
|
17
|
+
produção — projete-o pra ser curto, raso e óbvio. Olhe um teste e entenda a intenção na hora.**
|
|
18
|
+
Tudo abaixo deriva disso.
|
|
19
|
+
|
|
20
|
+
## O problema / os tells
|
|
21
|
+
|
|
22
|
+
Se a suíte tem 3+ destes, ela é teatro de cobertura, não rede de segurança:
|
|
23
|
+
|
|
24
|
+
1. **Nome de teste que não diz nada** — `it("Add product")`, `it("Test addNewOrder")`. Falhou no
|
|
25
|
+
CI: você não faz ideia do que quebrou sem abrir o código.
|
|
26
|
+
2. **Sem separação AAA** — arrange, act e assert grudados num bloco só; o leitor gasta CPU mental
|
|
27
|
+
só pra achar onde o teste age e onde verifica.
|
|
28
|
+
3. **Asserção imperativa** — `forEach` + `if` + flags booleanas + `throw` manual em vez de um
|
|
29
|
+
`expect` declarativo. A "história" do teste some no meio do controle de fluxo.
|
|
30
|
+
4. **Testa método privado / internals** — o teste chama `calculateVATAdd()` (interno) e quebra
|
|
31
|
+
quando você renomeia o método, embora o resultado final esteja certo. O teste vira o menino
|
|
32
|
+
que gritou lobo: dá falso-positivo até alguém ignorar o CI e um bug real passar.
|
|
33
|
+
5. **Mock que verifica "foi chamado com esses args"** — `mock.expects("deleteProduct").withArgs(...)`.
|
|
34
|
+
Acoplado ao como, não ao quê. Qualquer refactor obriga a caçar e reescrever todos os mocks.
|
|
35
|
+
6. **Input `"Foo"` / `123`** — input sintético nunca dispara o regex de validação, o path de erro,
|
|
36
|
+
o caso de borda. Verde no dev, vermelho quando um usuário manda `"@3e2ddsf . ##' 1 fdsfds"`.
|
|
37
|
+
7. **`setTimeout(2000)` esperando algo async** — o teste é lento (espera demais) ou flaky (espera
|
|
38
|
+
de menos). Trade-off entre lentidão e flakiness, perde nos dois.
|
|
39
|
+
8. **Seed global de DB** (`before(() => DB.seed('seed.json'))`) — testes acoplados a dados que
|
|
40
|
+
vivem fora deles; dois testes mutam a mesma linha e o deploy aborta sem causa óbvia.
|
|
41
|
+
9. **Selector por classe CSS** — `wrapper.find("[className='thin-border']")`. O designer troca a
|
|
42
|
+
classe e o teste de *lógica* de login quebra.
|
|
43
|
+
10. **Snapshot gigante externo** — `toMatchSnapshot()` de 2000 linhas que ninguém leu; quebra a
|
|
44
|
+
cada espaço, comentário ou mudança de CSS, e o autor aprova cegamente o "novo correto".
|
|
45
|
+
11. **100% de cobertura, 0% de teste** — o teste chama a função e não tem **nenhum** `expect`.
|
|
46
|
+
Visitou todas as linhas, não verificou nada.
|
|
47
|
+
12. **Só pirâmide de unit** — 50% do budget em unit tests pra uma app que é integração-cêntrica
|
|
48
|
+
(ingest Kafka → data warehouse → UI), quase sem lógica. Muito esforço, 20% de cobertura real.
|
|
49
|
+
|
|
50
|
+
## Os princípios do craft (com pares bad→good reais do repo)
|
|
51
|
+
|
|
52
|
+
### 1. Nome do teste em 3 partes: o quê / cenário / esperado
|
|
53
|
+
O relatório do CI tem que dizer o que está quebrado pra quem **não** conhece o código (o ops que
|
|
54
|
+
faz deploy, você daqui a dois anos). Três partes: (1) unidade sob teste, (2) cenário/circunstância,
|
|
55
|
+
(3) resultado esperado.
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
// ❌ "Add product" — falhou no deploy. Isso te diz o que está com defeito?
|
|
59
|
+
|
|
60
|
+
// ✅ describe aninhado carrega a parte (1); o it() carrega (2) e (3)
|
|
61
|
+
describe('Products Service', () => {
|
|
62
|
+
describe('Add new product', () => {
|
|
63
|
+
it('When no price is specified, then the product status is pending approval', () => {
|
|
64
|
+
const newProduct = new ProductService().add(/* ... */);
|
|
65
|
+
expect(newProduct.status).to.equal('pendingApproval');
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 2. Estruture com AAA — Arrange, Act, Assert, separados
|
|
72
|
+
Três seções marcadas. Garante que o leitor não gasta "brain-CPU" decifrando o plano do teste.
|
|
73
|
+
Act e Assert costumam ser 1 linha cada.
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
// ❌ tudo num bloco só, mais difícil de interpretar
|
|
77
|
+
test("Should be classified as premium", () => {
|
|
78
|
+
const customerToClassify = { spent: 505, joined: new Date(), id: 1 };
|
|
79
|
+
const DBStub = sinon.stub(dataAccess, "getCustomer").reply({ id: 1, classification: "regular" });
|
|
80
|
+
const received = customerClassifier.classifyCustomer(customerToClassify);
|
|
81
|
+
expect(received).toMatch("premium");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// ✅ Arrange / Act / Assert separados
|
|
85
|
+
test("When customer spent more than 500$, should be classified as premium", () => {
|
|
86
|
+
// Arrange
|
|
87
|
+
const customerToClassify = { spent: 505, joined: new Date(), id: 1 };
|
|
88
|
+
sinon.stub(dataAccess, "getCustomer").reply({ id: 1, classification: "regular" });
|
|
89
|
+
// Act
|
|
90
|
+
const receivedClassification = customerClassifier.classifyCustomer(customerToClassify);
|
|
91
|
+
// Assert
|
|
92
|
+
expect(receivedClassification).toMatch("premium");
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 3. Asserção declarativa (BDD), não fluxo imperativo
|
|
97
|
+
Código imperativo com `if`/`forEach`/flags força o leitor a executar o teste na cabeça. Use
|
|
98
|
+
`expect`/`should` declarativo. Se a asserção que você precisa não existe e é repetível, estenda o
|
|
99
|
+
matcher — não escreva lógica de verificação inline.
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
// ❌ o leitor tem que percorrer o loop pra entender a história do teste
|
|
103
|
+
allAdmins.forEach(u => {
|
|
104
|
+
if (u === "user1") assert.notEqual(u, "user1", "A user was found and not admin");
|
|
105
|
+
if (u === "admin1") admin1Found = true;
|
|
106
|
+
if (u === "admin2") admin2Found = true;
|
|
107
|
+
});
|
|
108
|
+
if (!admin1Found || !admin2Found) throw new Error("Not all admins were returned");
|
|
109
|
+
|
|
110
|
+
// ✅ uma linha declarativa
|
|
111
|
+
expect(allAdmins)
|
|
112
|
+
.to.include.ordered.members(["admin1", "admin2"])
|
|
113
|
+
.but.not.include.ordered.members(["user1"]);
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Corolário — **não capture erro, espere-o.** Nada de `try/catch` + flag pra provar que lançou.
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
// ❌ se a asserção final falhar, o relatório só diz "valor null" — nada sobre exceção faltando
|
|
120
|
+
let caught = null;
|
|
121
|
+
try { await addNewProduct({}); } catch (e) { expect(e.code).to.equal("InvalidInput"); caught = e; }
|
|
122
|
+
expect(caught).not.to.be.null;
|
|
123
|
+
|
|
124
|
+
// ✅ legível até pro QA/PM, e o tipo do erro é verificado
|
|
125
|
+
await expect(addNewProduct({}))
|
|
126
|
+
.to.eventually.throw(AppError)
|
|
127
|
+
.with.property("code", "InvalidInput");
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 4. Teste comportamento via API pública (black-box), nunca internals
|
|
131
|
+
Verificar o comportamento público testa a implementação privada **implicitamente**. Testar o
|
|
132
|
+
interno (white-box) desloca o foco pro detalhe e quebra o teste em refactors inofensivos.
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
// ❌ white-box: testa um método interno que nem é requisito
|
|
136
|
+
class ProductService {
|
|
137
|
+
calculateVATAdd(price) { return { finalPrice: price * 1.2 }; } // renomear → testes quebram
|
|
138
|
+
getPrice(id) { return this.calculateVATAdd(DB.getProduct(id).price).finalPrice; }
|
|
139
|
+
}
|
|
140
|
+
expect(new ProductService().calculateVATAdd(0).finalPrice).to.equal(0);
|
|
141
|
+
|
|
142
|
+
// ✅ teste o que é requisito (preço final via método público); o VAT é coberto de tabela
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
No frontend, a mesma regra vira "renderize de verdade e aja como o usuário", não shallow render +
|
|
146
|
+
invocar método interno:
|
|
147
|
+
|
|
148
|
+
```javascript
|
|
149
|
+
// ✅ realista: monta o componente, clica, verifica o que o usuário vê
|
|
150
|
+
const wrapper = mount(<Calendar showFilters={false} />);
|
|
151
|
+
wrapper.find("button").simulate("click");
|
|
152
|
+
expect(wrapper.text().includes("Choose Filter"));
|
|
153
|
+
|
|
154
|
+
// ❌ shallow + .instance().showFilters() — tapeia a UI e chama método privado (white-box)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### 5. Escolha o test double certo: stub/spy (comportamento), não mock (internals)
|
|
158
|
+
Antes de qualquer double, pergunte: **isto aparece (ou poderia aparecer) no documento de requisitos?**
|
|
159
|
+
Se não, é cheiro de white-box. Stub pra simular um cenário ("pagamento fora do ar"), spy pra
|
|
160
|
+
verificar um efeito que **é** requisito ("envie e-mail se o pagamento falhar"). Mock que checa
|
|
161
|
+
"foi chamado com esses tipos/args" testa o interno — vai mudar toda hora.
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
// ❌ mock: o objetivo virou verificar a chamada interna ao DAL, não o requisito
|
|
165
|
+
const dataAccessMock = sinon.mock(DAL);
|
|
166
|
+
dataAccessMock.expects("deleteProduct").once().withArgs(DBConfig, product, true, false);
|
|
167
|
+
new ProductService().deletePrice(product);
|
|
168
|
+
dataAccessMock.verify();
|
|
169
|
+
|
|
170
|
+
// ✅ spy: verifica o requisito (e-mail enviado); tocar no interno é só efeito colateral
|
|
171
|
+
const spy = sinon.spy(Emailer.prototype, "sendEmail");
|
|
172
|
+
new ProductService().deletePrice(product);
|
|
173
|
+
expect(spy.calledOnce).to.be.true;
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### 6. Input realista, não `"Foo"`
|
|
177
|
+
Bug de produção aparece em input específico e surpreendente. Use Faker/Chance pra gerar dado que
|
|
178
|
+
se parece com produção; suba pra property-based testing quando quiser cobrir permutações.
|
|
179
|
+
|
|
180
|
+
```javascript
|
|
181
|
+
// ❌ "Foo" nunca dispara o regex (sem espaço) — falso verde
|
|
182
|
+
const r = addProduct("Foo", 5);
|
|
183
|
+
expect(r).toBe(true);
|
|
184
|
+
|
|
185
|
+
// ✅ input pseudo-real cobre paths que você não planejou
|
|
186
|
+
const r = addProduct(faker.commerce.productName(), faker.random.number());
|
|
187
|
+
expect(r).to.be.true;
|
|
188
|
+
|
|
189
|
+
// ✅✅ property-based (fast-check): roda 100 permutações automáticas
|
|
190
|
+
fc.assert(fc.property(fc.integer(), fc.string(), (id, name) => {
|
|
191
|
+
expect(addNewProduct(id, name).status).toEqual("approved");
|
|
192
|
+
}));
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### 7. Anti-flakiness: determinismo, sem sleep, dados por-teste
|
|
196
|
+
- **Não durma.** Em vez de `setTimeout`, use a espera determinística do framework (`cy.wait('@route')`,
|
|
197
|
+
`waitFor`/`findBy` do testing-library, fake timers). Sleep é trade-off entre lento e flaky.
|
|
198
|
+
|
|
199
|
+
```javascript
|
|
200
|
+
// ❌ sleep/polling caseiro, sem timeout
|
|
201
|
+
const interval = setInterval(() => { if (getByText("the lion king")) clearInterval(interval); }, 100);
|
|
202
|
+
|
|
203
|
+
// ✅ espera determinística do framework
|
|
204
|
+
await waitFor(() => expect(getByText("the lion king")).toBeInTheDocument());
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
- **Dados isolados por teste.** Cada caso adiciona e age só nas próprias linhas de DB. Seed global é
|
|
208
|
+
acoplamento: dois testes mutam o mesmo registro e o deploy aborta sem causa óbvia.
|
|
209
|
+
|
|
210
|
+
```javascript
|
|
211
|
+
// ❌ before(() => DB.AddSeedDataFromJson('seed.json')); // o dado vive fora do teste
|
|
212
|
+
// ✅ cada teste cria o que precisa: const site = await SiteService.addSite({ name: faker.... });
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
- **Stub recurso flaky/lento** (API de backend) nos testes que não são E2E — staging cai sozinho e
|
|
216
|
+
reprova seu componente que está correto; e chamada de rede deixa o teste ~20x mais lento.
|
|
217
|
+
- **Selector estável**: `data-test-id`, não classe CSS. Classe muda com o visual e derruba teste de lógica.
|
|
218
|
+
|
|
219
|
+
```javascript
|
|
220
|
+
// ❌ expect(wrapper.find("[className='d-flex-column']").text()).toBe("0");
|
|
221
|
+
// ✅ <span data-test-id="errorsLabel">{value}</span> → getByTestId("errorsLabel")
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### 8. Pirâmide vs. troféu: enriqueça o portfólio, não empilhe só unit
|
|
225
|
+
A pirâmide de testes (muito unit, pouco E2E) ainda vale pra muita app — mas "todo modelo está
|
|
226
|
+
errado às vezes". App integração-cêntrica com pouca lógica não merece 50% do budget em unit. Combine
|
|
227
|
+
o **tipo de teste ao risco real** da feature, como um investidor diversifica por análise de risco.
|
|
228
|
+
O nível mais valioso e subestimado costuma ser o **component test** (o "troféu"): bate na API do
|
|
229
|
+
microsserviço, usa DB real (ou in-memory), e faz stub só do que é externo (outros serviços). Testa
|
|
230
|
+
o que você faz deploy, de fora pra dentro, com cobertura realista a custo razoável.
|
|
231
|
+
|
|
232
|
+
### 9. Meça a *qualidade* do teste, não só a cobertura — mutation testing
|
|
233
|
+
Cobertura tradicional mente: pode mostrar 100% e nenhuma função retornar o certo, porque ela mede
|
|
234
|
+
linha **visitada**, não **testada** (asserção certa). É como provar trabalho mostrando carimbos no
|
|
235
|
+
passaporte. Mutation testing (Stryker) **planta bugs** no código (`price === 0` vira `price != 0`)
|
|
236
|
+
e roda a suíte: se os testes passam mesmo assim, o mutante "sobreviveu" — seu teste não pega aquele
|
|
237
|
+
bug. Mutante morto = teste de verdade.
|
|
238
|
+
|
|
239
|
+
```javascript
|
|
240
|
+
// ❌ 100% de cobertura, 0% de teste — visita tudo, não verifica nada
|
|
241
|
+
function addNewOrder(o) { logger.log(o); DB.save(o); Mailer.sendMail(o.assignee, "..."); return { approved: true }; }
|
|
242
|
+
it("Test addNewOrder", () => { addNewOrder({ assignee: "j@x.com", price: 120 }); }); // sem expect
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Complemente com **lint de teste** (`eslint-plugin-jest`/`-mocha`): pega teste sem asserção, teste
|
|
246
|
+
skipado, título duplicado — coisas que viram "90% verde" enganoso.
|
|
247
|
+
|
|
248
|
+
### 10. Garanta o contrato entre serviços — contract tests
|
|
249
|
+
Microsserviço com múltiplos clientes: você muda um campo e quebra um cliente importante. O provider
|
|
250
|
+
publica o typing da API (JSDoc/TypeScript) como pacote npm, e os consumidores ganham validação em
|
|
251
|
+
tempo de build. Abordagem mais rica: **PACT** — o cliente define as expectativas, grava num "broker",
|
|
252
|
+
e o servidor roda contra elas em todo build, pegando o mismatch cedo no CI.
|
|
253
|
+
|
|
254
|
+
### 11. Cubra os 5 resultados possíveis de um fluxo (foco no de fora, não no como)
|
|
255
|
+
Ao planejar o que verificar numa ação (ex.: chamada de API), cubra os cinco resultados observáveis
|
|
256
|
+
de fora: **(1) Response** (dados, schema, status HTTP) · **(2) Novo estado** (dado publicamente
|
|
257
|
+
acessível mudou) · **(3) Chamadas externas** (SMS, e-mail, cobrança) · **(4) Filas de mensagem**
|
|
258
|
+
(mensagem publicada) · **(5) Observabilidade** (erro tratado, log/métrica certos — o "usuário ops"
|
|
259
|
+
também é usuário).
|
|
260
|
+
|
|
261
|
+
## Checklist (qualquer "sim" é um tell a corrigir)
|
|
262
|
+
|
|
263
|
+
- [ ] Algum nome de teste não tem as 3 partes (o quê / cenário / esperado)?
|
|
264
|
+
- [ ] Tem teste sem separação AAA, ou com asserção imperativa (`if`/`forEach`/flag) em vez de `expect`?
|
|
265
|
+
- [ ] Algum teste verifica método privado / internal que não é requisito?
|
|
266
|
+
- [ ] Tem mock checando "foi chamado com esses args" em vez de stub/spy de comportamento?
|
|
267
|
+
- [ ] Input é `"Foo"`/`123` em vez de dado realista (Faker) ou property-based onde compensa?
|
|
268
|
+
- [ ] Tem `setTimeout`/sleep esperando async em vez de espera determinística do framework?
|
|
269
|
+
- [ ] Tem seed global de DB em vez de dado criado por-teste?
|
|
270
|
+
- [ ] Selector de teste de lógica depende de classe CSS em vez de `data-test-id`?
|
|
271
|
+
- [ ] Tem snapshot externo gigante em vez de inline curto (3–7 linhas) e focado?
|
|
272
|
+
- [ ] Existe teste sem nenhuma asserção (cobre linha, não testa nada)?
|
|
273
|
+
- [ ] A confiança vem só de "% de cobertura", sem mutation testing nos caminhos críticos?
|
|
274
|
+
- [ ] A estratégia é "só unit" mesmo numa feature integração-cêntrica?
|
|
275
|
+
|
|
276
|
+
## Tabela de decisão (use X quando Y)
|
|
277
|
+
|
|
278
|
+
| Quando Y | Use X | O que pega / o que custa |
|
|
279
|
+
|---|---|---|
|
|
280
|
+
| Lógica pura, sem IO (cálculo, classificação, validação) | **Unit test** (black-box, API pública) | Pega bug de lógica; barato e rápido, mas cobre pouca área por teste |
|
|
281
|
+
| Feature que cruza camadas de **um** serviço (rota → lógica → DB) | **Component test** (API real, DB real/in-memory, stub do externo) | Pega bug de integração interna com cobertura realista; melhor ROI no backend |
|
|
282
|
+
| Risco de mismatch de schema **entre** serviços/clientes | **Contract test** (typing publicado ou PACT) | Pega quebra de contrato no CI, antes do deploy; setup extra no provider+consumer |
|
|
283
|
+
| Validar fluxo ponta-a-ponta (front + backend real) | **E2E**, mas só **1–10** sobre staging production-like | Pega falha de deploy e de integração front↔back; caro, frágil, lento — use com parcimônia |
|
|
284
|
+
| Sanidade de produção / dev | **1 smoke E2E** que percorre o site map | ROI altíssimo, pega falha funcional/rede/empacotamento; não substitui teste funcional |
|
|
285
|
+
| Input com muitas permutações possíveis | **Property-based** (fast-check) sobre o unit | Acha o caso de borda que você não imaginou; roda N vezes, um pouco mais lento |
|
|
286
|
+
| Você quer saber se os testes **prestam** (não só cobrem) | **Mutation testing** (Stryker) nos caminhos críticos | Mede teste real (mutante morto); setup ~igual ao de cobertura, execução mais cara |
|
|
287
|
+
| Componente UI (lógica + alguns filhos, tamanho razoável) | **Render realista** (`mount`) + query por `data-test-id` | Pega bug que dado certo não chega na UI; evite shallow + chamar método interno |
|
|
288
|
+
| Recurso externo lento/instável num teste não-E2E (API backend) | **Stub** (nock/Sinon) | Mata flakiness e ~20x de lentidão; nunca stube o que você está justamente testando |
|
|
289
|
+
| Async com tempo desconhecido (animação, fetch) | Espera **determinística** do framework (`waitFor`, `cy.wait`, fake timers) | Determinismo sem sleep; sleep troca lentidão por flakiness |
|
|
290
|
+
| Asserção em markup que muda muito | **Inline snapshot** curto (3–7 linhas) sobre o trecho que importa | Self-explanatory e estável; snapshot externo gigante quebra por espaço/CSS |
|
|
291
|
+
|
|
292
|
+
## O que NÃO testar
|
|
293
|
+
|
|
294
|
+
- **Métodos privados / internals** — cobertos implicitamente pela API pública; testá-los só cria
|
|
295
|
+
testes frágeis e custo de manutenção.
|
|
296
|
+
- **Como (interação interna)** quando o que importa é o **resultado observável** — não verifique
|
|
297
|
+
"chamou o DAL com esses args"; verifique o efeito que é requisito.
|
|
298
|
+
- **100% de tudo** — 100% desloca o foco dos caminhos críticos pros cantos exóticos; ~80% é o número
|
|
299
|
+
de bolso (Fowler: "nos 80s ou 90s altos"), e o limiar é contextual (A380 ≠ site de cartoon).
|
|
300
|
+
- **Detalhe gráfico (HTML/CSS) em teste de lógica** — separe UI de funcionalidade; asserte dado contra
|
|
301
|
+
dado.
|
|
302
|
+
- **Documento gigante via snapshot externo** que ninguém leu — 1000 motivos pra falhar, zero sinal útil.
|
|
303
|
+
- Às vezes vale **dropar um teste** e trocar confiabilidade por agilidade — o Golden Rule manda manter
|
|
304
|
+
a suíte enxuta e deliciosa de manter, não exaustiva por exaustão.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
*Fonte: [goldbergyoni/javascript-testing-best-practices](https://github.com/goldbergyoni/javascript-testing-best-practices) — Yoni Goldberg. Exemplos de código extraídos do repositório real.*
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
sla:
|
|
3
|
+
P0: imediato
|
|
4
|
+
P1: menos de 4h
|
|
5
|
+
P2: menos de 24h
|
|
6
|
+
P3: menos de 1 semana
|
|
7
|
+
categorias:
|
|
8
|
+
- { categoria: Dívida técnica, dono: architect, mitigador: dev, escalacao: nexus-master, severidade: P2 }
|
|
9
|
+
- { categoria: Regressão de qualidade, dono: qa, mitigador: dev, escalacao: nexus-master, severidade: P1 }
|
|
10
|
+
- { categoria: Vulnerabilidade de segurança, dono: qa, mitigador: devops, escalacao: nexus-master, severidade: P0 }
|
|
11
|
+
- { categoria: Estouro de custo, dono: pm, mitigador: nexus-master, escalacao: nexus-master, severidade: P1 }
|
|
12
|
+
- { categoria: Perda ou corrupção de dados, dono: data-engineer, mitigador: devops, escalacao: nexus-master, severidade: P0 }
|
|
13
|
+
- { categoria: Escopo furado (invenção), dono: po, mitigador: pm, escalacao: nexus-master, severidade: P2 }
|
|
14
|
+
- { categoria: Dependência externa instável, dono: devops, mitigador: architect, escalacao: nexus-master, severidade: P2 }
|
|
15
|
+
- { categoria: Acessibilidade/UX quebrada, dono: ux-design-expert, mitigador: dev, escalacao: nexus-master, severidade: P2 }
|
|
16
|
+
- { categoria: Falha de release, dono: devops, mitigador: dev, escalacao: nexus-master, severidade: P0 }
|
|
17
|
+
- { categoria: Requisito ambíguo, dono: analyst, mitigador: pm, escalacao: nexus-master, severidade: P3 }
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# Matriz de risco — donos, mitigadores e SLA
|
|
21
|
+
|
|
22
|
+
> A FONTE ÚNICA é o frontmatter YAML acima; a tabela abaixo é derivada dele. Um risco sem dono é um
|
|
23
|
+
> risco órfão — o validator `risk-ownership` confere que todo dono, mitigador e escalação existe no
|
|
24
|
+
> roster. O SLA amarra a severidade ao tempo de resposta esperado.
|
|
25
|
+
|
|
26
|
+
## SLA por severidade
|
|
27
|
+
|
|
28
|
+
| Severidade | Resposta esperada |
|
|
29
|
+
|---|---|
|
|
30
|
+
| P0 | imediato |
|
|
31
|
+
| P1 | menos de 4h |
|
|
32
|
+
| P2 | menos de 24h |
|
|
33
|
+
| P3 | menos de 1 semana |
|
|
34
|
+
|
|
35
|
+
## Categorias (10)
|
|
36
|
+
|
|
37
|
+
| Categoria | Dono (detecta) | Mitigador (corrige) | Escalação | Severidade |
|
|
38
|
+
|---|---|---|---|---|
|
|
39
|
+
| Dívida técnica | architect | dev | nexus-master | P2 |
|
|
40
|
+
| Regressão de qualidade | qa | dev | nexus-master | P1 |
|
|
41
|
+
| Vulnerabilidade de segurança | qa | devops | nexus-master | P0 |
|
|
42
|
+
| Estouro de custo | pm | nexus-master | nexus-master | P1 |
|
|
43
|
+
| Perda ou corrupção de dados | data-engineer | devops | nexus-master | P0 |
|
|
44
|
+
| Escopo furado (invenção) | po | pm | nexus-master | P2 |
|
|
45
|
+
| Dependência externa instável | devops | architect | nexus-master | P2 |
|
|
46
|
+
| Acessibilidade/UX quebrada | ux-design-expert | dev | nexus-master | P2 |
|
|
47
|
+
| Falha de release | devops | dev | nexus-master | P0 |
|
|
48
|
+
| Requisito ambíguo | analyst | pm | nexus-master | P3 |
|
|
49
|
+
|
|
50
|
+
## Como usar
|
|
51
|
+
|
|
52
|
+
- **Dono** monitora a categoria e levanta a bandeira quando o risco aparece (ele detecta, não
|
|
53
|
+
necessariamente conserta).
|
|
54
|
+
- **Mitigador** executa a correção sob o SLA da severidade.
|
|
55
|
+
- **Escalação** entra quando o SLA estoura ou o mitigador não converge — o `nexus-master` medeia.
|
|
56
|
+
- Um risco P0 (segurança, dados, release) para a linha: imediato, sem exceção.
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: mcp-server-selection-matrix
|
|
3
|
+
domain: integration
|
|
4
|
+
agents: [devops]
|
|
5
|
+
when: "ao escolher e adicionar um servidor MCP ao roster do projeto"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Matriz de seleção de servidor MCP — o melhor por categoria do NEXUS
|
|
9
|
+
|
|
10
|
+
Adicionar um MCP ao roster é decisão de DevOps (@devops detém a authority exclusiva de add/remove/configure de
|
|
11
|
+
MCP). O erro comum é tratar isso como "instala o primeiro que aparece na busca": pega-se um fork community não
|
|
12
|
+
mantido, com token de admin, write habilitado, sem nunca ter rodado o servidor uma vez fora do agente. Este pack dá
|
|
13
|
+
a **matriz canônica** (melhor servidor por categoria), o critério de escolha e o passo **obrigatório** de validar
|
|
14
|
+
com o **MCP Inspector** antes de qualquer `mcp add`.
|
|
15
|
+
|
|
16
|
+
## O problema
|
|
17
|
+
|
|
18
|
+
Os tells de um roster de MCP mal montado:
|
|
19
|
+
|
|
20
|
+
1. **Fork community no lugar do oficial** — pega `asifdotpy/github-mcp-server` em vez de `github/github-mcp-server`;
|
|
21
|
+
`bkeys73/mcp-supabase` em vez de `supabase-community/supabase-mcp`. O awesome-mcp-servers lista 142 servidores de
|
|
22
|
+
database e 188 de busca — a maioria é redundante. Sem marcar o oficial, escolhe-se ruído.
|
|
23
|
+
2. **Servidor arquivado tratado como vivo** — `@modelcontextprotocol/server-github`, `server-postgres`,
|
|
24
|
+
`server-brave-search`, `server-puppeteer`, `server-gitlab` etc. **foram arquivados** para `servers-archived`. Quem
|
|
25
|
+
copia config de tutorial velho instala um servidor morto.
|
|
26
|
+
3. **Write por padrão** — adiciona supabase ou github sem `--read-only`. O agente ganha poder de `DROP TABLE` ou
|
|
27
|
+
`git push --force` num servidor que devia só ler.
|
|
28
|
+
4. **Credencial com escopo total** — um Personal Access Token `repo` + `admin:org` colado no env quando o agente só
|
|
29
|
+
precisava ler issues. Token vaza no log, no handoff, no histórico do shell.
|
|
30
|
+
5. **Nunca validou** — adiciona o MCP direto no roster e descobre no meio de uma story que o servidor não sobe, pede
|
|
31
|
+
prompt em vez de expor tools, ou expõe 60 tools quando precisava de 5.
|
|
32
|
+
6. **Transport errado** — usa stdio (local, processo filho) onde queria HTTP remoto gerenciado, ou vice-versa, e
|
|
33
|
+
depois briga com Docker/credencial que nem precisava existir.
|
|
34
|
+
|
|
35
|
+
## O conhecimento
|
|
36
|
+
|
|
37
|
+
### Critério de escolha (a ordem importa)
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
1. Oficial > community # mantido pelo vendor/steering group, não por um fork
|
|
41
|
+
2. Manutenção ativa # commits recentes, releases, issues respondidas
|
|
42
|
+
3. Read-only por padrão # write só quando a categoria exige e a story justifica
|
|
43
|
+
4. Credencial de escopo mínimo # o menor token/role que faz a tool funcionar
|
|
44
|
+
5. Transport adequado # stdio p/ local-dev, HTTP/SSE p/ remoto gerenciado
|
|
45
|
+
6. Validado no MCP Inspector # GATE — nunca entra no roster sem passar por aqui
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
"Oficial" tem um significado concreto: os **reference servers** vivem em `modelcontextprotocol/servers` e são
|
|
49
|
+
mantidos pelo steering group; os servidores de vendor (`github/`, `supabase-community/`, `microsoft/`, `exa-labs/`,
|
|
50
|
+
`brave/`) são o canônico de cada produto. Tudo o mais é community — útil, mas só depois de descartar o oficial.
|
|
51
|
+
|
|
52
|
+
### Transport: stdio vs HTTP/SSE
|
|
53
|
+
|
|
54
|
+
| Transport | Como roda | Quando usar | Custo |
|
|
55
|
+
|---|---|---|---|
|
|
56
|
+
| **stdio** | processo filho local (`npx`/`uvx`/binário) | dev local, filesystem/git, controle total da credencial | você gerencia processo + token |
|
|
57
|
+
| **HTTP/SSE (remoto)** | endpoint hospedado pelo vendor, OAuth | quando o vendor oferece remoto gerenciado (GitHub, Exa, Supabase) | sem Docker/atualização manual, mas depende do vendor |
|
|
58
|
+
|
|
59
|
+
Regra prática: **filesystem, git e qualquer coisa que toque o disco do dev → stdio sempre.** Serviço de nuvem com
|
|
60
|
+
remoto oficial (GitHub `https://api.githubcopilot.com/mcp/`, Exa `https://mcp.exa.ai/mcp`, Supabase
|
|
61
|
+
`https://mcp.supabase.com/mcp`) → prefira o **HTTP remoto** e evite manter Docker/binário/atualização à mão.
|
|
62
|
+
|
|
63
|
+
### A matriz — melhor MCP por categoria do NEXUS
|
|
64
|
+
|
|
65
|
+
| Categoria NEXUS | Servidor canônico | Origem | Transport | Escopo de tools | Agente consumidor |
|
|
66
|
+
|---|---|---|---|---|---|
|
|
67
|
+
| Dados / DB | `supabase-community/supabase-mcp` | oficial (vendor) | stdio (npx) **ou** HTTP remoto | `execute_sql`, `apply_migration`, branches, projetos | @data-engineer, @dev |
|
|
68
|
+
| Browser / QA | `microsoft/playwright-mcp` (`@playwright/mcp`) | oficial (Microsoft) | stdio (npx) | navegar, snapshot a11y, click/type, screenshot | @qa, @ux-design-expert |
|
|
69
|
+
| DevOps / Git remoto | `github/github-mcp-server` | oficial (GitHub) | HTTP remoto **ou** stdio/Docker | issues, PRs, repos, actions (por toolset) | **@devops apenas** |
|
|
70
|
+
| Filesystem | `@modelcontextprotocol/server-filesystem` | reference (steering group) | stdio (npx) | leitura/escrita de arquivo com paths permitidos | @dev |
|
|
71
|
+
| Git local | `mcp-server-git` | reference (steering group) | stdio (uvx) | ler/buscar/manipular repo Git local | @dev |
|
|
72
|
+
| Fetch / web → markdown | `mcp-server-fetch` | reference (steering group) | stdio (uvx) | buscar URL e converter p/ LLM | @analyst, @dev |
|
|
73
|
+
| Memória / knowledge graph | `@modelcontextprotocol/server-memory` | reference (steering group) | stdio (npx) | grafo de conhecimento persistente | @analyst |
|
|
74
|
+
| Busca web | `exa-labs/exa-mcp-server` **ou** `brave/brave-search-mcp-server` | oficial (vendor) | HTTP remoto (Exa) / stdio (Brave) | `web_search`, research, crawling | @analyst |
|
|
75
|
+
|
|
76
|
+
> **Authority:** adicionar/remover/configurar QUALQUER linha desta matriz é operação **exclusiva do @devops**. O
|
|
77
|
+
> servidor `github-mcp-server` em particular só é consumido pelo @devops — push, PR e gerência de repo remoto não
|
|
78
|
+
> saem de outro agente.
|
|
79
|
+
|
|
80
|
+
### Config: ruim → bom
|
|
81
|
+
|
|
82
|
+
#### Filesystem — escopo de paths
|
|
83
|
+
|
|
84
|
+
```jsonc
|
|
85
|
+
// RUIM — sem restrição: o agente lê/escreve qualquer lugar do disco
|
|
86
|
+
{ "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/"] }
|
|
87
|
+
|
|
88
|
+
// BOM — paths permitidos explícitos; o servidor recusa fora deles
|
|
89
|
+
{ "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem",
|
|
90
|
+
"/Users/me/projeto/docs", "/Users/me/projeto/packages"] }
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### Git local — repo escopado
|
|
94
|
+
|
|
95
|
+
```jsonc
|
|
96
|
+
// RUIM — server arquivado + sem repo definido
|
|
97
|
+
{ "command": "npx", "args": ["-y", "@modelcontextprotocol/server-git"] } // não existe mais
|
|
98
|
+
|
|
99
|
+
// BOM — reference server oficial via uvx, repo explícito
|
|
100
|
+
{ "command": "uvx", "args": ["mcp-server-git", "--repository", "/Users/me/projeto"] }
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### Supabase — read-only e projeto escopado
|
|
104
|
+
|
|
105
|
+
```jsonc
|
|
106
|
+
// RUIM — write habilitado, sem escopo de projeto, token inline com todos os escopos
|
|
107
|
+
{ "command": "npx", "args": ["-y", "@supabase/mcp-server-supabase"],
|
|
108
|
+
"env": { "SUPABASE_ACCESS_TOKEN": "sbp_live_admin_total_no_codigo" } }
|
|
109
|
+
|
|
110
|
+
// BOM — --read-only (queries rodam como Postgres read-only user),
|
|
111
|
+
// --project-ref escopa só o projeto, token vem do ambiente
|
|
112
|
+
{ "command": "npx",
|
|
113
|
+
"args": ["-y", "@supabase/mcp-server-supabase", "--read-only", "--project-ref=abcdef123456"],
|
|
114
|
+
"env": { "SUPABASE_ACCESS_TOKEN": "${SUPABASE_ACCESS_TOKEN}" } }
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
`--read-only` faz `execute_sql`/`apply_migration` rodarem como usuário Postgres read-only; `--project-ref` remove as
|
|
118
|
+
tools de nível de conta (`list_projects`, `list_organizations`). Em CI, prefira o remoto:
|
|
119
|
+
`https://mcp.supabase.com/mcp?project_ref=abc123&read_only=true`.
|
|
120
|
+
|
|
121
|
+
#### GitHub — read-only, toolsets e remoto
|
|
122
|
+
|
|
123
|
+
```jsonc
|
|
124
|
+
// RUIM — server arquivado, token com escopo total no código
|
|
125
|
+
{ "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"], // arquivado
|
|
126
|
+
"env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_token_repo_admin_org_workflow" } }
|
|
127
|
+
|
|
128
|
+
// BOM (stdio/binário) — oficial, read-only, só os toolsets necessários, token do ambiente
|
|
129
|
+
{ "command": "github-mcp-server", "args": ["stdio", "--read-only", "--toolsets=repos,issues,pull_requests"],
|
|
130
|
+
"env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PAT}" } }
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
```http
|
|
134
|
+
# BOM (remoto HTTP) — sem Docker, OAuth, headers de hardening
|
|
135
|
+
# endpoint:
|
|
136
|
+
https://api.githubcopilot.com/mcp/
|
|
137
|
+
X-MCP-Readonly: true
|
|
138
|
+
X-MCP-Toolsets: repos,issues,pull_requests
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### Playwright — perfil isolado e capabilities mínimas
|
|
142
|
+
|
|
143
|
+
```jsonc
|
|
144
|
+
// RUIM — perfil persistente (estado vaza entre sessões), todas as caps
|
|
145
|
+
{ "command": "npx", "args": ["@playwright/mcp@latest", "--caps=vision,pdf,devtools"] }
|
|
146
|
+
|
|
147
|
+
// BOM — --isolated (sessão descartável, sem storage state vazando), só a cap que a story pede
|
|
148
|
+
{ "command": "npx", "args": ["@playwright/mcp@latest", "--isolated", "--caps=vision"] }
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### Busca — chave de escopo mínimo
|
|
152
|
+
|
|
153
|
+
```jsonc
|
|
154
|
+
// RUIM — server de busca arquivado
|
|
155
|
+
{ "command": "npx", "args": ["-y", "@modelcontextprotocol/server-brave-search"], // arquivado
|
|
156
|
+
"env": { "BRAVE_API_KEY": "chave_colada" } }
|
|
157
|
+
|
|
158
|
+
// BOM (Brave) — server oficial do vendor, chave do ambiente
|
|
159
|
+
{ "command": "npx", "args": ["-y", "@brave/brave-search-mcp-server"],
|
|
160
|
+
"env": { "BRAVE_API_KEY": "${BRAVE_API_KEY}" } }
|
|
161
|
+
|
|
162
|
+
// BOM (Exa) — remoto, sem setup local; ou local com --tools restrito
|
|
163
|
+
{ "url": "https://mcp.exa.ai/mcp" }
|
|
164
|
+
// local, só as tools que a story usa:
|
|
165
|
+
{ "command": "npx", "args": ["-y", "exa-mcp-server", "--tools=web_search_exa,crawling"],
|
|
166
|
+
"env": { "EXA_API_KEY": "${EXA_API_KEY}" } }
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### O GATE obrigatório: validar no MCP Inspector ANTES do roster
|
|
170
|
+
|
|
171
|
+
**Nenhum servidor entra no roster sem passar pelo Inspector.** O Inspector (`@modelcontextprotocol/inspector`) sobe o
|
|
172
|
+
servidor isolado, mostra as tools/resources reais e prova que a credencial funciona — antes de você confiar nele
|
|
173
|
+
dentro de um agente.
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# 1. CLI mode — lista as tools que o servidor REALMENTE expõe (não as que o README promete)
|
|
177
|
+
npx @modelcontextprotocol/inspector --cli node build/index.js --method tools/list
|
|
178
|
+
|
|
179
|
+
# 2. Passa a credencial via -e e roda o binário/comando real do servidor
|
|
180
|
+
npx @modelcontextprotocol/inspector -e SUPABASE_ACCESS_TOKEN=$SUPABASE_ACCESS_TOKEN \
|
|
181
|
+
npx -y @supabase/mcp-server-supabase --read-only --project-ref=abcdef123456
|
|
182
|
+
|
|
183
|
+
# 3. UI mode — abre o cliente em :6274 (proxy em :6277) p/ inspeção interativa
|
|
184
|
+
npx @modelcontextprotocol/inspector node build/index.js
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Sinais de **reprovação** no Inspector (não adicione ao roster):
|
|
188
|
+
- Mostra **"(N prompts)" em vez de "(N tools)"** — o servidor subiu mas **falhou autenticação** (credencial não
|
|
189
|
+
chegou). Corrija o env antes de prosseguir.
|
|
190
|
+
- A lista de tools não bate com o esperado, ou expõe write quando você passou `--read-only`.
|
|
191
|
+
- O servidor não sobe, trava ou exige um runtime que o projeto não tem.
|
|
192
|
+
|
|
193
|
+
Só depois de uma `tools/list` limpa, com a credencial certa e o escopo correto, o @devops roda o `mcp add`.
|
|
194
|
+
|
|
195
|
+
### Hardening — não-negociável
|
|
196
|
+
|
|
197
|
+
- **Read-only por padrão.** DB, git remoto e qualquer servidor com poder de escrita entram com `--read-only` (ou
|
|
198
|
+
`X-MCP-Readonly: true`). Write só quando a story exige e o @devops aprova.
|
|
199
|
+
- **Escopo de credencial mínimo.** O menor PAT/role que faz a tool funcionar. GitHub: só os escopos que você se
|
|
200
|
+
sente confortável em dar ao agente; nunca `admin:org` "por garantia". Supabase: `--project-ref` para tirar as
|
|
201
|
+
tools de conta.
|
|
202
|
+
- **Credencial via ambiente, nunca inline.** Token vai em `${VAR}`/env, não colado no JSON que vira commit/handoff.
|
|
203
|
+
- **Tools/toolsets enxutos.** `--toolsets` (GitHub), `--tools` (Exa), `--caps` (Playwright) reduzem a superfície:
|
|
204
|
+
menos tools expostas = menos vetor de erro/abuso.
|
|
205
|
+
- **Sessão descartável onde fizer sentido.** Playwright `--isolated` evita vazar storage state entre stories.
|
|
206
|
+
|
|
207
|
+
## Checklist
|
|
208
|
+
|
|
209
|
+
Antes de o @devops rodar `mcp add`, todo "não" é um bloqueio:
|
|
210
|
+
|
|
211
|
+
- [ ] É o servidor **oficial** da categoria (reference do steering group ou do vendor), não um fork community?
|
|
212
|
+
- [ ] O servidor **não está arquivado** (não é `@modelcontextprotocol/server-{github,postgres,brave-search,...}`)?
|
|
213
|
+
- [ ] Tem **manutenção ativa** (commits/releases recentes)?
|
|
214
|
+
- [ ] O **transport** é o certo (stdio p/ local; HTTP remoto quando o vendor oferece gerenciado)?
|
|
215
|
+
- [ ] Está em **read-only** por padrão (ou a escrita é justificada pela story)?
|
|
216
|
+
- [ ] A **credencial é de escopo mínimo** e vem do **ambiente** (`${VAR}`), nunca inline?
|
|
217
|
+
- [ ] O conjunto de **tools/toolsets/caps** está enxuto p/ o que a story precisa?
|
|
218
|
+
- [ ] Foi **validado no MCP Inspector** — `tools/list` limpa, mostra "(N tools)" e não "(N prompts)"?
|
|
219
|
+
- [ ] É consumido pelo **agente certo** (ex.: `github-mcp-server` só @devops)?
|
|
220
|
+
|
|
221
|
+
## Tabela de decisão
|
|
222
|
+
|
|
223
|
+
| Situação | Decisão |
|
|
224
|
+
|---|---|
|
|
225
|
+
| Preciso ler/escrever arquivos do projeto | `@modelcontextprotocol/server-filesystem` (stdio) com paths permitidos explícitos |
|
|
226
|
+
| Preciso operar um repo Git **local** | `mcp-server-git` (uvx, stdio) com `--repository` escopado |
|
|
227
|
+
| Preciso de issues/PRs/repo **remoto** no GitHub | `github/github-mcp-server` — remoto HTTP ou stdio, **read-only + toolsets**, **só @devops** |
|
|
228
|
+
| Preciso consultar/migrar banco Supabase | `supabase-community/supabase-mcp` com `--read-only` + `--project-ref` |
|
|
229
|
+
| Preciso de QA de browser / screenshot | `microsoft/playwright-mcp` (`--isolated`, `--caps` mínimo) |
|
|
230
|
+
| Preciso de busca web p/ pesquisa | Exa (`https://mcp.exa.ai/mcp`, remoto) ou Brave (oficial, stdio) com `--tools` restrito |
|
|
231
|
+
| Preciso buscar URL e virar markdown | `mcp-server-fetch` (uvx, stdio) |
|
|
232
|
+
| Preciso de memória persistente entre sessões | `@modelcontextprotocol/server-memory` (stdio) |
|
|
233
|
+
| Encontrei só um fork community da categoria | Procure o oficial primeiro; se não existir, **só** após Inspector + hardening + aprovação @devops |
|
|
234
|
+
| O tutorial manda usar `@modelcontextprotocol/server-{github,postgres,...}` | **Recuse** — está arquivado; use o servidor do vendor |
|
|
235
|
+
| O Inspector mostra "(N prompts)" | **Não adicione** — credencial falhou; corrija o env e revalide |
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Copy que converte — clareza antes de esperteza
|
|
2
|
+
|
|
3
|
+
Copy de conversão não é escrever bonito. É fazer a pessoa parar, entender a oferta em três segundos e
|
|
4
|
+
ter uma razão para agir agora. O adjetivo empilhado ("inovador, revolucionário, único") é o que se
|
|
5
|
+
escreve quando não se tem uma promessa de verdade.
|
|
6
|
+
|
|
7
|
+
## A anatomia que converte
|
|
8
|
+
|
|
9
|
+
1. **Headline com promessa específica.** O que a pessoa ganha, em número quando possível. "Economize 6
|
|
10
|
+
horas por semana" vence "produtividade revolucionária". Especificidade é credibilidade.
|
|
11
|
+
2. **Subheadline / abertura.** A razão de continuar lendo — o custo de não resolver ou a facilidade de resolver.
|
|
12
|
+
3. **Corpo que antecipa objeções.** Cada "sim, mas..." do leitor (é caro? é difícil? funciona pra mim?)
|
|
13
|
+
respondido antes de ele fechar a página.
|
|
14
|
+
4. **Prova.** Número, caso, garantia, redução de risco — o que torna o "sim" seguro.
|
|
15
|
+
5. **Um call-to-action, sem atrito.** Uma ação clara, com o menor esforço possível.
|
|
16
|
+
|
|
17
|
+
## Clareza vence esperteza
|
|
18
|
+
|
|
19
|
+
A pessoa tem de entender na primeira leitura. Trocadilho que precisa ser explicado já falhou. A copy
|
|
20
|
+
esperta premia o ego do autor; a copy clara converte. Na dúvida, corte a piada e diga a coisa.
|
|
21
|
+
|
|
22
|
+
## Específico vence superlativo
|
|
23
|
+
|
|
24
|
+
| Fraco (superlativo) | Forte (específico) |
|
|
25
|
+
|---|---|
|
|
26
|
+
| "resultados incríveis" | "3 leads a mais por dia" |
|
|
27
|
+
| "solução revolucionária" | "configura em 5 minutos, sem código" |
|
|
28
|
+
| "atendimento de excelência" | "resposta em menos de 2 horas, sempre" |
|
|
29
|
+
|
|
30
|
+
## Objeções: a venda mora nos "sim, mas..."
|
|
31
|
+
|
|
32
|
+
Liste o que o leitor pensa antes de fechar e responda cada um NA copy:
|
|
33
|
+
- "é caro" → mostre o retorno / o custo de não ter.
|
|
34
|
+
- "é complicado" → mostre a facilidade / o tempo de setup.
|
|
35
|
+
- "não funciona pra mim" → mostre o caso parecido com o dele.
|
|
36
|
+
- "e se eu me arrepender" → garantia / risco reduzido.
|
|
37
|
+
|
|
38
|
+
## Anti-padrões
|
|
39
|
+
|
|
40
|
+
- Adjetivo empilhado sem promessa concreta.
|
|
41
|
+
- Dois CTAs — dividem a decisão; nenhum — não vende.
|
|
42
|
+
- Prometer o que o produto não entrega — copy é contrato; overpromise é churn.
|
|
43
|
+
- Esconder o preço/oferta atrás de esperteza — clareza fecha, mistério cansa.
|