PROYECTO_01
Skilled ERP
ERP de nóminas, empleados, inventario y herramientas: API JSON en Flask con 216 endpoints y SPA en React/Vite, con notificaciones en tiempo real por Socket.IO.
- TIPO
- Full Stack · Seguridad
- ESTADO
- EN PRODUCCIÓN
- CAPTURAS
- 5
CONTEXTO
Sistema de gestión interna que concentra nóminas, expedientes de empleados, inventario y herramientas en una sola plataforma, con control estricto de qué información puede ver cada uno de los 6 roles.
QUÉ CUBRE
- Empleados: alta, baja y edición, con campos laborales, personales, médicos y financieros filtrados por whitelist según el rol.
- Nómina: prenómina, descuentos, depósitos extra, préstamos con abonos y ajustes por periodo.
- Horas: reportes semanales, registros diarios, ausencias, saldo de vacaciones y captura por RFID/QR.
- Inventario: productos, almacenes y estantes con QR, solicitudes con flujo de aprobación y entrega parcial, tomas físicas con ajuste automático y órdenes de compra.
- Herramientas: catálogo y unidades físicas rastreables por serie/QR, con asignaciones, mantenimientos, incidencias y baja autorizada.
- Reportes en PDF y Excel (recibos, constancias, totales por proyecto) saneados contra inyección de fórmulas.
ARQUITECTURA
- API JSON en Flask 3 + SQLAlchemy 2 con 18 blueprints y 216 endpoints documentados; migraciones con Alembic.
- Cadena de producción: Cloudflare Tunnel → Nginx → Gunicorn → Flask. El origen no publica ningún puerto hacia afuera.
- 4 workers gevent con WebSocket real; todo el estado compartido (rate-limit, lockout, anti-replay, eventos) vive en Redis.
- Archivos en Cloudflare R2: bucket público para el catálogo y privado para documentos, con disco como respaldo.
- Docker Compose para desarrollo: api, PostgreSQL, Redis y ClamAV, cada uno con su volumen.
SEGURIDAD Y CONCURRENCIA
- Login en dos pasos: la contraseña devuelve un token de un solo uso y solo con él se pide el código TOTP; el secreto 2FA se guarda cifrado.
- JWT con refresh en cookie httpOnly y renovación automática; varias peticiones en vuelo comparten un solo refresh.
- Las imágenes externas se validan contra SSRF y por magic bytes, se reescriben a WebP y se escanean con ClamAV antes de guardarse.
- Los movimientos de inventario toman la fila con SELECT … FOR UPDATE, de modo que dos operaciones sobre el mismo stock no se pisan.
- Rate-limit y bloqueo escalado de cuenta con Flask-Limiter sobre Redis; cabeceras de seguridad con Flask-Talisman.
OBSERVABILIDAD
- Cada respuesta pasa por un after_request que suma contadores en Redis y guarda el detalle de las peticiones lentas y fallidas.
- Panel de sistemas con p50/p95/p99, tráfico, sesiones activas, bloqueos de cuenta, eventos de seguridad y auditoría de archivos huérfanos en R2.
- 36 módulos de pruebas con pytest.