Clientes
template-crm
Angular · personal de clínica
template-admin
Angular · superadmin
template-expo
React Native · cliente final
↓ HTTP · JWT de acceso + refresh rotativo
template-api
NestJS · multi-tenant · dueño de los datos
↓ HTTP best-effort — si no responde, la operación no falla
notification-api
ingesta · dueño de plantillas y logs
↓ BullMQ sobre Redis — cola, no HTTP
notification-worker
consumidor · entrega
↓
dev-identity-server no participa en este flujo: solo firma los JWT que protegen el panel de colas de notification-api.
Cada sección abre con una entrada de orientación y sigue con las decisiones concretas. Si es tu primera vez en un repo, lee las dos o tres primeras en orden; si ya lo conoces, ve directo a la decisión que tengas delante.
- Las cuatro capas, en dos minutos
Qué guarda cada capa, hacia dónde apuntan las dependencias y las dos reglas que no se rompen nunca.
- Añadir una feature con entidad propia
El recorrido completo por las cuatro capas, siguiendo un caso real de punta a punta: la chapa QR de una mascota.
- Añadir una feature sin entidad propia
No toda feature crea las cuatro capas. Los dos niveles más ligeros, con ejemplos de dónde parar.
- ¿Repositorio o port?
Los dos tipos de contrato de la api, por qué viven en carpetas distintas y cómo saber cuál te toca.
- ¿Métodos en la entidad, o fuera?
Por qué la mitad de las entidades tienen comportamiento y la otra mitad son datos puros.
- ¿Use case, o service con métodos?
84 use cases y 2 services. Las dos excepciones y las condiciones exactas que las justifican.
- ¿Evento, o llamada directa?
Qué sale del use case y qué se va a un handler: la frontera es si puede fallar sin invalidar la operación.
- ¿Mapper, o proyección inline?
Las dos fronteras de traducción, por qué existen aunque sean triviales, y el único caso donde no se crea mapper.
- Errores de dominio
Un error por fichero, el código HTTP decidido en el dominio y un único filtro que los traduce.
- Swagger y wiring del módulo
Dónde va la anotación de OpenAPI, qué exporta un módulo y cómo se agrupa la autorización repetida.
- Aislamiento entre tenants
Un solo esquema y un tenantId en cada fila: de dónde sale, dónde se comprueba, por qué la respuesta es 404 y qué hacer con el acceso cruzado consentido.
- Conectar con notification-api
Cómo se manda un aviso desde aquí: qué port usar, por qué hay dos estilos de petición y por qué la api arranca aunque el servicio esté caído.
- Un aviso que no se puede perder
La cola garantiza la entrega, pero llegar a la cola es una llamada HTTP que puede fallar. Cuándo eso importa y qué patrón lo cubre.
- Sesiones y refresh en el servidor
Access corto y refresh rotativo con las sesiones en Redis: qué se guarda hasheado, cómo se detecta un token robado y por qué el login no revela nada antes de comprobar la contraseña.
- Añadir una tarea programada
Un cron en @nestjs/schedule: dónde se registra, por qué lleva guarda de entorno y zona horaria explícita, y por qué la idempotencia no es una virtud sino el requisito.
- Cerrar una cuenta: borrado y anonimización
Dar de baja y suprimir los datos no son la misma operación. Cómo se separan, qué arrastra cada una y por qué el orden de los pasos importa más que el SQL.
- Unicidad cuando hay borrado blando
Un índice único cuenta también las filas borradas, y eso bloquea altas legítimas. El índice parcial, la trampa del índice compuesto y lo que deja de funcionar.
- Suspender un tenant sin echar a sus personas
El panel se cierra, pero el personal también es cliente. Degradar el rol de la petición en vez de rechazarla, y lo que esa técnica no arregla.
- Dar de baja a un tenant entero
Cerrar una cuenta tiene un destino; cerrar un tenant tiene cuatro. Qué se queda con quien lo necesita, qué se bloquea, qué se anonimiza y por qué las claves ajenas hacen el trabajo difícil.
- Entregar un fichero que se genera al pedirlo
Un ZIP con todos los datos de un usuario, servido en la misma petición: token de un solo uso porque la app descarga con GET, y streaming porque el fichero no cabe dos veces en memoria.
- Cuando el fichero ya no cabe en la petición
El mismo paquete, un orden de magnitud más grande: fila en PENDING, construcción por un cron, subida por partes mientras se calcula la suma, y la descarga días después.
- Los datos de un panel: agrupar, degradar, acotar, cachear
Once endpoints de gráfica se convierten en dos. Cómo se agrupan sin acoplarlas, por qué una clave viene null en vez de fallar, y dónde entra la caché.
- Cómo está organizado el cliente
Ocho carpetas, qué va en cada una, y por qué no hay gestor de estado.
- Hablar con la api: apiFetch
Un único punto de salida, con tres decisiones que hay que conocer antes de tocarlo: dónde viven los tokens, por qué el refresh se comparte y qué rutas no lo disparan.
- ¿useFetch o usePaginatedFetch?
Los dos hooks de carga, cuándo usa cada uno, y por qué no se toca el estado dentro del efecto.
- Sesión y almacenamiento seguro
Un contexto, SecureStore y el puente hacia apiFetch. Qué se guarda, qué se borra y qué pasa al caducar.
- Rutas con expo-router
Cada fichero es una pantalla. Cómo se protege un grupo, dónde va lo que se ejecuta una vez y cómo se navega con parámetros.
- Push: registrar el dispositivo y enrutar el aviso
Token nativo en vez del de Expo, importación diferida obligatoria, y cómo un toque acaba abriendo la pantalla correcta.
- Tema e i18n
Dónde viven los colores y los textos, y las dos reglas que impiden que se dispersen.
- Pasar la app a producción
El build se hace en la nube, así que no hace falta Android Studio ni Xcode. Qué configurar, en qué orden, y qué pide cada tienda.