| name | novo-endpoint |
| description | Cria um endpoint REST completo no padrão do projeto — atualiza a especificação OpenAPI antes do código, implementa validação, autorização RBAC e RLS, segue o envelope de resposta padrão e escreve os testes de integração. Use ao adicionar qualquer rota à API. |
Procedimento
- Identificar o grupo em
docs/catalogo-endpoints.md. Confirmar o domínio em docs/catalogo-dominios.md.
- Definir o acesso por perfil (P1–P5 / público) antes de qualquer código.
- Atualizar
services/api/openapi.yaml com:
- caminho
/v1/<recurso> no plural
- método HTTP correto
- parâmetros de path/query
- schema da requisição (com obrigatoriedade e formato)
- schema da resposta (envelope padrão)
- schemas de erro (formato único)
security declarando o regime (público / autenticado / autorizado)
- Implementar em
services/backend/<dominio>/:
- Validação de entrada contra o schema (tipo, formato, obrigatoriedade, taxonomia).
- Autorização:
requireCapability('<cap>') ou equivalente. Verificação antes de qualquer efeito.
- Regra de negócio: vive em
regras.ts do módulo. Nunca na camada de transporte.
- Persistência: via
repositorio.ts. Confia na RLS do banco como última linha de defesa.
- Eventos: publicar evento de domínio se a operação causa fato que outros podem reagir (cap. 13).
- Resposta: envelope padrão com
dados e paginacao (em coleção).
- Testes de integração em
*.integration.test.ts:
- Caso feliz: a operação funciona.
- Validação: cada campo obrigatório falha individualmente.
- Autorização: usuário sem capability é rejeitado com 403.
- RLS: usuário de outra microrregião não enxerga o recurso.
- Idempotência (operações de escrita sensíveis).
- Documentar códigos de erro estáveis usados.
- Acionar
revisor-seguranca e — se há dado pessoal — revisor-lgpd.
Modelo de referência (estrutura)
import { z } from "zod";
import { requireCapability } from "@/lib/auth";
import { CategoriasDemanda } from "@/packages/taxonomias";
import { registrarDemanda } from "./regras";
const Entrada = z.object({
titulo: z.string().min(3).max(200),
area: z.enum(CategoriasDemanda),
microrregiao_id: z.string().uuid(),
});
export async function POST(req: Request) {
const session = await requireCapability("registrar:demanda");
const dados = Entrada.parse(await req.json());
const demanda = await registrarDemanda({
autor_uuid: session.uuid,
...dados,
});
return envelope({ dados: demanda }, 201);
}
Antipatterns rejeitados
- Endpoint que pula a etapa "atualizar OpenAPI primeiro".
- Endpoint autenticado sem verificação de capability (presume que basta estar logado).
- Resposta com formato diferente do envelope padrão.
console.log em lugar de logger estruturado.
- Validação só no cliente.
- Endpoint público filtrando dado pessoal na tela.
Saída
Spec OpenAPI atualizada, código implementado em camadas, testes de integração verdes, código de erro documentado. Aprovação dos revisores antes do merge.