Auditoría de un proyecto NestJS con un agente de IA
Auditoría de un proyecto NestJS con un agente de IA
Los catorce capítulos anteriores explican qué hace de calidad a un backend NestJS y cómo se ve cada práctica en el código. Este último capítulo cierra el ciclo: convierte todo el curso en un procedimiento reproducible que un agente de IA con acceso al repositorio ejecuta para auditar un proyecto NestJS real y emitir un informe priorizado por severidad, con la evidencia (archivo:línea) que respalda cada hallazgo.
La idea no es que el agente diga “el código se ve bien”. Es que recorra diez dimensiones —las mismas del curso—, ejecute búsquedas concretas (ripgrep, grep, inspección del package.json), y para cada smell devuelva un veredicto con severidad, ubicación, impacto y una recomendación enlazada al capítulo que la explica. Un agente hace esto en minutos sobre un repo que a una persona le tomaría un día leer entero.
flowchart LR
A[Fase 0<br/>Reconocimiento] --> B[10 dimensiones<br/>de auditoría]
B --> C[Hallazgos con<br/>evidencia]
C --> D[Informe<br/>priorizado]
D -.aprobación.-> E[Remediación]
Cómo usar este capítulo
- Abrí una sesión limpia de tu agente (Claude Code, Cursor, Codex, etc.) en la raíz del proyecto NestJS que querés auditar.
- Copiá el bloque “Prompt para el agente” completo (está al final) y pegalo como primer mensaje.
- El agente ejecuta la Fase 0 (reconocimiento) y luego las diez dimensiones, y devuelve el informe estructurado.
- Regla de oro: el agente audita y reporta, no modifica nada. La remediación se propone como plan y espera tu aprobación explícita.
El capítulo primero desglosa cada fase con las búsquedas concretas para que entiendas qué hace el agente y puedas revisar su trabajo. Al final está el prompt listo para copiar.
Escala de severidad
Cada hallazgo lleva una severidad. Usá siempre esta escala, nunca un binario “está/no está”:
| Severidad | Significado |
|---|---|
| CRÍTICO | Vulnerabilidad explotable ya presente, o pérdida/corrupción de datos posible (p. ej. entidad con password en la respuesta, transacción ausente en una operación multi-tabla). |
| ALTO | Riesgo serio de seguridad o de rendimiento bajo carga real (N+1 en un endpoint caliente, autorización sólo por rol sin chequeo de propiedad). |
| MEDIO | Deuda de calidad que degrada mantenibilidad o rendimiento moderado (lógica de negocio en el controlador, await en serie evitable). |
| BAJO | Mejora recomendable sin impacto inmediato (console.log residual, falta de paginación en un listado chico). |
Fase 0 — Reconocimiento
Antes de auditar nada, el agente construye un mapa del proyecto. Sin este contexto, muchas heurísticas dan falsos positivos (p. ej. buscar helmet en un proyecto Fastify, donde el paquete es @fastify/helmet).
Qué detectar y cómo:
# Versión de Nest y adapter (Express por defecto vs Fastify)
rg '"@nestjs/(core|common|platform-express|platform-fastify)"' package.json
# ORM / capa de datos
rg '"(@prisma/client|typeorm|@mikro-orm/core|drizzle-orm|mongoose)"' package.json
# Scripts disponibles (test, lint, e2e)
rg '"(test|test:e2e|test:cov|lint|start:prod)"' package.json
# ¿Hay validación y config centralizada?
rg '"(class-validator|class-transformer|zod|@nestjs/config|joi)"' package.json
# Estructura de módulos: cuántos módulos y cómo se organizan
fd -e module.ts
fd -e controller.ts | wc -l
fd -e service.ts | wc -l
# ¿ValidationPipe global? ¿helmet? ¿versión de Node?
rg 'useGlobalPipes|useGlobalFilters|useGlobalInterceptors' src/main.ts
rg '"node"' package.json # engines
Con eso el agente redacta un resumen de 5-8 líneas: versión de Nest (11.x), adapter (Express/Fastify), ORM, número de módulos, si existe ConfigModule, si hay ValidationPipe global, y qué comandos de test/lint están disponibles. Ese resumen encabeza el informe y condiciona el resto: por ejemplo, si el adapter es Fastify, el agente busca @fastify/helmet y @fastify/rate-limit en vez de helmet y @nestjs/throttler sobre Express.
Si
package.jsondeclara Nest^12onext, el agente lo señala: cambian las recomendaciones de validación (Standard Schema), el runner de tests (Vitest en vez de Jest) y el sistema de módulos (ESM). Ver Validación y transformación.
Las diez dimensiones de auditoría
Cada dimensión tiene: qué buscar, comandos/greps concretos y el capítulo de referencia para la recomendación. El agente recorre las diez en orden.
1. Arquitectura y organización — caps. 2 y 3
Qué buscar: lógica de negocio en los controladores, acoplamiento directo al ORM desde la capa de dominio, e imports circulares entre módulos.
# Lógica de negocio en el controller: llamadas al repositorio/ORM,
# lógica condicional o cálculos dentro de métodos de *.controller.ts
rg -n 'repository|prisma|entityManager|\.save\(|\.create\(|if \(|for \(' -g '*.controller.ts'
# Controladores gordos (más de ~120 líneas suele indicar lógica mal ubicada)
fd -e controller.ts -x wc -l {} \; | sort -rn | head
# Acoplamiento al ORM en la capa de dominio/servicios de negocio
rg -n 'import .*(typeorm|@prisma/client|mongoose)' src/**/domain src/**/core 2>/dev/null
# Imports circulares: forwardRef es la señal delatora
rg -n 'forwardRef' -g '*.ts'
Señales de hallazgo: un *.controller.ts que inyecta un repositorio y arma queries; if/for con reglas de negocio dentro del handler; entidades de dominio que importan decoradores de TypeORM/Prisma. Recomendación: mover la lógica a servicios de aplicación y aislar el dominio del ORM (puertos y adaptadores). Ver Organización del proyecto y SOLID en NestJS.
2. Inyección de dependencias y providers — cap. 4
Qué buscar: Scope.REQUEST usado sin necesidad (contamina toda la cadena de dependencias y elimina el caché del contenedor), forwardRef como parche de dependencias circulares, y providers globales innecesarios.
# Scope REQUEST/TRANSIENT: cada uno reconstruye el árbol por request
rg -n 'Scope\.(REQUEST|TRANSIENT)' -g '*.ts'
# forwardRef: casi siempre delata un problema de diseño de módulos
rg -n 'forwardRef' -g '*.ts'
# Módulos globales: @Global() esparcido rompe el encapsulamiento
rg -n '@Global\(\)' -g '*.ts'
# Providers con token string mágico sin constante centralizada
rg -n "provide: ['\"]" -g '*.ts'
Señales: Scope.REQUEST en un provider que no necesita estado por request; @Global() en módulos de dominio; forwardRef entre dos servicios que podrían separarse en un tercer módulo. Impacto de Scope.REQUEST: el contenedor instancia el provider y toda su cadena en cada request, perdiendo el singleton. Ver Providers y DI avanzada.
3. Validación y transformación — cap. 5
Qué buscar: ValidationPipe sin whitelist, ValidationPipe no registrado globalmente, y validación hecha a mano dentro de servicios en vez de DTOs.
# ¿ValidationPipe global y con whitelist/forbidNonWhitelisted?
rg -n 'ValidationPipe' -g '*.ts'
rg -n 'whitelist|forbidNonWhitelisted|transform: true' src/main.ts
# DTOs sin decoradores de validación (clases *.dto.ts sin @Is*)
fd -e dto.ts -x sh -c 'rg -L "@Is|@Validate|@Type" "$1" >/dev/null || echo "sin validacion: $1"' _ {}
# Validación manual en servicios (síntoma de DTO ausente)
rg -n 'throw new BadRequestException' -g '*.service.ts'
rg -n 'typeof .* !== |=== undefined|isNaN\(' -g '*.service.ts'
Señales: app.useGlobalPipes(new ValidationPipe()) sin whitelist: true (deja pasar propiedades no declaradas, riesgo de mass assignment); DTOs que son interfaces sin decoradores; servicios llenos de if que validan tipos que un DTO resolvería. Recomendación: ValidationPipe global con whitelist: true y forbidNonWhitelisted: true. Ver Validación y transformación.
4. Ciclo de vida del request — cap. 6
Qué buscar: autorización dentro del service (debería vivir en un guard), try/catch que traga errores en vez de delegarlos a un exception filter, y stack traces expuestos al cliente.
# Autorización en el service en lugar de un Guard
rg -n 'if \(.*user\.role|req\.user|currentUser\.' -g '*.service.ts'
# try/catch que devuelve genéricos u oculta el error real
rg -n 'catch \(' -g '*.service.ts' -A2
# Stack traces / error.message crudo enviado al cliente
rg -n 'error\.stack|error\.message' -g '*.controller.ts' -g '*.filter.ts'
# ¿Existe algún exception filter global?
rg -n 'useGlobalFilters|@Catch\(' -g '*.ts'
Señales: chequeos de rol dentro de métodos de servicio (deberían ser un @UseGuards); catch que hace return null o re-lanza un Error genérico perdiendo el tipo; envío de error.stack en la respuesta. Recomendación: guards para autz, filtros para errores, y nunca serializar el stack en producción. Ver Ciclo de vida del request.
5. Rendimiento — cap. 7
Qué buscar: await en serie donde podría ir Promise.all, ausencia total de caché, y listados sin paginación.
# await consecutivos independientes (candidatos a Promise.all)
rg -n 'await ' -g '*.service.ts' -A1 | rg -B1 'await '
# ¿Se usa algo de caché?
rg -n 'CacheModule|@CacheKey|CACHE_MANAGER|cacheManager' -g '*.ts'
# Endpoints que devuelven listas sin take/limit/skip
rg -n '\.find\(\)|findAll\(\)|\.findMany\(\{\}\)' -g '*.ts'
rg -n 'take:|limit:|skip:|cursor:' -g '*.ts' # si no aparece, no hay paginación
Señales: dos o más await seguidos sobre promesas independientes (se ejecutan en serie, sumando latencias en vez de solaparlas); ningún CacheModule; find() sin take/limit. Impacto concreto: tres await en serie de 100 ms cada uno tardan 300 ms; con Promise.all, 100 ms. Ver Rendimiento.
6. Persistencia — cap. 8
Qué buscar: N+1 queries, transacciones ausentes en operaciones multi-tabla, y SQL crudo o SELECT * sin proyección.
# N+1: find/query dentro de un map/forEach/for
rg -n 'map\(async|for .* of |forEach\(async' -g '*.service.ts' -A3 | rg 'await .*(find|query|repository)'
# Operaciones de escritura múltiple sin transacción
rg -n '\.save\(|\.create\(|\.update\(|\.delete\(' -g '*.service.ts'
rg -n 'transaction\(|\$transaction|queryRunner|manager\.transaction' -g '*.ts' # si no aparece cerca, falta tx
# SQL crudo / QueryBuilder sin proyección
rg -n 'getManager\(|\.query\(|createQueryBuilder' -g '*.ts'
rg -n 'select \*|SELECT \*' -g '*.ts'
Señales: un await repository.find(...) dentro de un map/for (una query por iteración, O(n) round-trips); varios save/update seguidos sin un $transaction/queryRunner alrededor; .query('SELECT * ...') que trae columnas de más. Recomendación: cargar relaciones con relations/include/join, envolver escrituras en transacciones, y proyectar sólo las columnas necesarias. Ver Persistencia.
7. Seguridad — cap. 10
Qué buscar: sin helmet ni rate limiting, autorización sólo por rol (BOLA: falta el chequeo de propiedad del recurso), secretos hardcodeados, y entidades que exponen password/hash en la respuesta.
# helmet y rate limiting (según adapter)
rg -n 'helmet|@fastify/helmet' -g '*.ts'
rg -n 'ThrottlerModule|@Throttle|@fastify/rate-limit' -g '*.ts'
# BOLA: autz sólo por rol, sin comparar ownerId con el usuario actual
rg -n '@Roles\(|hasRole|user\.role ===' -g '*.ts'
rg -n 'ownerId|userId ===|\.userId ==' -g '*.service.ts' # si no aparece, sospechar BOLA
# Secretos hardcodeados
rg -n "(secret|password|apiKey|token|jwt).{0,3}=.{0,3}['\"][A-Za-z0-9+/_-]{8,}" -g '*.ts' -i
rg -n "['\"]sk-|AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{36}" -g '!node_modules'
# Entidad con password expuesto: falta @Exclude / select:false
rg -n 'password|passwordHash|salt' -g '*.entity.ts'
rg -n '@Exclude\(\)|select: false' -g '*.entity.ts' # debe aparecer junto a password
Señales: ningún helmet; ningún ThrottlerModule; endpoints protegidos sólo con @Roles('user') que nunca comparan el ownerId del recurso con el req.user.id (cualquier usuario autenticado accede a recursos de otro: Broken Object Level Authorization); literales tipo jwtSecret = 'supersecret'; una entidad con password sin @Exclude() (class-transformer) ni select: false (TypeORM), que se serializa en cada respuesta. Este último es CRÍTICO. Ver Seguridad.
8. Configuración — cap. 11
Qué buscar: process.env disperso por todo el código en vez de ConfigService, y ausencia de validación del esquema de variables de entorno.
# process.env accedido fuera de la config centralizada
rg -n 'process\.env\.' -g '*.ts' -g '!*.config.ts' -g '!main.ts'
# ¿Hay ConfigModule y validación de env?
rg -n 'ConfigModule\.forRoot|ConfigService' -g '*.ts'
rg -n 'validationSchema|validate:|envSchema' -g '*.ts' # si no aparece, no se validan las env
Señales: process.env.DATABASE_URL leído en servicios y controladores (sin tipado, sin validación, falla en runtime si falta); ConfigModule.forRoot() sin validationSchema (Joi) ni validate (Zod/class-validator). Impacto: una variable faltante o mal escrita revienta en producción en el peor momento, no al arrancar. Ver Configuración.
9. Observabilidad — cap. 12
Qué buscar: console.log en vez de un logger estructurado, y ausencia de health checks.
# console.* residual (usar Logger de Nest o pino/winston)
rg -n 'console\.(log|error|warn|debug|info)' -g '*.ts' -g '!*.spec.ts'
# ¿Hay health checks (Terminus)?
rg -n '@nestjs/terminus|HealthCheck|@Get\(.health.\)' -g '*.ts'
# ¿Logger estructurado?
rg -n 'nestjs-pino|winston|new Logger\(' -g '*.ts'
Señales: console.log en código de producción (sin niveles, sin correlación, sin formato JSON parseable por el agregador); ningún endpoint /health ni @nestjs/terminus. Recomendación: Logger de Nest o nestjs-pino, y un health check con Terminus que verifique DB y servicios upstream. Ver Observabilidad.
10. Testing — cap. 13
Qué buscar: mocks excesivos que acoplan el test a la implementación, ausencia de tests e2e, y falta de cobertura de los caminos de error.
# Densidad de mocks: muchos jest.fn()/mock por spec indica sobre-mockeo
rg -c 'jest\.fn\(\)|mockResolvedValue|createMock' -g '*.spec.ts' | sort -t: -k2 -rn | head
# ¿Existen tests e2e?
fd -e e2e-spec.ts
rg -n 'supertest|request\(app' -g '*.ts'
# ¿Se testean los caminos de error? (expect a que se lance)
rg -n 'toThrow|rejects\.toThrow|expect.*Exception' -g '*.spec.ts' # escasez = sólo happy path
Señales: specs con decenas de jest.fn() que mockean hasta las dependencias internas (el test verifica la implementación, no el comportamiento; se rompe con cualquier refactor); cero archivos *.e2e-spec.ts; ausencia de toThrow/rejects.toThrow (sólo se prueba el camino feliz). Ver Testing.
Tabla resumen de heurísticas
Para revisar el trabajo del agente de un vistazo, este es el mapa smell → dónde mirar → señal:
| Dimensión | Búsqueda clave | Señal de hallazgo | Cap. |
|---|---|---|---|
| Arquitectura | repository|prisma en *.controller.ts | Controller que arma queries | 2, 3 |
| DI | Scope.REQUEST, forwardRef | Scope abusado, ciclo parcheado | 4 |
| Validación | whitelist en main.ts | ValidationPipe sin whitelist | 5 |
| Request | if.*user.role en *.service.ts | Autz en el service | 6 |
| Rendimiento | await seguidos, CacheModule | Serie evitable, sin caché | 7 |
| Persistencia | find dentro de map/for | N+1 queries | 8 |
| Persistencia | save/update sin $transaction | Transacción ausente | 8 |
| Seguridad | password sin @Exclude en *.entity.ts | Password serializado (CRÍTICO) | 10 |
| Seguridad | @Roles sin chequeo de ownerId | BOLA | 10 |
| Seguridad | helmet, ThrottlerModule ausentes | Sin hardening HTTP | 10 |
| Configuración | process.env fuera de *.config.ts | Env dispersa, sin validar | 11 |
| Observabilidad | console.log, terminus ausente | Log no estructurado, sin health | 12 |
| Testing | toThrow escaso, sin *.e2e-spec.ts | Sólo happy path, sin e2e | 13 |
Cuidado con los falsos positivos. Un
console.logen un script de seed no es un hallazgo;Scope.REQUESTen un provider de contexto multi-tenant puede ser correcto. El agente debe leer el contexto de cada coincidencia antes de reportarla, no listar greps en crudo.
Formato del informe de auditoría
Cada hallazgo se reporta con esta estructura fija:
- **[SEVERIDAD] Título del hallazgo** — dimensión
- Ubicación: `ruta/archivo.ts:línea`
- Impacto: qué consecuencia técnica tiene (rendimiento, seguridad, mantenibilidad)
- Recomendación: qué cambio aplicar + [enlace al capítulo](/tecnologias/nestjs-buenas-practicas/NN-slug/)
Y el informe completo sigue esta plantilla:
# Auditoría NestJS — <nombre del proyecto>
## Resumen del stack (Fase 0)
- Nest: 11.x · Adapter: <Express|Fastify> · ORM: <Prisma|TypeORM|…>
- Módulos: N · ConfigModule: <sí|no> · ValidationPipe global: <sí|no>
- Comandos: test=<…>, lint=<…>, e2e=<…>
## Tabla de hallazgos
| # | Dimensión | Hallazgo | Severidad | Ubicación |
|---|-----------|----------|-----------|-----------|
| 1 | Seguridad | Entidad User serializa password | CRÍTICO | user.entity.ts:14 |
| 2 | Persistencia | N+1 al listar pedidos | ALTO | orders.service.ts:42 |
| 3 | Configuración | DATABASE_URL vía process.env | MEDIO | app.service.ts:8 |
| … | … | … | … | … |
## Score
- CRÍTICO: N · ALTO: N · MEDIO: N · BAJO: N
- Dimensiones sin hallazgos: <lista>
## Los 3 hallazgos más urgentes (detalle)
- **[CRÍTICO] La entidad User expone el hash de la contraseña** — Seguridad
- Ubicación: `src/users/user.entity.ts:14`
- Impacto: el campo `password` se serializa en toda respuesta que devuelva un User; se filtra en `GET /users/:id`.
- Recomendación: agregar `@Exclude()` (class-transformer) o `select: false` (TypeORM) y activar `ClassSerializerInterceptor`. Ver [Seguridad](/tecnologias/nestjs-buenas-practicas/10-seguridad/).
- **[ALTO] N+1 al listar pedidos con sus ítems** — Persistencia
- Ubicación: `src/orders/orders.service.ts:42`
- Impacto: un `find` de items por cada pedido dentro de un `map`; 100 pedidos = 101 queries.
- Recomendación: cargar con `relations: ['items']` / `include`. Ver [Persistencia](/tecnologias/nestjs-buenas-practicas/08-persistencia/).
- **[ALTO] Endpoint sin chequeo de propiedad (BOLA)** — Seguridad
- Ubicación: `src/orders/orders.controller.ts:31`
- Impacto: `@Roles('user')` permite a cualquier usuario leer pedidos ajenos vía `GET /orders/:id`.
- Recomendación: guard que compare `order.userId` con `req.user.id`. Ver [Seguridad](/tecnologias/nestjs-buenas-practicas/10-seguridad/).
## Plan de remediación priorizado
### CRÍTICO
- [ ] #1 Ocultar `password` de la serialización — user.entity.ts
### ALTO
- [ ] #2 Resolver N+1 en listado de pedidos — orders.service.ts
- [ ] #3 Agregar chequeo de propiedad (BOLA) — orders.controller.ts
### MEDIO / BAJO
- [ ] #…
> Espero tu aprobación antes de modificar ningún archivo.
Prompt para el agente
Copiá todo el bloque siguiente y pegalo como primer mensaje a tu agente, con la sesión abierta en la raíz del proyecto NestJS.
# MISIÓN: Auditoría de calidad de un proyecto NestJS
Sos un auditor de backends NestJS. Tu misión es evaluar ESTE proyecto contra las
buenas prácticas de arquitectura, rendimiento, persistencia, seguridad,
configuración, observabilidad y testing, y emitir un informe priorizado por
severidad con evidencia en `archivo:línea`.
REGLA DE ORO: NO modifiques ningún archivo. Solo leés, buscás y reportás. Toda
remediación se propone como plan y espera mi aprobación explícita.
## FASE 0 — Reconocimiento
Inspeccioná `package.json`, `src/main.ts` y la estructura de carpetas para
determinar: versión de NestJS, adapter (Express/Fastify), ORM, número de módulos,
si hay ConfigModule, si el ValidationPipe es global, y qué comandos de test/lint
existen. Resumí en 5-8 líneas. Este resumen condiciona el resto (p. ej. en
Fastify buscá `@fastify/helmet`, no `helmet`).
## FASE 1 — Auditoría por dimensión
Recorré estas 10 dimensiones. Para cada smell usá ripgrep/grep, LEÉ el contexto de
cada coincidencia (evitá falsos positivos) y reportá sólo hallazgos reales:
1. Arquitectura: lógica de negocio en controllers, acoplamiento al ORM en el
dominio, imports circulares (`forwardRef`).
2. DI: `Scope.REQUEST`/`TRANSIENT` abusado, `forwardRef`, `@Global()` innecesario.
3. Validación: `ValidationPipe` no global o sin `whitelist`, DTOs sin decoradores,
validación manual en servicios.
4. Ciclo de request: autz dentro del service, `try/catch` que traga errores,
`error.stack`/`error.message` expuesto al cliente, sin exception filter.
5. Rendimiento: `await` en serie evitable (usar `Promise.all`), sin caché, listados
sin paginación (`take`/`limit`).
6. Persistencia: N+1 (`find`/`query` dentro de `map`/`for`), escrituras múltiples
sin transacción, SQL crudo / `SELECT *`.
7. Seguridad: sin `helmet` ni rate limiting, BOLA (autz sólo por rol sin chequear
propiedad del recurso), secretos hardcodeados, entidad con `password`/hash sin
`@Exclude()`/`select:false` (esto es CRÍTICO).
8. Configuración: `process.env` disperso fuera de la config central, sin validación
de variables de entorno.
9. Observabilidad: `console.log` en producción, sin health checks (Terminus).
10. Testing: mocks excesivos acoplados a la implementación, sin tests e2e, sin
cobertura de caminos de error (`toThrow`).
Severidad: CRÍTICO (explotable / pérdida de datos) · ALTO (riesgo serio) ·
MEDIO (deuda de calidad) · BAJO (mejora recomendable).
## FASE 2 — Informe
Entregá, en este orden:
1. Resumen del stack (Fase 0).
2. Tabla de hallazgos: # | dimensión | hallazgo | severidad | archivo:línea.
3. Score por severidad y dimensiones sin hallazgos.
4. Los 3 hallazgos más urgentes en detalle (ubicación, impacto, recomendación).
5. Plan de remediación priorizado con checkboxes, agrupado por severidad.
Cada hallazgo cita su evidencia (`archivo:línea` y el fragmento). No inventes
ubicaciones. Esperá mi aprobación antes de tocar ningún archivo.
Automatizar parte de la auditoría en CI
El agente da profundidad y contexto, pero varias dimensiones se prestan a gates automáticos en cada Pull Request, sin esperar una auditoría manual:
- Validación/estilo:
eslintcon reglas de@typescript-eslintyeslint-plugin-securityatrapaconsole.log,anyy patrones peligrosos. - Secretos (dimensión 7):
gitleaksotrufflehogcomo paso obligatorio, revisando también el historial de git. - Cobertura de errores (dimensión 10):
jest --coveragecon umbral mínimo por rama (branches), que falla si el happy path es lo único cubierto. - N+1 y queries lentas (dimensión 6): logging de queries de Prisma/TypeORM en los tests e2e, con una aserción sobre el número máximo de queries por endpoint.
La combinación ideal: CI atrapa las regresiones conocidas en cada commit, y la auditoría con agente descubre lo que ningún linter tiene regla —lógica de negocio filtrada al controlador, BOLA, transacciones ausentes, sobre-mockeo—.
Checklist
- Abriste el agente en la raíz del proyecto y le pegaste el prompt completo.
- La Fase 0 identificó versión de Nest, adapter, ORM y comandos de test/lint.
- El agente recorrió las 10 dimensiones con greps y leyó el contexto de cada coincidencia.
- Cada hallazgo tiene severidad, ubicación (
archivo:línea), impacto y recomendación enlazada al capítulo. - Revisaste falsos positivos (seeds, tests, casos legítimos de
Scope.REQUEST). - El informe incluye tabla, score por severidad y los 3 hallazgos más urgentes en detalle.
- El plan de remediación está priorizado (CRÍTICO → ALTO → MEDIO/BAJO) con checkboxes.
- Configuraste al menos un gate automático en CI (secretos, cobertura, N+1).
- El agente esperó tu aprobación antes de modificar nada.
Con esto cerrás el curso. Recorriste el camino completo: de los cimientos de arquitectura e IoC, a la mecánica de providers, validación y ciclo de request; del rendimiento y la persistencia, a la seguridad, la configuración, la observabilidad y el testing; y terminaste con un catálogo de patrones y este protocolo que convierte todo ese conocimiento en un procedimiento que un agente ejecuta sobre tu propio código. Ahora tenés el criterio de ingeniería para que un backend NestJS aguante producción real, y una herramienta para verificarlo de forma reproducible.
¡Felicitaciones por completar NestJS: Buenas Prácticas! Volvé cuando quieras al índice del curso para repasar cualquier capítulo.