工程规范

schematize-go 的完整规范文档。可复制到你的仓库、粘贴给你的智能体,或安装该技能让 Claude Code 自动执行。

下载 .md

权威文档为葡萄牙语——唯一可信来源。站点界面已翻译;为避免规范文档产生偏差,规范本身保留原文。

Padrões e Diretrizes de Engenharia

Versão: 5.6 Atualizado em: 2026-06-12 Status: Documento normativo e contexto operacional. Desvios exigem ADR aprovado.


0. Como Ler

  • MUST / Obrigatório — regra. Desvio bloqueia merge ou exige ADR.
  • SHOULD / Recomendado — padrão. Desvio precisa de justificativa no PR.
  • MAY / Opcional — sugestão.
  • VETADO / Proibido — não existe "atalho". Não se faz, não se cogita, não se "resolve depois". Burlar é incidente, não decisão técnica.

Quando este documento conflitar com a realidade do problema, registre um ADR explicando o desvio. Padrão sem exceção vira dogma; dogma vira dívida. Mas itens marcados VETADO não têm ADR de exceção — são pisos de segurança e integridade, não preferências.

Versões concretas de stacks ficam no Anexo A, atualizado independentemente deste corpo.


0.1. Aplicação Universal — Este Arquivo é Contexto Máximo

MUST

  • Este documento é anexado a TODO prompt / sessão / tarefa de engenharia (humana ou assistida por IA). É contexto pinado, não referência opcional. Se a tarefa toca código, infra, dados, deploy ou design de sistema, este arquivo está em contexto. Sem exceção.
  • Nenhuma resposta, PR, geração de código ou decisão arquitetural é válida se ignorar este documento. "Não estava no contexto" não é desculpa — garantir o anexo é responsabilidade de quem abre a tarefa, e a ausência dele é, por si só, motivo para parar e recarregar o contexto antes de produzir qualquer coisa.
  • Em caso de conflito entre uma instrução pontual ("faz rápido", "ignora o teste", "depois a gente arruma") e este documento, este documento vence. Pressa não revoga regra.
  • Assistentes de IA operam sob as mesmas regras dos humanos (§34) e sob as proibições explícitas da §37. Velocidade de geração nunca justifica violar um piso.

Um padrão que não está no contexto na hora da decisão é um padrão que não existe. Por isso ele é pinado, não linkado.


1. Filosofia

Prioridades, em ordem de desempate:

  1. Clareza > esperteza
  2. Simplicidade > abstração antecipada
  3. Manutenibilidade > velocidade pontual
  4. Observabilidade > debugging manual
  5. Segurança por padrão > segurança como camada final
  6. Evolução incremental > big-bang
  7. Registro do que foi decidido > memória de quem decidiu (ver §28)

Princípios: Clean Code, SOLID, KISS, DRY (com bom senso — duplicação acidental ≠ duplicação semântica).

Regra suprema: se algo aumenta acoplamento, reduz observabilidade, cria dependência desnecessária, vaza segredo, mistura contexto, ou pula registro ou adiciona complexidade sem benefício claro, provavelmente está errado.


2. Estrutura de Repositórios

MUST

  • Um repositório = uma aplicação ou um bounded context.
  • Comunicação entre serviços via HTTP, gRPC, eventos ou mensageria — nunca via banco compartilhado.
  • Cada serviço é dono do seu schema.

VETADO

  • Aplicação monolítica que acopla múltiplos bounded contexts num só deploy/processo. Não se cogita "começar monolito e quebrar depois" sem ADR explícito de plano e prazo de quebra. Misturar domínios de negócio "pra entregar rápido" é dívida disfarçada de produtividade.
  • Monólito distribuído — o pior dos dois mundos: serviços separados fisicamente, mas acoplados por banco compartilhado, shared lib de domínio (§7) ou chamadas síncronas em cascata sem fronteira. Tão proibido quanto o monólito clássico.
  • Big ball of mud — código sem fronteira de contexto, onde tudo importa tudo.

SHOULD

  • Evitar mais de um domínio de negócio no mesmo repositório.
  • Leitura cross-service por réplica read-only só com ADR e contrato documentado.

MAY

  • Modular monolith (módulos com fronteira de contexto rígida, schema separado, comunicação por interface interna) somente com ADR que justifique estágio do produto e contenha o plano de extração. É exceção registrada, não default. Nunca usar como atalho para colar domínios.

Não existe "MVP monolítico que vira microserviço depois" sem o ADR que prova que o depois tem data. Sem isso, "depois" é "nunca", e "nunca" é um big ball of mud em produção.


3. Linguagens

Backend — apenas Go e Rust.

Cenário Stack
Serviços backend, APIs, glue code, concorrência, padrão da casa Go
Performance crítica, segurança de memória Rust

Frontend — Node é 100% permitido (e só frontend). Frontend baseado em Node é a stack da casa porque hoje é o melhor do mercado: Next.js é a stack principal, mas Astro e outros frameworks consolidados são permitidos. O server-side do próprio front (route handlers, server actions, BFF) faz parte do frontend e é governado pelo §13.4 e §38 (segredo só server-side, etc.). Isso vale apenas para frontend — não reabre Node como linguagem de serviço backend (ver o MUST abaixo e §3.1: backend novo em Node é proibido; o ganho marginal de tooling/npm não compensa o histórico de incidentes de segurança).

MUST

  • Versão exata em uso fica no Anexo A.
  • Não misturar linguagens dentro do mesmo bounded context sem ADR.
  • Backend novo só em Go ou Rust. Nenhum serviço backend novo em Node.

SHOULD

  • Default é Go; Rust quando performance crítica ou segurança de memória justificam. Em empate técnico, Go vence (padrão do time).
  • Frameworks são bem-vindos; abstrações mágicas não. Critério: consigo entender o stack trace?

3.1 Node legado (backend) — migração para Go/Rust

Node como linguagem de serviço backend está em saída. Tudo que existe em Node backend será migrado para Go ou Rust, guiado por esforço (não big-bang) e medido por funcionalidade do módulo, não por linha.

Modelo da métrica. Um módulo tem N funcionalidades (ex.: 10 — cálculo, ABAC, CRUD, etc.). O quanto uma mudança "pesa" é a fração de funcionalidades que ela altera ou cria sobre o total do módulo. Ex.: módulo com 10 funcionalidades — refatorar 2 = 20%; refatorar 3 (ou criar ~4 novas) ≈ 30%.

MUST

  • Não mexer no que está feito em Node, a menos que solicitado. Node backend funcionando fica como está até ser tocado.
  • Gatilho de extração (~30%): quando uma mudança atingir ~30% das funcionalidades do módulo (alteradas + novas), não cresça o Node — extraia essa(s) funcionalidade(s) para um módulo Go/Rust à parte e incorpore o comportamento Node nessa nova base.
  • Extração incremental: conforme se mexe no módulo Node ao longo do tempo, vai-se extraindo aos poucos para Go/Rust.
  • Virada dos 50%: quando ~50% do módulo já estiver extraído/inutilizado (substituído pela versão Go/Rust), migra-se os 50% restantes de uma vez — encerra o módulo Node.
  • Ajuste pontual não porta. Mudança pequena/localizada (abaixo do gatilho) é feita no próprio Node, sem portabilidade.
  • Toda migração registra ADR (§27) e segue o DDD híbrido/coexistência (§4.X, §36): flag de coexistência, sem big-bang.

Os percentuais (~30% pra extrair, ~50% pra finalizar) são os limiares da casa; ajuste por ADR se um módulo específico exigir. A regra é: parou de ser ajuste pontual, vira extração; passou da metade, termina.

3.2 PHP — proibido

VETADO — PHP não é linguagem da casa, em nenhuma camada.

  • Nenhum código novo em PHP.
  • Projeto existente em PHP é migrado sumariamente para Go/Rust (backend) — prioridade de migração, com ADR e plano. Não é "quando der"; é dívida ativa a ser zerada.

4. Arquitetura

MUST — todos os projetos

  • Separação explícita de camadas: domain, application, infrastructure, interface.
  • Inversão de dependência: domínio não conhece infra.
  • Domínio não importa frameworks nem ORM.

SHOULD — projetos com regra de negócio relevante

  • DDD tático (agregados, value objects, eventos de domínio).
  • Arquitetura hexagonal (ports & adapters).

MAY — CRUDs simples

  • Manter as 4 camadas, dispensar táticas DDD pesadas.

Dependências permitidas

interface       → application
application     → domain
infrastructure  → domain, application

Dependências proibidas

domain          → qualquer outra camada
domain          → frameworks, ORM, libs de IO
application     → interface

Anti-Corruption Layer

MUST em integrações com sistemas externos: adapter dedicado em infrastructure/external/ que traduz o modelo externo para o modelo de domínio. Nunca expor DTOs externos diretamente no domínio.

4.X DDD híbrido durante transição

Projetos legados onde código já existe sem separação de camadas podem adotar DDD progressivamente em vez de big-bang. Regras:

MUST

  • Toda nova feature/refactor em código tocado segue o layout completo (domain/, application/, infrastructure/, interface/) — não introduzir mais código "flat".
  • Ao mover/quebrar arquivo legado, organize já em folders DDD mesmo que internamente alguma classe ainda misture responsabilidades (ex.: service em application/ ainda chamando SQL direto). Estrutura primeiro, inversão depois.
  • Cada PR que toca arquivo híbrido deve mover ao menos um pedaço pra direção certa (ex.: extrair entidade pra domain/, mover query pra infrastructure/repositories/).
  • ADR registrando o débito e o plano de remoção: <project>/docs/adr/<n>-ddd-migration-<contexto>.md.

SHOULD

  • Manter teste de cobertura por camada (§22) durante a transição — domain começa com 0%, sobe a cada PR.
  • Linter ou guard test que rejeita imports proibidos logo que possível (mesmo que com whitelist de exceções legadas):
    • domain/ não importa @nestjs/*, pg, axios, infrastructure/*, application/*, interface/*.
    • application/ não importa interface/*.

MAY

  • Marcar arquivos híbridos com comment // @ddd-hybrid pra busca fácil e cleanup priorizado.

5. Estrutura de Pastas

Node.js

src/
├── domain/           # entities, value-objects, services, events, repositories (interfaces)
├── application/      # use-cases, dto, commands, queries
├── infrastructure/   # persistence, messaging, external, observability
├── interface/        # http, grpc, cli
├── shared/
└── config/
tests/

Go

cmd/<app-name>/
internal/
├── domain/
├── application/
├── infrastructure/
├── interface/
├── shared/
└── config/
tests/

Rust

src/
├── domain/
├── application/
├── infrastructure/
├── interface/
├── shared/
└── config/
tests/

6. Complexidade e Tamanho

MUST — arquivos pequenos, micro-funções

  • Arquivo alvo: ≤ 300 linhas. Acima disso, o arquivo deve ser quebrado — extraia responsabilidades em módulos menores e a lógica em micro-funções com nome que explica a intenção. Não existe "arquivo de 800 linhas porque é coeso": coesão real cabe em arquivos pequenos colaborando.
  • Funções pequenas e de responsabilidade única. Ideal ≤ 50 linhas; função grande vira micro-funções compostas. Use case: uma responsabilidade.
  • Exceções (não disparam quebra): testes, migrations, código gerado, schemas/fixtures.

MUST — toda função documentada

  • TODA função/método tem comentário no formato de doc da linguagem (JSDoc, GoDoc, rustdoc). O comentário declara, no mínimo:
    • O quê — o que a função faz, em uma linha.
    • Onde é usada / prevista — quem chama, em que fluxo/camada ela foi pensada pra servir (ex.: "usado pelo use-case CreateOrder", "handler HTTP de /v1/checkout"). Isto dá contexto explícito de propósito e evita função órfã.
    • Parâmetros, retorno e efeitos colaterais relevantes.
  • Esse comentário é a fonte do índice de microfunções (§39) — escreva pensando que ele será extraído e indexado, não como enfeite.

Convenção mínima (adapte à linguagem):

/**
 * O quê: valida o payload de checkout e cria o pedido.
 * Onde:  use-case CreateOrder; chamado pelo handler POST /v1/checkout.
 * Efeitos: persiste em orders, publica catalog.order.created via outbox.
 */

Bloqueio rígido em CI

  • Arquivo de produção > 300 linhas sem quebra (exceto as exceções acima) → bloqueia.
  • Função de produção sem doc-comment → bloqueia.
  • Complexidade ciclomática > 15 em função de produção.
  • Aninhamento > 4 níveis.

Linha de código é proxy ruim para complexidade — complexidade ciclomática é a métrica honesta. Mas arquivo gigante e função sem contexto são dívidas óbvias: quebre e documente antes do merge.


7. Dependências Internas e Shared Libraries

MUST

  • Shared libraries são mínimas e com escopo claramente delimitado.
  • Permitido como shared: observabilidade, autenticação/auth, primitives de infraestrutura, SDKs internos, logging, configuração.

MUST NOT

  • Criar commons / core-lib / platform-utils genéricos.
  • Compartilhar lógica de domínio entre bounded contexts.
  • Compartilhar entidades de domínio. Cada contexto modela o seu.

O caminho mais rápido pra um monólito distribuído é uma shared lib chamada commons.

SHOULD

  • Shared libs versionadas com SemVer próprio.
  • Breaking changes em shared lib exigem ADR.

8. CQRS e Padrões de Aplicação

  • Commands: alteram estado, retornam id ou void.
  • Queries: nunca alteram estado, otimizadas para leitura, podem usar projeções.
  • CQRS não exige event sourcing.

9. Eventos e Mensageria

MUST — produção e consumo

  • Eventos são imutáveis e versionados (v1, v2).
  • Consumidores idempotentes (deduplicação por id de evento).
  • Suporte a replay.

MUST — compatibilidade evolutiva

  • Novos campos são opcionais, com default seguro.
  • Nunca remover ou renomear campo sem nova versão do evento.
  • Consumidores ignoram campos desconhecidos (forward compatible).
  • Coexistência de versões durante janela de migração documentada.

MUST — entrega

  • Transactional Outbox para publicação de eventos. Dual-write (banco + broker no mesmo fluxo) é VETADO (ver §37).
  • DLQ (dead letter queue) configurada para todo consumidor.
  • Retry infinito proibido. Política de retry explícita com limite e backoff.

MUST — backpressure

  • Consumidores com limites explícitos de concorrência e prefetch.
  • Throttling em produtores quando broker sinaliza pressão.

Convenção de nome: <dominio>.<entidade>.<evento> no passado. Exemplos: catalog.product.created, billing.invoice.paid.

Brokers

Cenário Stack
Eventos leves, baixa latência, pub/sub simples NATS
Alto throughput, retenção, replay, streaming Kafka
Workflows com routing complexo (caso a caso) RabbitMQ

NATS e Kafka são padrão. RabbitMQ exige justificativa pelo custo operacional.


10. Banco de Dados

Caso Stack
Relacional PostgreSQL
Cache Redis
Busca textual OpenSearch
Analytics / eventos ClickHouse

MUST

  • Migrations versionadas, reversíveis (com down), automatizadas no deploy.
  • Schema próprio por serviço.
  • Sem joins cross-service no banco.
  • Timestamps em UTC, sempre. Conversão de timezone apenas na borda (UI/API response).
  • IDs: UUIDv7 ou ULID por padrão. IDs sequenciais apenas com justificativa (ex: ordenação natural exigida pelo domínio).
  • Toda query com input externo é parametrizada. Concatenação de string em SQL é VETADA (§37).

SHOULD — alta escala

  • Separação leitura/escrita (réplicas) quando volume justificar.
  • Revisão periódica de índices.
  • Análise de query plan em endpoints críticos.
  • Particionamento para tabelas com crescimento previsível alto.

Ferramentas sugeridas: golang-migrate, node-pg-migrate, sqlx-cli, flyway.


11. Cache

MUST

  • TTL sempre explícito. Sem TTL infinito sem ADR.
  • Mitigação de cache stampede (single-flight, lock, jitter).
  • Fallback seguro em cache miss — degradação graciosa, nunca falha total.
  • Invalidação documentada por chave.
  • Resposta autenticada sempre tem a chave de cache segmentada por usuário e tenant (§37).

MUST NOT

  • Cache como source of truth.
  • Cache de dados pessoais sensíveis sem criptografia.

12. APIs

MUST

  • OpenAPI 3.1 em /docs/openapi.yaml — fonte da verdade.
  • Versionamento na URL: /v1, /v2.
  • Validação de payload na borda.
  • Erro padrão (compatível com RFC 7807):
{
  "error": {
    "code": "PRODUCT_NOT_FOUND",
    "message": "Product not found",
    "trace_id": "01HXYZ...",
    "details": []
  }
}
  • Operações de escrita aceitam Idempotency-Key e o implementam de fato (aceitar o header e ignorar é VETADO — §37).
  • Quebra de contrato exige nova versão + janela de deprecação ≥ 90 dias com headers Deprecation e Sunset.
  • Timestamps em ISO-8601 com timezone explícito (preferencialmente Z).

MUST — paginação

  • Cursor pagination é o padrão.
  • Offset apenas em listas pequenas (< 10k itens) e estáticas.
  • Resposta inclui next_cursor e has_more.

MUST — rate limiting

  • Rate limiting distribuído (Redis, gateway, ou serviço dedicado).
  • Chave por usuário, API key e tenant.
  • Resposta 429 com header Retry-After.

SHOULD

  • Contratos consumer-driven (Pact) entre serviços.
  • gRPC para alta performance interna; HTTP/JSON para externa.

13. Segurança

MUST — pipeline (fail on high/critical)

  • Dependabot ou Renovate
  • SAST (Semgrep / CodeQL)
  • SCA (dependências + licenças)
  • Container scan (Trivy / Grype)
  • Secret scan (Gitleaks)
  • Commit signing (GPG / SSH / Sigstore)
  • SBOM no build (CycloneDX ou SPDX)

MUST — runtime

  • Containers não-root, read-only filesystem.
  • Distroless ou chainguard quando viável.
  • Multi-stage build.
  • Healthcheck na imagem.

MUST — segredos

  • Nunca em código, nunca em env file commitado.
  • Storage: Vault, AWS/GCP Secret Manager, sealed-secrets.
  • Rotação documentada.

Licenças permitidas: MIT, Apache 2.0, BSD, MPL 2.0, ISC. Bloqueadas sem ADR: GPL/AGPL, SSPL, proprietárias.

13.4 Segredos no Cliente / Frontend / NextJS

VETADO — sem exceção, sem ADR

  • Qualquer segredo no bundle que vai pro browser. API key privada, secret de JWT, senha de banco, service-role key (Supabase/Firebase admin), token de provedor de pagamento, chave de terceiro — nada disso entra em código que o cliente baixa. O navegador não guarda segredo. Ponto.
  • Prefixar segredo com NEXT_PUBLIC_ (ou equivalente VITE_, REACT_APP_, PUBLIC_). Esse prefixo expõe a variável publicamente por definição — usar só para valor que pode estar num outdoor.
  • Chamar API de terceiro com chave secreta direto do browser. Toda chamada que usa segredo passa por um BFF / route handler / server action server-side (§38).
  • Guardar token de sessão em localStorage/sessionStorage. Sessão vai em cookie HttpOnly + Secure + SameSite (§38, §22.3 hardening).
  • Confiar em validação de auth/role feita no client (if (user.isAdmin) no React) como controle de acesso. Isso é UX, não segurança — a decisão é sempre server-side (§15, §37).

"Coloca a senha no NextJS pra funcionar" não é uma solução, é um vazamento agendado. Se o cliente pode ver, o atacante já viu.


14. Autenticação e Autorização

  • OAuth2 / OIDC.
  • JWT assinado (RS256 ou EdDSA; nunca HS256 em fluxo público).
  • Validação completa do JWT em toda request: assinatura, exp, nbf, aud, iss e alg contra allowlist. Decodar o payload e confiar é VETADO (§37).
  • Refresh token rotativo com detecção de reuso.
  • RBAC com permissões granulares; ABAC quando necessário.
  • Hash de senha: bcrypt cost ≥ 12 ou argon2id. MD5/SHA1/sem-salt/plaintext são VETADOS (§37).
  • Tokens, ids de sessão e códigos de reset gerados por CSPRNG (crypto/rand, crypto.randomBytes) — nunca Math.random() (§37).

15. Multi-tenancy

MUST — quando aplicável (SaaS, plataformas)

  • Isolamento de tenant explícito em todas as camadas.
  • tenant_id propagado em contexto, logs e traces.
  • Autorização validada server-side em toda operação. Nunca confiar em tenant_id (ou role, ou user_id) enviado pelo cliente sem verificação contra o token. Derivar sempre do token, server-side.
  • Queries com tenant_id no WHERE, sempre. Considerar Row Level Security no Postgres.

SHOULD

  • Testes de cross-tenant leak em CI.
  • Métricas e logs particionáveis por tenant.

16. Observabilidade

Stack obrigatória: Grafana, Alloy, Loki, Tempo, Prometheus, OpenTelemetry.

16.1 Logs

  • JSON estruturado.
  • trace_id, correlation_id, tenant_id (se aplicável) em toda request.
  • Níveis: DEBUG, INFO, WARN, ERROR.
  • Proibido logar: senhas, tokens, JWT, PII (CPF, email, telefone), dados financeiros, payloads de pagamento. Mascaramento obrigatório.
  • VETADO logar request/response inteiros, headers ou body cru "pra debugar" (§37). Logue campos específicos, mascarados.

16.2 Métricas

  • RED por endpoint/handler: Rate, Errors, Duration (histograma p50/p95/p99).
  • USE para infra: Utilization, Saturation, Errors.

16.3 Tracing

  • Toda chamada externa, fila, banco e fluxo crítico instrumentados.
  • Propagação W3C Trace Context.

16.4 SLOs

  • Cada serviço define SLI/SLO em /docs/slo.md.
  • Error budget consumido → freeze de features até recuperação.

16.5 Business Observability

SHOULD

  • Métricas de negócio expostas (pedidos/min, conversão, churn, etc).
  • Dashboards de negócio separados dos técnicos.
  • KPIs principais instrumentados desde o dia 1.

16.6 Auditoria

MUST

  • Operações sensíveis (mudança de permissão, transações financeiras, alteração de configuração, ações administrativas) registradas em trilha de auditoria imutável.
  • Campos mínimos: actor_id, tenant_id, action, resource, timestamp, ip, user_agent, result.
  • Retenção mínima conforme regulação aplicável.
  • Storage append-only (não usar a mesma tabela de domínio).

17. Healthchecks

Endpoints obrigatórios:

  • /health — liveness (processo está vivo)
  • /ready — readiness (dependências OK, pronto pra tráfego)
  • /metrics — Prometheus

18. Resiliência

MUST em chamadas externas:

  • Timeout explícito (nunca infinito).
  • Retry com backoff exponencial + jitter, idempotência garantida.
  • Circuit breaker.
  • Rate limiting na borda.
  • Bulkhead em integrações críticas.

19. Jobs e Workers

MUST

  • Jobs idempotentes (pode executar 2x sem corromper).
  • Timeout obrigatório por job.
  • Política de retry explícita com limite.
  • Progress/state persistido para jobs longos ou críticos.
  • DLQ para jobs que falharem após max retries.

SHOULD

  • Jobs longos divisíveis em chunks com checkpoint.
  • Cancelamento gracioso (respeitar context/signal).

20. Configuração

  • Via environment variables (12-factor).
  • Validação tipada no startup — falha rápido.
  • Sem hardcode.
  • Defaults seguros (fail closed).

21. Infraestrutura e Deploy

MUST

  • Kubernetes + Helm.
  • IaC: Terraform ou OpenTofu.
  • CI/CD: GitHub Actions.
  • Ambientes isolados: dev, staging, production.
  • Promoção entre ambientes por artefato imutável (mesma imagem).

21.1 Estratégia de Deploy

Estratégia Quando usar
Rolling update Default para serviços comuns
Blue/green Serviços críticos, rollback instantâneo necessário
Canary Mudanças de alto impacto, rollouts graduais

MUST

  • Rollback automatizado quando healthcheck falhar pós-deploy.
  • Healthcheck gating: tráfego só vai pra pod ready.
  • Janela de validação antes de declarar deploy bem-sucedido.

21.2 Preview Environments

SHOULD

  • PRs em serviços principais geram ambiente efêmero automaticamente.
  • Destruído ao merge ou após X dias de inatividade.

22. Testes

Obrigatório

  • Testes em dois eixos: por código (unit/integration, dentro de cada serviço) e por sistema vivo (smoke/security/pentest/authz/hardening/chaos/simulated, no repo <project>_ops).
  • Caminhos críticos (auth, pagamento, autorização, billing, eventos de domínio, multi-tenancy) têm testes explícitos cobrindo sucesso, falha e edge cases — independentemente da cobertura agregada.

Cobertura mínima (por código)

Camada Mínimo
domain 80%
application 70%
infrastructure 40%
Global 60%

Editar o threshold ou pular teste pra "passar o CI" é VETADO (§37). O número é contrato.

Mutation testing (SHOULD) no domínio em serviços críticos: Stryker (JS/TS), go-mutesting, cargo-mutants.


22.1 Test Kit do <project>_ops

Toda a malha de testes "do sistema vivo" mora num repo dedicado (<project>_ops), invocada por um CLI único.

Estrutura padrão

<project>_ops/
├── bin/
│   └── <project>-test          # CLI: run modes, agrega saída
├── tests/
│   ├── lib.sh                  # helpers compartilhados (cores, assertions, http_call)
│   ├── README.md               # tabela de modos × scripts × duração
│   ├── smoke/                  # health, rotas-chave, shape de respostas
│   ├── integration/            # login real + CRUD ponta-a-ponta
│   ├── security/               # auth bypass, headers, rate-limit
│   ├── pentest/                # OWASP + extensão
│   ├── authz/                  # RBAC + multi-tenancy isolation
│   ├── hardening/              # TLS, cookies, CORS, exposed paths
│   ├── chaos/                  # fuzz, property-based, kill, db-disconnect
│   ├── simulated/              # matriz exaustiva: rotas × personas × injections
│   ├── seeds/                  # SQL de setup (personas de teste, superadmin)
│   ├── unit/                   # delega `go test` / `npm test` por serviço
│   └── workspace-code.sh       # smell-scan no monorepo (arquivos > N linhas, etc.)
├── Makefile
└── README.md

CLI padrão

<project> test                  # default: smoke
<project> test smoke
<project> test integration
<project> test security
<project> test pentest
<project> test authz
<project> test hardening
<project> test chaos
<project> test simulated
<project> test unit
<project> test all              # tudo exceto chaos+unit
<project> test full             # all + chaos + unit
<project> test seed-superadmin  # setup inicial (uma vez)

MUST

  • Cada script é executável standalone: bash tests/smoke/auth-endpoints.sh deve rodar e sair 0/1.
  • Cada script declara TEST_NAME e usa helpers de lib.sh (test_pass, test_fail, test_skip, test_section, test_summary, http_call, assert_http_in).
  • Banner ENORME em vermelho quando há falha — feedback visual impossível de ignorar em CI.
  • Skip sem erro quando dependência opcional falta (ex.: openssl ausente em hardening/tls).

22.2 Saída estruturada (machine-readable)

Toda execução escreve em /<project>/logs/test-<YYYY-MM-DD>-<HHMMSS-pid>/:

Arquivo Conteúdo
summary.txt PASS/FAIL por script, legível
summary.json fonte única pra dashboards/CI — schema fixo abaixo
run-totals.txt 7 linhas: mode, started, finished, duration, scripts, pass, fail, exit
<mode>-<name>.log output completo de cada script
cookies.txt sessão dos personas (só em integration)
coverage-summary.{txt,json} cobertura por serviço (só em unit)

Schema summary.json

{
  "started_at": "2026-05-11T11:35:50Z",
  "finished_at": "2026-05-11T11:35:57Z",
  "duration_seconds": 7,
  "mode": "smoke",
  "log_dir": "/<project>/logs/test-2026-05-11-083550-448694",
  "scripts": [
    {"category": "smoke", "name": "auth-endpoints", "status": "pass"},
    {"category": "smoke", "name": "services-health", "status": "fail"}
  ],
  "totals": {"pass": 23, "fail": 1, "scripts": 24, "exit_code": 1}
}

MUST

  • Exit code 0 se tudo passou; 1 se qualquer caso falhou.
  • summary.json é contrato — não quebre os campos mode, totals, scripts[].
  • Logs zipados e enviados pra storage de longo prazo após cada CI run (90 dias mínimo).

22.3 Categorias de teste (por modo)

smoke — saúde do sistema, < 2min

Cobre: health/metrics de cada serviço, rotas-chave do dispatcher, frontends, observability stack, endpoints por domínio (auth, catalog, billing, etc.), DB connectivity, microservices-status, shape de health/metrics, response-time p95, CORS preflight, OpenAPI availability, log scan pra PII vazada.

Falha = bloqueio de deploy. Roda antes e depois de cada update em todo ambiente.

MUST — anti "verde mentiroso" (smoke que passa com bug dentro)

Um smoke que só confere status 200 é teatro: a rota responde, o conteúdo está quebrado, e o deploy passa. Para impedir isso:

  • Assertar conteúdo, não só status. Toda rota-chave valida o shape do body (campos esperados via jq -e), não apenas o código HTTP. 200 com body vazio, {}, null, [] onde deveria haver dado, ou HTML de erro com status 200 = FALHA.
  • Assertion negativa obrigatória. Cada rota crítica também testa que o que não deveria estar lá não está: sem stack trace, sem error/exception no body de sucesso, sem "undefined"/"null"/"NaN" serializado, sem placeholder de template não renderizado ({{, ${, %s).
  • Self-test do próprio smoke (meta-teste). O suite tem um caso que força uma falha conhecida (ex.: bater numa rota fake /_smoke_canary_should_404 esperando 404, e numa asserção que deve falhar de propósito num modo --self-check) pra provar que o runner consegue reportar FAIL. Se o "self-check" passa quando deveria falhar, o smoke está cego → CI quebra. Nenhum teste pode ser estruturalmente incapaz de falhar.
  • Cobertura de rota verificada. O smoke compara as rotas que testou contra o inventário do OpenAPI/dispatcher. Rota em produção sem caso de smoke = FALHA, não silêncio. (Liga com §35 e com simulated.)
  • Sem || true, sem swallow. Proibido curl ... || true, set +e sem set -e de volta, ou condição que transforma erro em pass. Falha de rede/timeout numa dependência obrigatória é FAIL, não skip (skip só pra dependência opcional declarada).
  • Latência e dado fresco. Healthcheck que devolve 200 cacheado/estático não conta — /ready valida dependência de verdade (ping no DB, no broker), e o smoke afere response-time p95 contra o SLO (§30). Resposta lenta demais = FALHA.
  • Fail loud. Banner vermelho ENORME (§22.1) e o summary.json com totals.fail > 0 travando o deploy. Verde só quando todas as asserções de conteúdo passaram.

Smoke que nunca falha não é smoke saudável — é smoke quebrado. Se você não viu o teste falhar de propósito, você não sabe se ele funciona.

integration — fluxos end-to-end com credenciais reais, < 3min

Cobre: login do superadmin com cookie real, CRUD course/user/subscription via API admin, upload de imagem, reset de senha completo. Usa seed tests/seeds/test-superadmin.sql pra garantir user existente.

Requer pré-seed: rodar <project> test seed-superadmin na primeira vez no ambiente.

security — controles de segurança "óbvios", < 1min

Cobre: auth bypass tentando rotas admin sem cookie, headers de segurança (CSP, X-Content-Type, HSTS), rate limit no login (50 paralelas → expect 429), formato de password hash (bcrypt cost ≥ 12 / argon2id), npm audit --audit-level=high, JWT algorithm validation (RS256 only).

pentest — OWASP Top 10 + extensão, < 3min

Scripts cobrem (cada um isolado):

  • sql-injection.sh — payloads SQLi clássicos em query/body. Esperado: 400/422 ou 401/403/404. NUNCA 500 e nunca 200 com data revelando "OR 1=1".
  • xss.sh<script>, <img onerror>, javascript: em campos refletidos. Resposta não pode incluir payload sem escape.
  • idor.sh / user-bola.sh — IDs de outro tenant/user nos paths.
  • ssrf.sh — URLs apontando pra 127.0.0.1, 169.254.169.254, file://, redirect chains.
  • jwt-tampering.sh / jwt-claim-tampering.sh / jwt-algorithm.sh — alg=none, alg=HS256-com-RS256-pubkey, exp futuro, sub trocado.
  • path-traversal.sh../, ..%2f, null bytes.
  • mass-assignment.sh — POST com campos extras (is_admin, tenant_id, created_at) que deveriam ser ignorados.
  • open-redirect.sh?next=https://evil.com.
  • host-header.sh — Host header arbitrário pra envenenar links em emails.
  • csrf.sh — POST sem origin/referer válido.
  • http-method-tampering.sh — TRACE, OPTIONS, métodos não suportados.
  • request-smuggling.shTransfer-Encoding: chunked + Content-Length conflitantes.
  • cache-poisoning.sh — headers exóticos que envenenam CDN.
  • cookie-bomb.sh — flood de cookies grandes → expect 4xx limpo, não 500.
  • session-fixation.sh — session ID atribuído pré-login persiste pós-login.
  • timing-attack.sh — diff de latência entre user existente vs inexistente no login (alvo: < 30% variance).
  • prototype-pollution.sh__proto__, constructor.prototype no body JSON.
  • redos.sh — strings catastróficas pra regex (aaaaaa...aaa!).
  • billion-laughs.sh — JSON/XML bomb (nested arrays profundos).
  • clickjacking.shX-Frame-Options / CSP frame-ancestors.
  • refresh-token-reuse.sh — usar mesmo refresh duas vezes → 2ª deve revogar família.
  • parameter-pollution.sh?id=1&id=2.
  • excessive-data-exposure.sh — endpoint público vaza email/cpf/telefone.
  • header-spoof.shX-Forwarded-For, X-Real-IP, X-Original-User injetados.
  • oversized-payload.sh — body de 10MB+ → 413, não 500.

Validação de tipo e sanitização de entrada — campo só aceita o que deveria, e o que não deveria vira 422/400 limpo, nunca 500 e nunca persistido cru:

  • type-confusion.sh — manda o tipo errado em cada campo: string/varchar onde o schema espera int/uuid/bool/enum/date; número onde espera string; array onde espera objeto; objeto aninhado onde espera escalar. Esperado: 422 com erro de validação. Aceitar "123" como int por coerção silenciosa, ou estourar 500, é FALHA.
  • boundary-values.sh — limites numéricos: negativo onde só positivo, 0, MAX_INT+1, -1, float onde espera int, NaN, Infinity, notação científica (1e999).
  • charset-fuzz.sh — caracteres estrangeiros e estranhos em todo campo de texto: unicode astral (emoji 𝕏, 𝓪), CJK (中文), árabe/hebraico (RTL), combinação de diacríticos, zero-width (\u200b), homoglyphs, \u0000 null byte, control chars (\x01-\x1f), BOM. Esperado: aceitar normalizado (NFC) ou rejeitar com 422 — nunca quebrar encoding, corromper o dado, ou refletir sem escape.
  • format-validation.sh — campos com formato declarado (email, cpf, telefone, url, uuid, cep) recebem lixo que casa o "shape" mas é inválido (a@b, cpf com dígito verificador errado, uuid de 35 chars). Validação semântica, não só regex frouxa.
  • length-overflow.sh — string acima do maxLength do schema, campo obrigatório vazio/ausente, whitespace-only. Esperado: 422, e o limite vem do schema, não de um varchar(255) implícito que estoura no banco.
  • injection-in-every-field.sh — roda o conjunto SQLi + XSS + path-traversal + command-injection + template-injection (${7*7}, {{7*7}}) contra cada parâmetro de cada rota mutável, não só os "óbvios". Tudo que entra é tratado como hostil até prova de sanitização.

Regra do pentest de entrada: todo campo é um campo de ataque. Se o schema diz int, prove que int é tudo que entra. Se diz texto, prove que sai escapado e normalizado. Coerção silenciosa e 500 são as duas faces do mesmo bug.

authz — autorização e isolamento, < 1min

  • cross-tenant-idor.sh — tenant A não vê dados de tenant B (cobre §15: tenant_id sempre no WHERE).
  • rbac-negative.sh — viewer não consegue write, editor não consegue admin.
  • privilege-escalation.sh — tenant_admin não consegue virar platform superadmin.
  • permission-boundary.sh — combinações de roles + recursos → matriz de allow/deny.
  • tenant-isolation.sh — cookie/JWT de tenant A injetado em rota de tenant B → 403.

hardening — endurecimento da superfície de ataque, < 1min

  • tls-config.sh — TLS 1.2/1.3 ok, 1.0/SSLv3 rejeitados, cert válido, HSTS no header, nome bate.
  • headers-full.sh — CSP, COOP, CORP, Referrer-Policy, Permissions-Policy, X-Content-Type-Options.
  • cookies.sh / cookie-attributes.sh — HttpOnly + Secure + SameSite=Lax|Strict em todos os cookies de sessão.
  • cors.sh — origens permitidas explícitas, sem * em rotas autenticadas.
  • exposed-paths.sh.git/HEAD, .env, /debug, /actuator, phpinfo.php retornam 404 (não 200).
  • default-creds.sh — login com admin/admin, root/root, test/test falha sempre.

chaos — comportamento sob stress / falha, < 5min

  • input-fuzz.sh — strings longas (10MB), null bytes, unicode astral, JSON malformado.
  • property-based.sh — idempotência (POST com Idempotency-Key igual 2x → mesmo resultado), p95 < SLO, JWKS sempre formado corretamente, enums com valores fora do range.
  • service-kill.shsystemctl stop <service>, mede recuperação (gated por EDUCE_CHAOS_ALLOW=1 — perigoso).
  • db-disconnect.sh — derruba conexão DB momentaneamente, valida que pool recupera.
  • concurrent-load.sh — 50 GETs concorrentes em rotas públicas, mede taxa de sucesso e p50/p95/p99, hang > 10s = falha.

simulated — matriz exaustiva, ~5min

Engine Python (tests/simulated/run.py) que cruza rotas × personas × injections:

  • Personas (mínimo 3) declaradas em personas.json:

    • superadmin (platform role)
    • tenant_admin (escopo de 1 tenant de teste)
    • normal_user (sem roles) Cada persona declara expected_access por categoria de rota (public, auth, authenticated, admin, internal, import).
  • Injections (mínimo 10) em injections.json:

    • SQLi (' OR 1=1 --, '; DROP TABLE users CASCADE; --)
    • XSS (<script>alert(1)</script>)
    • Path traversal (../../etc/passwd, ..%2f..%2fetc%2fpasswd)
    • Null byte, unicode RTL override, long string
    • Mass-assignment keys (is_admin, tenant_id, created_at, password_hash)
  • Rota catalog — JSON gerado a partir do OpenAPI ou inventário de rotas do dispatcher (no Educe: educe_api_go/docs/legacy_inventory.json).

MUST — cobertura total de rotas (garantia de acessibilidade)

  • O engine enumera 100% das rotas do catalog e prova, por persona, que cada uma responde como esperado (acessível pra quem deve, 403/401 pra quem não deve). Rota no catalog sem resultado no raw.jsonl = FALHA — não existe rota "não testada".
  • Reconciliação obrigatória: rota servida em runtime mas ausente do catalog (rota fantasma) e rota no catalog que não responde (rota morta / 404 inesperado) ambas quebram o run. O número de rotas testadas tem que bater com o inventário.
  • Toda rota é exercida com persona autorizada e não autorizada — acessibilidade e isolamento no mesmo passe.
  • Saída lista explicitamente, no report.md, a matriz rota × persona × esperado × obtido, com as linhas REVIEW destacadas pra olho humano.

Outputs:

  • raw.jsonl — uma linha por request, toda evidência.
  • report.md — relatório humano com seções AUTO (passou claro) e REVIEW (status inesperado, precisa olho humano).
  • summary.json — totais por categoria.

Setup: bash tests/simulated/setup.sh cria as 3 personas no DB com hash bcrypt.

Vars de ambiente úteis (EDUCE_TEST_* no Educe — generalizar com <PROJECT>_TEST_*):

  • <P>_TEST_API_BASE (default http://127.0.0.1:13000)
  • <P>_TEST_LOG_DIR (default /<project>/logs)
  • <P>_SIM_TENANT_ID
  • <P>_SIM_MAX_ROUTES (debug: limita)
  • <P>_SIM_SKIP_MUTATIONS=1 (só GET)

unit — testes por código, 5-15min — agressivos, não decorativos

CLI delega para o test runner nativo de cada serviço:

  • Go: go test -cover -race ./...
  • Node/Nest: npm test ou vitest run
  • Next.js: vitest run ou jest

Gera coverage-summary.json agregando cobertura por serviço.

MUST — teste unitário que realmente caça bug (não só cobre linha)

  • -race sempre (Go), detector de concorrência ligado. Teste flaky por corrida = bug, não "re-roda".
  • Caminho de erro é obrigatório, não opcional. Para cada função, testar o sucesso e as falhas: input inválido, dependência que retorna erro, timeout, nil/null, slice/array vazio, divisão por zero, overflow. Cobertura de 80% só de happy-path é cobertura mentirosa.
  • Tabela de casos hostis por validador/parser: tipo errado, fora do range, string gigante, vazia, unicode/RTL/null byte, número como string e vice-versa — espelhando o type-confusion/charset-fuzz do pentest, só que na fronteira da função. Bug de sanitização tem que morrer no unit, antes do pentest achar.
  • Property-based testing (SHOULD → MUST em domínio crítico): fast-check (TS), gopter/rapid (Go), proptest (Rust). Idempotência, round-trip (encode→decode), invariantes de agregado. Encontra o edge case que você não imaginou.
  • Mutation testing no domínio crítico (§22, Stryker/go-mutesting/cargo-mutants): se o teste não pega a mutação, o teste é decorativo. Mutation score mínimo definido por serviço crítico, não só line coverage.
  • Boundary obrigatório: 0, -1, 1, MAX, MAX+1, vazio, um, muitos. O bug mora na borda.
  • Proibido teste que não pode falhar: assert ausente, expect(true), mock que devolve o próprio input esperado. Revisão de PR rejeita teste tautológico.

Cobertura mede o que o teste executa, não o que ele verifica. Mutation testing mede o que ele verifica. Por isso line coverage é piso, não meta.


22.4 Padrão de script (tests/<mode>/<name>.sh)

Skeleton obrigatório:

#!/usr/bin/env bash
# <Categoria> · <Nome curto>
# Descrição clara do que cobre e o esperado.
# Esperado: status X em caso Y. Falha = significado Z.

set -uo pipefail
_DIR="$(cd -P "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# shellcheck source=../lib.sh
source "$_DIR/lib.sh"

test_section "<Categoria> · <Nome>"

API="$(api_base)"

# Caso 1
assert_http_in "<descrição do caso>" "200|401" GET "$API/v1/<rota>"

# Caso 2 — body shape
http_call GET "$API/v1/<rota>"
if [[ "$HTTP_CODE" == "200" ]]; then
  if echo "$HTTP_BODY" | jq -e '.data | length > 0' >/dev/null 2>&1; then
    test_pass "<rota> retorna dados"
  else
    test_fail "<rota> sem 'data'" "$HTTP_BODY"
  fi
fi

test_summary "<categoria>/<nome>"
exit $TEST_EXIT_CODE

MUST

  • Banner do test_section na primeira linha do output.
  • Cada caso assertado vira uma linha ou ou ○ skip.
  • test_summary no fim agrega contadores pra o runner.
  • Falhas incluem HTTP_BODY truncado nos primeiros 2000 chars (sem PII).

22.5 Seeds e personas de teste

MUST

  • Personas declaradas em tests/seeds/test-*.sql ou tests/<mode>/*.json — versionadas, reproduzíveis.
  • Senhas test-only explicitamente flagadas (ex.: prefixo SimTest!) e rejeitadas em produção por validador de senha fraca.
  • Setup idempotente: INSERT ... ON CONFLICT DO UPDATE — re-rodar não duplica.
  • Cleanup automático no fim de cada run? Não — deixa lixo pra inspeção. Limpe via comando explícito (<project> test clean-seeds).

Personas mínimas pra cobrir RBAC + multi-tenancy:

  1. superadmin — platform role, vê tudo.
  2. tenant_admin_A — escopo do tenant A.
  3. tenant_admin_B — escopo do tenant B (pra testar isolamento).
  4. normal_user — sem role, só dados próprios.
  5. (Opcional) viewer, editor, support — combinações de roles dentro de A.

22.6 Integração com CI

MUST

  • PR check: <project> test smoke + security + authz + hardening (rápido — ~3min total).
  • Pré-deploy: <project> test all (full minus chaos+unit — ~6min).
  • Nightly: <project> test full (inclui chaos + unit).
  • Bloqueio de merge: fail no summary.json (.totals.fail > 0) trava merge.

Dashboards

  • summary.json é parseado por job de métricas pra empurrar tests_pass_total, tests_fail_total, tests_duration_seconds_bucket pra Prometheus.
  • Falha em smoke pós-deploy dispara rollback automático.

22.7 Pentest leve via ferramentas externas (complementar)

SHOULD — em CI noturno, não a cada PR:

  • OWASP ZAP baseline (zap-baseline.py -t https://api.example.com) — passive scan.
  • Nuclei (nuclei -u https://api.example.com -t cves,exposures,misconfiguration).
  • trivy fs ou grype sobre o repo + imagens Docker pra CVE em deps + base images.
  • Semgrep ruleset p/owasp-top-ten pra SAST.

Resultados em PR comment ou dashboard, não bloqueiam merge por default (alto ruído) — mas qualquer Critical sem ADR de aceite trava.


22.8 Diretrizes de Pentest (princípios, não só scripts)

Os scripts da §22.3 são a implementação; estes são os princípios que regem como se faz pentest interno e o que conta como passar.

Postura

  • Assume-breach / hostil por padrão. Todo input vindo de fora (body, query, header, cookie, path, arquivo, webhook) é tratado como hostil até prova de validação. Não existe "campo interno confiável" exposto numa rota.
  • Cobrir a rota toda, não a amostra. Pentest roda contra o inventário completo de rotas (mesmo catalog do simulated). Rota nova sem caso de pentest correspondente bloqueia (liga com §35).
  • Caixa-cinza. O time tem o OpenAPI, o schema e as roles — testa sabendo o que deveria acontecer, não no escuro. Pentest sem mapa vira teatro de "tentei o ' OR 1=1 e deu 403, tá seguro".

Critério de resultado — o que é PASS / FAIL

  • Nunca 500 por input malicioso. Erro do servidor (5xx) diante de payload hostil é FALHA — significa que o input chegou fundo demais sem validação. O esperado é 400/422 (input inválido) ou 401/403/404 (sem acesso).
  • Nunca eco sem escape. XSS/template injection refletido no body/header sem encode = FALHA, mesmo com status 200.
  • Nunca coerção silenciosa. varchar aceito como int, string vazia virando 0, "true" virando bool = FALHA (liga com type-confusion.sh). O tipo do schema é contrato.
  • Nunca vazamento entre tenants/usuários. Qualquer 200 com dado de outro escopo = FALHA crítica, para o deploy na hora (§15).
  • Nunca diferença observável que ajude o atacante. Mensagem de erro distinta pra "user existe" vs "senha errada", timing > 30% de variância, stack trace no response = FALHA.
  • Idempotência sob ataque. Replay, duplicação, race no mesmo recurso não corrompe estado.

Severidade e gate

  • Classificar todo achado: Critical / High / Medium / Low / Info.
  • Critical e High bloqueiam merge/deploy. Sem exceção silenciosa — ou conserta, ou ADR de aceite de risco com prazo de remediação e dono (e mesmo assim Critical de auth/tenant/injeção não aceita ADR — é piso da §37).
  • Medium/Low viram issue rastreável com prazo; acumular não é opção.

Higiene

  • Pentest roda só contra dev/staging (ou alvo autorizado). Scripts destrutivos (service-kill, db-disconnect) gated por env var explícita (§22.3 chaos). Nunca contra produção sem autorização formal e janela.
  • Evidência sempre. Todo achado tem request/response reproduzível no raw.jsonl — "achei uma falha" sem repro não conta.
  • Falso-positivo é bug do teste. Pentest que grita sem motivo treina o time a ignorar — calibra ou remove. Mas na dúvida, FAIL (vai pra REVIEW, olho humano decide), nunca silencia por padrão.

Escopo mínimo coberto (mapeia OWASP Top 10 + API Top 10): injeção (SQL/NoSQL/command/template), XSS, validação de tipo e sanitização (§22.3), authz/IDOR/BOLA, broken auth (JWT, sessão, refresh), SSRF, mass assignment, exposição excessiva de dados, misconfig (headers, CORS, paths expostos), rate limiting, e abuso de recurso (payload gigante, ReDoS, billion-laughs).

Pentest não "tenta hackear pra ver se acha algo". Ele prova, rota por rota, campo por campo, que o sistema rejeita o que deve rejeitar. Achado é evidência; ausência de achado só vale se a cobertura for total.


22.9 Fluxo de execução de Q.A. (plan-first, aprovação obrigatória)

A malha de Q.A. inclui passos potencialmente destrutivos (chaos service-kill/db-disconnect, pentest, mutações). Por isso nenhuma submissão de Q.A. roda às cegas: toda submissão de um formulário/pedido de Q.A. passa por planejamento, aprovação humana e execução controlada.

MUST — antes de executar qualquer coisa

  1. Planejar tudo primeiro. Ao receber a submissão, o agente não executa nada ainda. Levanta o escopo completo: quais modos vão rodar (smoke/integration/security/pentest/authz/hardening/chaos/simulated/unit), ambiente alvo, rotas e personas afetadas, ordem de execução, dependências entre passos, o que é destrutivo/gated, e os riscos.
  2. Gerar um MD de passo a passo detalhado em <project>_archive/qa/<YYYY-MM-DD-HH-MM-SS>-<contexto>.md (liga com §28 — é archive obrigatório). Cada passo declara: objetivo, comando exato, ambiente, resultado esperado, critério de pass/fail, e flag de destrutivo quando aplicável. O plano referencia o summary.json (§22.2) que será produzido.
  3. Pedir aprovação explícita do usuário. Sem aprovação registrada, nada roda. O agente apresenta o plano e aguarda o "ok". Aprovação parcial (subconjunto de passos) é válida e vira o escopo efetivo.

MUST — após aprovado

  1. Oferecer a modalidade de execução. O agente pergunta como rodar:
    • Faseado e assistido — executa por fase, pausa entre fases para revisão/confirmação, mostra resultado parcial e só segue com o "continuar". Default recomendado para staging sensível e para qualquer plano com passo destrutivo.
    • De uma vez (autônomo) — executa o plano inteiro sem parar.
  2. No modo "de uma vez":
    • Multiagentes para produção da execução — paralelizar categorias independentes (ex.: security, authz, hardening, pentest, simulated em workers separados), respeitando dependências declaradas no plano e os limites de concorrência (§9 backpressure).
    • Cron/watchdog de continuidade ininterrupta — um agendador supervisiona a execução e a retoma de checkpoint até concluir, sem exigir intervenção manual se um worker cair. A "conclusão" é condição de parada explícita: todos os passos aprovados terminaram, ou uma falha bloqueante escalou para o humano. Checkpoints são idempotentes (§19) e a retomada não reexecuta passo já concluído.

MUST — segurança do fluxo (herda do resto do §22)

  • Passo destrutivo (service-kill, db-disconnect, drop, mutação em massa) só roda se constava no plano aprovado e com o gate de ambiente ligado (ex.: <PROJECT>_CHAOS_ALLOW=1 — §22.3). Aprovação do plano não dispensa o gate.
  • Modo autônomo "de uma vez" roda por default só em dev/staging. Produção exige confirmação adicional explícita no momento da execução (alinha com §22.8 — alvo autorizado).
  • Sem retry infinito no watchdog: a continuidade tem limite de tentativas por passo, backoff, e escala para humano ao estourar (§9, §18). "Ininterrupto até finalizar" é retomar até concluir, não repetir pra sempre.

VETADO

  • Pular o plano ou a aprovação "pra ir mais rápido" — é macaquice na linha da §37 (atalho que troca segurança por velocidade). Q.A. sem plano aprovado registrado não roda.

O plano aprovado é o contrato da execução. Multiagente e cron aceleram o como, nunca dispensam o o quê foi autorizado.


23. Makefile Padrão

make dev              # ambiente local
make test             # unit + integration
make test-unit
make test-integration
make lint
make fmt
make build
make run
make docker
make migrate
make docs             # gera/valida openapi
make security-scan    # sast + sca local
make smoketest
make pentest-light
make ci               # tudo que o CI roda
make clean

24. Qualidade e Git

Commits: Conventional Commits. Versionamento: SemVer.

Branches — trunk-based como padrão

main      → produção (protegida, linear history)

feature/<ticket>-<slug>
fix/<ticket>-<slug>
hotfix/<ticket>-<slug>

GitFlow (develop) é opcional e exige justificativa — só vale a pena em times com release cadenciado pesado.

Pull Requests

  • Tamanho alvo: ≤ 400 linhas alteradas.
  • ≥ 1 reviewer (≥ 2 para domain, schema, segurança).
  • CODEOWNERS obrigatório.
  • CI verde obrigatório.
  • Squash merge na main.
  • Merge direto na main é VETADO. Force push em branch protegida idem (§37).

25. Ownership

MUST

  • Cada serviço tem owner explícito (squad ou pessoa).
  • CODEOWNERS configurado.
  • Documentação de oncall definida.
  • Contato de escalação documentado no README.

26. Runbooks e Incidentes

26.1 Runbooks

MUST

  • Serviços críticos têm runbook em /docs/runbook.md.
  • Conteúdo mínimo: como diagnosticar falhas comuns, dashboards relevantes, comandos úteis, como fazer rollback, contatos.
  • Incidentes recorrentes atualizam o runbook.

26.2 Incidentes

MUST

  • Postmortem blameless para todo incidente Sev1/Sev2.
  • RCA (root cause analysis) documentado.
  • Ações preventivas rastreáveis (issue/task) com prazo.
  • Repositório central de postmortems acessível ao time.

27. ADR — Architecture Decision Records

Toda decisão arquitetural relevante vira ADR.

/docs/adr/
  0001-use-postgresql.md
  0002-adopt-hexagonal-architecture.md

Formato MADR. Status: proposed, accepted, deprecated, superseded by NNNN.

Quando criar: escolha de banco/broker/linguagem, padrão arquitetural, mudança de contrato público, qualquer desvio deste documento (exceto itens VETADO, que não admitem exceção).


28. Archive de Conversas e Tarefas — INEGOCIÁVEL

Esta seção não tem modo "pula pra ir mais rápido". O archive é parte da entrega, não um extra. Tarefa sem archive = tarefa não feita (§35). Gerar os .md é tão obrigatório quanto compilar.

Princípio: todo trabalho que produz código, decisão ou mudança de estado gera registro em Markdown, TODA vez, sem exceção. Não existe "depois eu documento". O .md nasce junto com o trabalho e é commitado junto.

28.1 Chat Archive

MUST — gerar SEMPRE para conversas/sessões que produzem:

  • Decisão arquitetural ou de segurança
  • Mudança de contrato público
  • Escolha de tecnologia
  • Resolução de incidente
  • Qualquer geração de código não trivial (inclui código assistido por IA — §34)

SHOULD para tasks de implementação significativas. MAY para o resto (troca trivial, dúvida pontual).

<project>_archive/chat/
  <YYYY-MM-DD-HH-MM-SS>-<contexto>.md

Conteúdo mínimo (todos os campos preenchidos, nunca placeholder vazio):

  • Pergunta/objetivo original
  • Entendimento do problema
  • Resposta/decisão tomada
  • Alternativas consideradas
  • Riscos e trade-offs
  • Próximos passos

28.2 Task Archive

MUST — gerar SEMPRE para toda task de implementação significativa.

<project>_archive/task/
  <task-name>.md

Conteúdo: contexto, objetivo, checklist, decisões, blockers, progresso. Atualizar ao fim de cada sessão — não acumular pra depois.

28.3 Garantias de processo

MUST

  • O archive é verificável: PR sem o .md correspondente (quando a regra acima exige) não passa no review (item de checklist de §35).
  • Gerar o archive é passo do fluxo, não tarefa separada que pode ser cortada por falta de tempo. Falta de tempo não revoga a §28.
  • Assistente de IA que produz código nesta base gera o .md do archive na mesma entrega — pular isso é violação direta (§37, item 28).

Registro indiscriminado de toda interação produz ruído. Registro seletivo do que importa produz contexto histórico útil. Mas "seletivo" é sobre o quê registrar, nunca sobre se registrar quando a regra manda.


29. Templates

/templates
├── README.md
├── ADR.md
├── TASK.md
├── PR_TEMPLATE.md
├── ISSUE_TEMPLATE.md
├── RUNBOOK.md
├── INDEX_GLOBAL.md       # índice global da aplicação (§39)
├── INDEX_FUNCTIONS.md    # índice de microfunções (§39)
└── OPENAPI_TEMPLATE.yaml

README mínimo: o que é, como rodar, como testar, como deployar, dependências, observabilidade, oncall, runbook.


30. Performance — Metas Padrão

Métrica Alvo
API p95 < 300 ms
API p99 < 1 s
Startup < 10 s
Imagem Docker < 200 MB (Go/Rust), < 400 MB (Node)

Metas específicas sobrescrevem, registradas no /docs/slo.md.


31. Feature Flags

Obrigatório para features críticas, migrações e rollouts graduais. Capacidades: rollout por % de tráfego, segmentação por tenant/usuário, kill switch, expiração de flag. Sugestões: Unleash, OpenFeature, GrowthBook.


32. LGPD e Dados Pessoais

MUST

  • Classificação de dados: público, interno, confidencial, pessoal, pessoal sensível.
  • PII nunca em logs (ver §16.1).
  • Política de retenção documentada por tipo de dado.
  • Processo para exercício de direitos (acesso, correção, eliminação, portabilidade).
  • Criptografia em trânsito (TLS 1.2+) e em repouso para dados pessoais.
  • DPIA para tratamentos de alto risco.
  • PII nunca em query string / URL (acaba em log, histórico, referer) — §37.

33. FinOps — Gestão de Custos

SHOULD

  • Monitoramento de custo por serviço/squad/tenant.
  • Budgets configurados com alertas de threshold.
  • Revisão periódica de overprovisioning (CPU/memória/réplicas).
  • Tags de billing consistentes em IaC.
  • Custo por request rastreado em serviços de alto volume.

34. Uso de IA Assistida

MUST

  • Código gerado por IA passa pelo mesmo PR review humano que qualquer outro.
  • Autor humano é responsável: assina o commit, entende o código, mantém.
  • Saídas de IA não substituem ADR.
  • IA opera sob a §37 (anti-padrões vetados) integralmente. Gerar código que viola um item VETADO é defeito, não estilo — rejeita no review.
  • IA gera o archive (§28) junto com o código, na mesma entrega.

MUST NOT / VETADO

  • Colar trecho gerado sem ler.
  • Aceitar dependências sugeridas sem verificar nome (typosquatting é real — §37).
  • Submeter código que não passa em make ci.
  • Aceitar "solução rápida" da IA que burla um piso de segurança da §37.

SHOULD

  • Prompt e contexto relevantes registrados no chat archive quando a decisão for não trivial.
  • Verificar licença de snippets longos sugeridos.

34.1 Handoff de contexto em sessões longas

Sessões longas de agente degradam quando o contexto enche: o modelo "esquece" decisões e a compactação automática resume de forma lossy. Para não perder estado, o handoff é proativo e arquivado, não reativo.

MUST

  • Definir um limite de handoff (tokens) abaixo do teto da janela — cedo o suficiente pra sobrar espaço pra escrever o resumo. Sugestão: ~25% da janela (ex.: 250k numa janela de 1M).
  • Ao cruzar o limite, antes de qualquer compactação, gerar dois artefatos em <project>_archive/context/:
    • <YYYY-MM-DD-HH-MM-SS>-context.md — estado do projeto, decisões tomadas, arquivos tocados, onde parou.
    • <YYYY-MM-DD-HH-MM-SS>-checklist.mdfeito vs. em aberto.
  • Só então compactar/limpar o contexto. O handoff é archive obrigatório (§28) — armazenar sempre em <project>_archive.
  • Rede de segurança determinística: um backup do estado é capturado automaticamente antes de toda compactação (manual ou automática), independente de o agente ter lembrado de gerar os MDs acima.

SHOULD

  • O limite é configurável por ambiente/projeto (ex.: env var), não hardcoded.
  • O resumo de contexto preserva o que você escolhe (foco na tarefa corrente), não o que a compactação automática adivinha.

Compactação automática é rede, não plano. Em sessão longa, o handoff arquivado vem antes do teto — quem controla o que sobrevive é você, não o resumo lossy.


35. Definition of Done

Uma task está pronta quando, cumulativamente:

  • Testes passam (unit + integration), cobertura nos mínimos
  • Caminhos críticos com testes explícitos
  • Teste emulado por IA (simulated, §22.3) executado — 100% das rotas do inventário acessíveis pra quem deve e bloqueadas pra quem não deve; rota fantasma/morta = bloqueio
  • Pentest de entrada limpo: sem 500, sem coerção de tipo, sem eco não-escapado, sem vazamento cross-tenant (§22.3, §22.8)
  • Lint, fmt, security scan limpos
  • Nenhum item da §37 (anti-padrões vetados) presente no diff
  • Arquivos ≤ 300 linhas (ou quebrados em micro-funções) e toda função com doc-comment de contexto — o quê + onde é usada (§6)
  • Índice de funcionalidades atualizado no mesmo PR — global e microfunções (§39)
  • Observabilidade implementada (logs, métricas, traces, audit se aplicável)
  • OpenAPI atualizada (se for API)
  • Migration testada com rollback (se houver schema change)
  • Documentação atualizada (README, ADR, runbook se aplicável)
  • Smoke tests executados em staging (com asserção de conteúdo e self-check anti verde-mentiroso — §22.3)
  • CI verde, code review aprovado
  • Archive de chat/task gerado e commitado (§28) — gate rígido, não opcional
  • Feature flag configurada (se aplicável)
  • CODEOWNERS aplicável revisou

Os itens em negrito são bloqueantes absolutos: archive (§28), ausência de macaquice (§37), teste emulado por IA com rota 100% acessível (§22.3), e pentest de entrada limpo (§22.8). Faltando qualquer um, a task não está pronta — independente de todo o resto estar verde. Smoke verde não basta: tem que ser smoke que prova conteúdo, não só status.


36. Evolução

  • Refactors incrementais. Big-bang rewrite exige ADR e plano de rollback.
  • Toda migração de runtime/framework tem flag de coexistência.
  • DDD e hexagonal podem ser adotados progressivamente — comece pelas bordas e pelos domínios mais complexos.

37. Anti-Padrões Vetados — "Macaquices" que Terminam Rápido e Quebram em Produção

Atalhos que parecem entregar mais rápido e na real entregam vulnerabilidade, vazamento ou dívida. Todos VETADOS — não admitem ADR de exceção, são pisos. Aparecem em diff humano ou de IA → o PR para. Cada item traz o veto e o caminho certo.

Segredos e exposição

  1. Segredo no bundle do cliente. API key privada, secret de JWT, senha de banco, service-role key, token de pagamento no código que vai pro browser, ou em NEXT_PUBLIC_* / VITE_* / REACT_APP_*. → Segredo só server-side (BFF, route handler, secret manager). O navegador não guarda segredo (§13.4, §38).

  2. PII / token / senha em query string ou URL. Acaba em log de acesso, histórico do browser, header Referer. → Vai em body ou header apropriado, nunca na URL (§32, §16.1).

  3. .env com segredo real commitado, ou segredo hardcoded "temporário" no código. → Secret manager + .env.example sem valores. Gitleaks no pipeline (§13).

Injeção e execução

  1. SQL por concatenação de string com input externo. → Prepared statements / query parametrizada, sempre (§10).

  2. eval, Function(), exec, template string em child_process/os/exec/shell com qualquer parte vinda de input. → Nunca. Args separados, allowlist de comandos, bibliotecas que não invocam shell.

  3. Desabilitar verificação TLS (rejectUnauthorized: false, InsecureSkipVerify: true, verify=False) pra "funcionar logo". → Cert válido. mTLS interno. Se o cert está errado, conserta o cert.

Auth e autorização

  1. Auth/authz só no client (if (user.isAdmin) no React decide acesso). → Toda decisão de acesso é server-side (§15). Front é UX, não controle.

  2. Confiar em tenant_id / role / user_id vindos do body ou header do cliente sem validar contra o token. → Derivar sempre do token verificado, server-side (§15).

  3. JWT decodado sem validar assinatura, exp, aud, iss, e alg contra allowlist (aceitar alg: none ou HS256 com pubkey RS256). → Validação completa em toda request (§14).

  4. Hash de senha fraco — MD5, SHA1, sem salt, ou plaintext. → bcrypt cost ≥ 12 ou argon2id (§14).

  5. Math.random() (ou rand não-cripto) pra token, id de sessão, código de reset, nonce. → CSPRNG: crypto.randomBytes, crypto/rand (§14).

CORS, headers e superfície

  1. Access-Control-Allow-Origin: * em rota autenticada (pior ainda com allow-credentials). → Allowlist explícita de origens (§22.3 hardening).

  2. Endpoint de debug/admin/management sem auth, ou bind em 0.0.0.0 expondo porta interna. → Bind restrito, auth obrigatória, /debug e /actuator retornam 404 externamente (§22.3).

  3. Mass assignment — dar bind do body inteiro direto na entidade, deixando passar is_admin, tenant_id, created_at, password_hash. → Allowlist explícita de campos aceitos por endpoint.

Erros, tipos e qualidade

  1. Catch que engole errocatch {}, except: pass, _ = err, .catch(() => {}). → Tratar, logar com contexto e trace_id, propagar ou degradar de forma consciente.

  2. // @ts-ignore, any, interface{}, unwrap()/panic/! pra calar o compilador/linter. → Tipar de verdade, tratar o caso de erro. Inline-ignore de regra de segurança (nolint, eslint-disable security/*, # nosec) é VETADO sem ADR.

  3. Logar request/response inteiro, headers ou body cru "pra debugar". → Logar campos específicos, mascarados. Nunca PII/token/senha (§16.1).

Testes e cobertura

  1. Pular/comentar teste pra passar o CI.skip, t.Skip, xit, @Ignore, comentar o assert. → Conserta o código, não silencia o teste.

  2. Baixar o threshold de cobertura ou editar o gate pra o número fechar. → Cobertura é contrato (§22). Sobe escrevendo teste, não mexendo na régua.

  3. Mockar o próprio sistema sob teste retornando sucesso fixo, dando "verde" falso. → Testar comportamento real; mock só nas bordas externas.

Dados e migrations

  1. Migration sem down, ou destrutiva sem backup (DROP/ALTER que perde dado). → Reversível, testada com rollback antes do merge (§10).

  2. Cache de resposta autenticada sem chave por usuário/tenant — um user recebe dado do outro. → Chave de cache sempre segmentada por usuário e tenant (§11, §15).

Operação e entrega

  1. Container root, chmod 777, --privileged, filesystem RW "pra funcionar". → Não-root, read-only, least-privilege (§13).

  2. Dependência nova sem verificar nome (typosquatting), manutenção, licença, e sem pin de versão (latest, range frouxo). → Pin exato, checar nome/manutenção/licença, SCA no pipeline (§13, §34).

  3. Retry infinito / sem backoff/jitter — DoS no próprio sistema ou no terceiro. → Limite explícito + backoff exponencial + jitter (§9, §18).

  4. Idempotency-Key aceito mas ignorado (header existe, lógica não). → Implementar de fato a deduplicação (§12).

  5. Dual-write — gravar no banco e publicar no broker no mesmo fluxo, sem outbox. → Transactional Outbox (§9, Anexo B).

  6. Pular o archive/MD "pra ir mais rápido" (§28). → Archive é parte da entrega. Sempre gerado. Tarefa sem archive não está pronta (§35).

  7. Merge direto na main / force push em branch protegida / pular o PR e o review. → Trunk-based com PR, CI verde, CODEOWNERS (§24).

  8. Desligar rate limit, validação de payload, ou security scan "temporariamente". → "Temporário" vira permanente. Não se desliga piso de segurança (§12, §13).

  9. Criar serviço backend novo em Node, ou qualquer código novo em PHP. → Backend novo só em Go/Rust; Next.js segue valendo pro frontend. PHP é proibido e migra (§3). Node backend legado segue a regra dos 30% (§3.1).

Regra de bolso: se a justificativa começa com "só pra funcionar", "depois eu arrumo", ou "é mais rápido assim" e o resultado mexe em segredo, auth, dado, ou registro — provavelmente é uma macaquice desta lista. Para e faz certo.


38. Frontend / NextJS / SPA — Regras Específicas

MUST

  • Fronteira clara client/server. Tudo que toca segredo, banco, ou terceiro com credencial roda server-side (route handler, server action, BFF, server component que não serializa segredo pra props).
  • Sessão em cookie HttpOnly + Secure + SameSite=Lax|Strict. Token de auth nunca em localStorage/sessionStorage (XSS lê tudo lá).
  • Variáveis públicas (NEXT_PUBLIC_* etc.) contêm apenas dado não-sensível (URL de API pública, id de analytics público). Tratar esse prefixo como "vai pro outdoor".
  • Validação de input no client é UX; a validação que importa é a do servidor (§12). Autorização idem é server-side (§15).
  • CSP, X-Content-Type-Options, Referrer-Policy, Permissions-Policy e frame-ancestors configurados (§22.3 hardening).
  • Chamada a API de terceiro com chave secreta passa por proxy server-side. O browser nunca segura a chave.

VETADO

  • Service-role key / admin SDK (Supabase, Firebase, etc.) no código do client.
  • dangerouslySetInnerHTML com conteúdo não sanitizado (XSS).
  • Confiar em redirect/next param sem allowlist (open redirect — §22.3).

"Bota a senha no NextJS" não existe como solução. Existe como CVE. O front pede ao servidor; o servidor guarda o segredo.


39. Índice de Funcionalidades (fonte da verdade viva)

O código diz como está agora; o índice diz o que existe, onde mora e como se faz cada coisa — e é tratado como fonte da verdade do projeto, consultado antes de criar algo (pra não duplicar) e atualizado a cada mudança. Índice que apodrece é pior que não ter; por isso ele é gerável/validável e tem gate na DoD.

MUST — existência e localização

  • Todo projeto mantém o índice versionado em <project>_archive/index/ (ou /docs/index/), em dois níveis:
    • Índice global da aplicação (INDEX_GLOBAL.md) — o mapa macro: repos/serviços/bounded contexts e como se comunicam; a relação de pastas top-level de cada repo e a responsabilidade de cada uma; o que cada coisa faz e o ponto de entrada de como se faz (link pro fluxo/use-case/runbook). É o "mapa do território".
    • Índice de microfunções (INDEX_FUNCTIONS.md, por serviço) — o catálogo fino: cada função/módulo relevante → o quê, onde é usada/prevista, dependências e efeitos colaterais. Gerado a partir dos doc-comments obrigatórios (§6).

MUST — atualização e gate

  • Todo PR que adiciona, remove ou move funcionalidade atualiza o índice no mesmo PR. Índice desatualizado trava o merge (item da DoD, §35).
  • O índice é fonte da verdade: ao planejar uma feature, consulte-o primeiro pra não reimplementar o que já existe (anti-duplicação — liga com DRY semântico, §1).
  • Formato machine-friendly (markdown com tabelas, ou JSON/YAML que renderiza) pra permitir geração e validação automáticas — não prosa solta.

SHOULD — geração assistida

  • O índice de microfunções é gerado por script que varre os doc-comments padronizados (§6) e monta a tabela função → o quê → onde → arquivo:linha. CI compara o índice commitado com o gerado; divergência aponta índice ou comentário desatualizado.
  • Cada entrada linka pro arquivo/linha de origem.
  • Índice global revisado em cada mudança arquitetural (junto com o ADR, §27).

Conteúdo mínimo

INDEX_GLOBAL.md: lista de repos/serviços com 1 linha de propósito cada; por repo, árvore de pastas top-level com responsabilidade; mapa de comunicação (quem chama quem, quais eventos/contratos); links pra OpenAPI, SLO, runbook.

INDEX_FUNCTIONS.md: tabela por módulo — função | o quê | onde é usada | efeitos | arquivo:linha.

O índice responde "isso já existe? onde? como faço X?" sem precisar reler o código. Se a resposta exige caçar no código, o índice falhou — ou está desatualizado, e isso é bug.


Anexo A — Versões Correntes

Atualizado independentemente do documento principal. Revisão trimestral.

Stack Versão alvo (2026-05)
Node.js 24 LTS (frontend: Next.js, Astro, etc. / legado backend em migração — §3)
Go 1.25
Rust 1.85
PostgreSQL 16+
Redis 7+
Kubernetes 1.30+
OpenAPI 3.1
OpenTelemetry 1.x (estável)

Mudanças de versão major exigem ADR.


Anexo B — Glossário Mínimo

  • Bounded Context — fronteira explícita dentro da qual um modelo de domínio é consistente.
  • Monólito distribuído — serviços fisicamente separados mas acoplados por banco compartilhado, shared lib de domínio ou cadeia síncrona sem fronteira. O pior dos dois mundos. Proibido (§2).
  • BFF (Backend for Frontend) — camada server-side que serve um frontend específico e mantém os segredos fora do browser (§38).
  • Outbox Pattern — gravar evento em tabela no mesmo commit do dado de negócio; publicador assíncrono lê a tabela e publica no broker. Garante consistência sem dual-write.
  • DLQ — dead letter queue, fila de mensagens que falharam após retries.
  • Anti-Corruption Layer — adapter que isola seu domínio do modelo externo.
  • SLO — service level objective, alvo mensurável de qualidade (ex: 99.9% das requests < 300ms em 30 dias).
  • Error Budget — quanto você pode falhar dentro do SLO antes de freezar features.
  • Blameless Postmortem — análise de incidente focada em sistema/processo, não em culpa individual.
  • CSPRNG — gerador pseudoaleatório criptograficamente seguro. Obrigatório para tokens, ids de sessão e segredos (§14).
  • Macaquice — atalho que parece entregar mais rápido e entrega vulnerabilidade ou dívida. Catalogadas e vetadas na §37.