Añadir una feature sin entidad propia
La trampa más común al añadir algo es rellenar las cuatro capas por costumbre: crear
domain/mi-feature/ porque las demás lo tienen, y acabar con una entidad anémica que solo existe
para que la carpeta no esté vacía.
La capa se gana, no se rellena. Si no hay entidad nueva, no hay
domain/nuevo. Si no hay adaptador nuevo, no hay directorio eninfrastructure/.
Hay tres niveles, y casi todo cae en uno de ellos.
Nivel 1 — Solo presentación
Cuando el endpoint no tiene estado propio ni lógica de negocio.
Ejemplo real: health. Tres ficheros, todos en presentation/health/: controller, docs y
módulo. No hay dominio, ni use case, ni repositorio. Comprueba que el proceso responde y ya está.
Ejemplo real: webhooks. Recibe el callback de otro servicio (tokens de push muertos), lo
valida con un guard de cabecera secreta y delega en un use case que ya existe en otra feature.
No crea nada propio más allá del guard y el DTO de entrada.
Señal de que estás en este nivel: lo que haces es exponer algo, no decidir nada.
Nivel 2 — Sin dominio propio, reutilizando entidades
La feature tiene lógica real, incluso persiste datos, pero no introduce un concepto nuevo: trabaja sobre entidades que ya existen.
Ejemplo real: two-factor. Es una feature grande —activar, desactivar, verificar, códigos de
respaldo— y aun así no existe domain/two-factor/. Trabaja sobre:
User, que ya tienetwoFactorSecretytwoFactorEnabledAt.domain/users/backup-code.repository.ts, que vive con los usuarios porque de eso es de lo que cuelga un código de respaldo.
Su infraestructura tampoco tiene carpeta propia: los adaptadores están en
infrastructure/security/ junto a los demás de su naturaleza (otplib-totp.service.ts,
aes-gcm-secret-cipher.ts).
Lo que sí crea es lo que de verdad es suyo: use cases en application/two-factor/, y controller +
DTOs + docs en presentation/two-factor/.
Señal de que estás aquí: puedes describir la feature sin inventar un sustantivo nuevo. “Activar 2FA de un usuario” habla de un usuario, no de un “TwoFactor”.
Nivel 3 — Las cuatro capas
Hay un sustantivo nuevo que se guarda y del que se pregunta. Ese es el otro recorrido.
Cómo decidir en 30 segundos
Tres preguntas, en orden. La primera que dé “no” te para:
- ¿Hay un concepto nuevo que guardar? Una chapa, un reporte, una cita. Si no lo hay, no hay entidad ni repositorio. → como mucho nivel 2.
- ¿Hay una decisión de negocio? Validar, autorizar, calcular, coordinar dos pasos. Si no la hay, no hay use case. → nivel 1.
- ¿Habla con algo de fuera del proceso? Otra api, el disco, una librería de cifrado. Si no, no
hay nada que añadir a
infrastructure/. Y si sí, mira antes si encaja en un directorio que ya existe (security/,notifications/) en vez de crear uno.
Dónde colocar lo que no es de nadie
- Una función pura (generar un código, formatear algo) →
application/<feature>/sin clase ni inyección, comogenerate-pet-tag-code.ts. - Un paso compartido por muchos use cases → un service en
application/, pero solo con el criterio de use case o service. - Un adaptador de una capacidad técnica nueva → un port en
application/ports/y su implementación eninfrastructure/. Ver repositorio o port.