# Achado crítico: validação de entrada não funcionava sob `tsx` **Resumo**: de quando `apps/api` foi criada (fase apps/api) até a fase Dialplan, `ValidationPipe` global do NestJS **não validava nada**. Todo `@Body()` passava batendo, incluindo campos não permitidos (`forbidNonWhitelisted`) e valores fora de qualquer allowlist (`@IsIn`). Descoberto ao testar deliberadamente que a allowlist de applications do dialplan (que existe especificamente pra impedir uma tenant de configurar `application: "system"` com dados de shell arbitrários — agente.md secao 180) **aceitou** a entrada maliciosa com 201. ## Causa raiz `apps/api` rodava via `tsx src/main.ts` (esbuild por baixo). O NestJS decide qual classe usar pra instanciar/validar um `@Body()` lendo a metadata `design:paramtypes` do método do controller (reflect-metadata, `emitDecoratorMetadata` do TypeScript). **esbuild não faz checagem de tipos completa entre arquivos** — pra parâmetros cujo tipo vem de um `import` de outro arquivo, ele às vezes emite `Object` genérico em vez da classe real. Quando `ValidationPipe` recebe `metatype === Object`, ele **pula a validação silenciosamente** (comportamento documentado do Nest: tipos primitivos/ genéricos são considerados "nada pra validar"). Isso é a mesma classe de bug já encontrada na fase Extensions (`PermissionGuard` injetando `Reflector` via construtor chegava `undefined` em runtime) — mas ali o sintoma era um crash óbvio (`TypeError`), fácil de notar. Aqui o sintoma é **ausência de erro**: a validação simplesmente não roda, sem log, sem exceção, sem pista nenhuma a não ser testar deliberadamente com entrada inválida. ## Correção `tsc` de verdade faz checagem de tipos completa e emite `design:paramtypes` corretamente (confirmado inspecionando o `dist/*.js` gerado: aparece a referência real da classe, ex. `create_extension_dto_1.CreateExtensionDto`, em vez de `Object`). A partir de agora `apps/api` **sempre** builda com `tsc` antes de rodar: ```json "build": "tsc -p tsconfig.json", "start": "tsx dist/main.js", "dev": "tsc -p tsconfig.json && tsx dist/main.js" ``` Importante: o `start`/`dev` rodam o JS compilado através do **`tsx`**, não do `node` puro — porque os pacotes internos (`@b2bcall/shared`, `@b2bcall/database`, ...) ainda não têm build próprio (`main` aponta pro `.ts` fonte, não pra um `dist/`). `tsx` resolve isso via seu loader; `node` sozinho quebraria tentando importar um arquivo `.ts` diretamente. Ver docs/AUTHENTICATION.md pra mais contexto sobre essa limitação dos pacotes internos. **Nunca rode `apps/api` com `tsx src/main.ts` (ou `tsx watch`) direto — só via `pnpm run build && pnpm run start`, ou `pnpm run dev`.** ## Limpeza feita Uma extension de dialplan de teste com `application: "system"` foi criada durante o teste que expôs o bug (nunca chegou a ser incluída numa versão gerada/ativada — não havia como executar de verdade) e foi apagada imediatamente após a correção. ## O que revisar - `packages/telephony`, `packages/auth`, `packages/database`: não usam `ValidationPipe`/decorators do Nest, não são afetados por esse bug específico. - `apps/freeswitch-events` e `apps/freeswitch-config`: não usam NestJS, não são afetados. - Todos os DTOs de `apps/api` (auth, extensions, trunks, dialplan) — a correção é geral (troca de runtime, não patch por endpoint), então todos passam a validar corretamente a partir desta fase. Reverificado com dois testes deliberados pós-correção (campo não permitido em `/extensions`, application fora da allowlist em `/dialplan/extensions`) — ambos corretamente rejeitados com 400.