← Todos los proyectos
En producciónDesarrollo activo

App de Gestión de Turnos

PWA mobile-first para la gestión de turnos, cambios y reservas en entornos con rotación cíclica de personal: enfermería, seguridad, bomberos, policía o cualquier equipo que trabaje por turnos. Construida para uso real, con 54 usuarios, ciclos de 42 días y panel de administración completo.

React 18Node.jsPostgreSQLPrismaPWAJWT

¿Qué es y por qué existe?

En hospitales, servicios de emergencias, seguridad privada o cuerpos de policía, el personal se organiza en grupos con turnos de 12 horas y ciclos de rotación fijos. Los cambios de turno, las reservas y los eventos se suelen gestionar a mano: papeles, llamadas y mensajes de WhatsApp.

Esta app lo resuelve. Cada trabajador consulta su calendario desde el móvil y pide cambios desde la app; los responsables los aprueban o rechazan desde el panel de administración. Todo queda registrado y el sistema calcula los turnos futuros a partir del ciclo de cada grupo.

Lo que la separa de un ejercicio académico es que está hecha para usuarios reales, con restricciones operativas concretas: validaciones de negocio en servidor, protección de los turnos modificados a mano, documentos que no se pueden descargar por política interna y una PWA instalable en el iPhone sin pasar por el App Store.

‹Mayo 2026›
LMXJVSD
123 45678910 11121314151617 18192021222324 25262728293031
Miércoles, 20 de mayoNOCHE19:00 – 07:00
DíaNocheReserva
Tablón
Juan R.PENDIENTE

Busca cambio 26 may (DÍA)
por cualquier turno de noche

Responder
Ana M.ACORDADO

Cambio 2 jun (NOCHE)
Esperando aprobación del admin

Carlos V.RECHAZADO

Cambio 15 jun (DÍA)
Motivo: festivo obligatorio

Maquetas ilustrativas con datos ficticios.

Funcionalidades implementadas

Motor de turnos (42 días)

Calcula el turno de cualquier usuario en cualquier fecha futura. Un cron job semanal genera 12 semanas vista sin tocar los turnos modificados a mano.

Solicitudes de cambio de turno

Dos vías: tablón abierto (cualquiera puede responder) o acuerdo directo con un compañero. Flujo en dos fases con aprobación final del admin.

Panel de administración

Aprobar o rechazar cambios, asignar reservas, cambiar el estado del personal (activo, baja, permiso), crear eventos y dar de alta usuarios.

Sistema de reservas

Solo se puede asignar como reserva a quien tiene turno libre ese día. El frontend filtra, pero la regla se aplica en la API.

Notificaciones in-app

Se generan en cada evento relevante (cambios, reservas, documentos nuevos), con panel propio y marcado de leídas.

Documentos PDF solo lectura

El admin sube PDFs que se sirven inline, sin opción de descarga: Content-Disposition: inline y Cache-Control: no-store.

PWA instalable

Funciona en móvil, tablet y escritorio. Se instala en la pantalla de inicio del iPhone sin App Store, con experiencia de app nativa.

Autenticación JWT

Login con email y contraseña, tokens de 7 días, rutas protegidas por rol (ADMIN/USER) y redirección automática al expirar la sesión.

Decisiones técnicas

Motor de cálculo en lugar de almacenarlo todo

La función calcularTurno() determina el turno de cualquier usuario en cualquier fecha sin tener todos los registros en memoria. Los turnos se guardan en base de datos solo para consultas rápidas y para admitir cambios manuales, no como fuente de verdad del ciclo.

Turnos manuales protegidos frente al cron

El campo generadoAuto: false hace de protección. El cron semanal hace upsert con update: {} vacío: si el registro existe, no lo toca, y se conservan los cambios del admin.

Validación de reservas en servidor

El frontend filtra visualmente a los disponibles, pero POST /api/reservas comprueba en base de datos que el turno de ese día sea LIBRE antes de crear la asignación. La interfaz es experiencia de usuario; la validación real está en el servidor.

Motivo de rechazo obligatorio

Decisión funcional: los trabajadores tienen derecho a saber por qué se rechaza su solicitud. Si aprueba: false llega sin motivoRechazo, la API responde 400. Es una regla de negocio, no una validación técnica.

Stack técnico

Frontend

React 18Vite 5React Router 6TanStack QueryAxiosdate-fns

Backend

Node.jsExpress 4Prisma ORM 5JWTbcryptjsnode-cronMulter

Base de datos

PostgreSQLNeon (cloud)

PWA y diseño

vite-plugin-pwaCSS variablesMobile-first

Lo que estoy aprendiendo

⚛️

React con estado real

TanStack Query para sincronizar servidor y cliente, Context API para la autenticación y React Router con rutas protegidas por rol.

🗄️

Prisma y modelado relacional

Esquema con 10 modelos relacionados, migraciones, upserts seguros y cuándo guardar un estado calculado frente a calcularlo bajo demanda.

🔐

JWT en producción

Interceptor de Axios que añade el token, gestión de la expiración con redirección al login y separación real de rutas por rol en servidor.

📱

PWA y mobile-first

Configurar vite-plugin-pwa para instalar la app en iOS sin App Store y diseñar primero para móvil con CSS propio.

¿Hablamos del proyecto?

El repositorio será público cuando se complete el despliegue en producción.