Backend API para el sistema OpenJornada, construido con FastAPI y MongoDB.
- FastAPI: Framework moderno y rápido para construir APIs con Python
- MongoDB + Motor: Base de datos NoSQL con driver async para máximo rendimiento
- Autenticación JWT: Para usuarios administradores y trackers
- Autenticación por Request: Para trabajadores que registran jornada
- Soft Delete: Eliminación lógica para mantener integridad de datos
- Sistema de Permisos: Control de acceso granular basado en roles
- Validación Pydantic: Validación de datos robusta
- Zona Horaria Automática: Manejo correcto de zonas horarias en registros
- Sistema de Empresas: Soporte multi-empresa con trabajadores asociados
- Envío de Emails: Recuperación de contraseña vía SMTP
- Gestión de Incidencias: Sistema completo de reportes y seguimiento
- Sistema de Backups: Copias de seguridad automáticas con múltiples backends (S3, SFTP, Local)
- Informes y Exportación: Informes mensuales, horas extra y exportación a CSV/XLSX/PDF
- Acceso Inspección de Trabajo: Endpoints para acceso conforme al art. 34.9 ET y RD-Ley 8/2019
- Verificación de Integridad: Hash SHA-256 para registros y exportaciones
- Firma Mensual de Trabajadores: Firma digital de registros mensuales por el trabajador
- Recordatorios SMS: Envío automático de SMS a trabajadores que olvidan fichar la salida (proveedor LabsMobile)
- Python 3.11+
- MongoDB 7.0+
- Docker y Docker Compose (recomendado)
- Dependencias adicionales para informes: openpyxl 3.1.2, reportlab 4.1.0
# Clonar el repositorio
cd openjornada-api
# Configurar variables de entorno
cp .env.example .env
# Editar .env con tus configuraciones
# Iniciar servicios
docker-compose up -d
# Ver logs
docker-compose logs -f api# Instalar dependencias
pip install -r requirements.txt
# Configurar variables de entorno
cp .env.example .env
# Editar .env con tus configuraciones
# Asegurarse de que MongoDB está corriendo
# mongodb://localhost:27017
# Iniciar la API
python -m api.mainCrea un archivo .env basado en .env.example:
# API Configuration
API_PORT=8000
API_HOST=0.0.0.0
DEBUG=True
# Security
SECRET_KEY=your_secret_key_here
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30
# Database
MONGO_URL=mongodb://mongodb:27017
DB_NAME=time_tracking_db
# SMTP Configuration
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your_email@example.com
SMTP_PASSWORD=your_password
SMTP_FROM_EMAIL=noreply@example.com
SMTP_FROM_NAME=OpenJornada
EMAIL_APP_NAME=OpenJornada
# SMS Configuration (LabsMobile)
# SMS_ENABLED=false
# SMS_PROVIDER=labsmobile
# SMS_LABSMOBILE_API_TOKEN= # Base64(username:api_key)
# SMS_SENDER_ID=OpenJornada
# SMS_UNLIMITED_BALANCE=0La API incluye un script CLI para gestionar usuarios administradores:
# Crear usuario
python -m api.manage_api_users create <username> <email> <role>
# Roles: admin, tracker
# Listar usuarios
python -m api.manage_api_users list
# Ver detalles de usuario
python -m api.manage_api_users show <username>
# Cambiar rol
python -m api.manage_api_users role <username> <new_role>
# Cambiar contraseña
python -m api.manage_api_users password <username>
# Activar/desactivar usuario
python -m api.manage_api_users toggle <username>
# Eliminar usuario
python -m api.manage_api_users delete <username>python -m api.manage_api_users create admin admin@example.com adminUna vez que la API esté corriendo, puedes acceder a:
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
openjornada-api/
├── api/
│ ├── auth/ # Autenticación y permisos
│ ├── models/ # Modelos Pydantic
│ │ ├── reports.py # Modelos de informes y exportación
│ │ ├── sms.py # Modelos SMS (logs, config, plantillas)
│ │ └── ...
│ ├── routers/ # Endpoints de la API
│ │ ├── reports.py # Informes, exportación e Inspección de Trabajo
│ │ ├── sms.py # Endpoints SMS
│ │ └── ...
│ ├── services/ # Servicios
│ │ ├── report_service.py # Generación de informes mensuales y horas extra
│ │ ├── export_service.py # Exportación a CSV, XLSX y PDF
│ │ ├── integrity_service.py # Verificación de integridad SHA-256
│ │ ├── sms_service.py # Servicio SMS (LabsMobile)
│ │ └── ...
│ ├── database.py # Configuración de MongoDB
│ ├── main.py # Punto de entrada de la aplicación
│ └── manage_api_users.py # CLI para gestión de usuarios
├── docker/ # Dockerfiles
├── docs/ # Documentación adicional
├── scripts/ # Scripts de verificación y utilidad
├── tests/ # Tests
│ └── unit/
│ ├── test_reports.py # Tests unitarios de informes (68 tests)
│ ├── test_sms_service.py # Tests del servicio SMS (24 tests)
│ └── test_scheduler_sms.py # Tests del scheduler SMS (17 tests)
├── requirements.txt # Dependencias Python
├── docker-compose.yml # Configuración Docker local
└── README.md # Este archivo
- admin: Acceso completo a todos los endpoints
- inspector: Acceso de solo lectura a informes y empresas (Inspección de Trabajo)
- tracker: Solo puede crear registros de tiempo
Admin:
- create_users, view_users
- create_workers, view_workers, update_workers, delete_workers
- create_time_records, view_all_time_records, view_worker_time_records
- manage_pause_types, view_pause_types
- view_change_requests, manage_change_requests, create_change_requests
- create_companies, view_companies, update_companies, delete_companies
- view_incidents, manage_incidents
- view_settings, update_settings
- view_backups, manage_backups
- view_reports, export_reports, manage_inspection
- manage_sms_config, view_sms_logs, view_sms_dashboard
Inspector:
- view_reports, export_reports, view_companies
Tracker:
- create_time_records, create_change_requests, view_pause_types
Trabajadores que registran jornada:
- Campos: first_name, last_name, email, phone_number, id_number, hashed_password
- company_ids: Array de IDs de empresas asociadas
- Soft delete: deleted_at, deleted_by
Registros de entrada/salida:
- Tipo automático basado en último registro
- Almacena UTC + hora local con zona horaria
- Campos: worker_id, company_id, company_name, type, timestamp
- Calcula duración automáticamente
Empresas del sistema:
- Campos: name, created_at, updated_at
- Soft delete: deleted_at, deleted_by
Usuarios administradores:
- Campos: username, email, hashed_password, role, is_active
- Roles: admin, tracker, inspector
Incidencias reportadas por trabajadores:
- Campos: worker_id, description, status
- Estados: pending, in_review, resolved
Firmas mensuales de trabajadores:
- Campos: worker_id, company_id, year, month, signed_at
- Índice único: (worker_id, company_id, year, month)
- Validación: Un trabajador solo puede firmar una vez por mes/empresa
Configuración global:
- contact_email: Email de contacto para soporte
- webapp_url: URL de la aplicación web
- backup_config: Configuración de backups automáticos
Registro de SMS enviados:
- Campos: worker_id, company_id, phone_number, message, status, provider_message_id, cost, reminder_number
- Estados: pending, sent, delivered, failed
- Índices: (company_id, created_at), (worker_id, time_record_entry_id, reminder_number)
Registros de copias de seguridad:
- Campos: filename, storage_path, storage_type, size_bytes, status, trigger
- Estados: in_progress, completed, failed
- Trigger: scheduled, manual, pre_restore
- Trabajador se autentica con email/password
- Sistema valida credenciales
- Verifica empresa asociada
- Comprueba último registro
- Si último es "exit" o no existe → crea "entry"
- Si último es "entry" → crea "exit" con duración
- Validación crítica: No permite entrada simultánea en múltiples empresas
- Trabajador solicita reset vía email
- Sistema genera token seguro (válido 1 hora)
- Envía email con enlace de recuperación
- Trabajador usa token para establecer nueva contraseña
- Rate limit: máximo 3 intentos por hora
POST /api/token- Obtener JWT token
GET /api/companies/- Listar empresasPOST /api/companies/- Crear empresaPATCH /api/companies/{id}- Actualizar empresaDELETE /api/companies/{id}- Eliminar empresa
GET /api/workers/- Listar trabajadoresPOST /api/workers/- Crear trabajadorPUT /api/workers/{id}- Actualizar trabajadorDELETE /api/workers/{id}- Eliminar trabajador
POST /api/workers/my-companies- Obtener empresas del trabajadorPATCH /api/workers/change-password- Cambiar contraseñaPOST /api/workers/forgot-password- Solicitar reset de contraseñaPOST /api/workers/reset-password- Restablecer contraseña
POST /api/time-records/- Crear registro (público con auth)GET /api/time-records/- Listar todos (admin)GET /api/time-records/{worker_id}/latest- Último registro
POST /api/incidents/- Crear incidencia (público con auth)GET /api/incidents/- Listar incidencias (admin)PATCH /api/incidents/{id}- Actualizar incidencia (admin)
GET /api/reports/monthly- Resumen mensual de empresaGET /api/reports/monthly/worker/{worker_id}- Resumen mensual de trabajadorGET /api/reports/overtime- Informe de horas extraGET /api/reports/export/monthly- Exportar informe mensual (CSV/XLSX/PDF)GET /api/reports/export/overtime- Exportar informe de horas extra (CSV/XLSX/PDF)GET /api/reports/integrity/{record_id}- Verificar integridad de registro
POST /api/reports/worker/monthly- Ver resumen mensual propioPOST /api/reports/worker/monthly/sign- Firmar registros mensualesPOST /api/reports/worker/signatures/status- Estado de firmas (últimos 12 meses)
GET /api/settings/- Obtener configuraciónPATCH /api/settings/- Actualizar configuración
GET /api/backups/- Listar backupsPOST /api/backups/trigger- Crear backup manualGET /api/backups/{id}- Detalle de backupDELETE /api/backups/{id}- Eliminar backupPOST /api/backups/{id}/restore- Restaurar desde backupGET /api/backups/{id}/download-url- URL de descargaPOST /api/backups/test-connection- Probar conexión storageGET /api/backups/schedule/status- Estado del scheduler
GET /api/sms/credits- Créditos y estado del proveedor SMSGET /api/sms/config- Obtener configuración SMS de la empresaPATCH /api/sms/config- Actualizar configuración SMSGET /api/sms/template- Obtener plantilla de mensaje SMSPUT /api/sms/template- Actualizar plantillaPOST /api/sms/template/reset- Restaurar plantilla por defectoGET /api/sms/stats- Estadísticas de envíoGET /api/sms/history- Historial de SMS enviadosDELETE /api/sms/history- Limpiar historialPOST /api/workers/{id}/sms/send- Enviar SMS manual a trabajador
La API incluye un sistema completo de copias de seguridad de MongoDB:
- Programación automática: Backups diarios, semanales o mensuales via APScheduler
- Múltiples backends de almacenamiento:
- S3-compatible: AWS S3, Backblaze B2, MinIO, DigitalOcean Spaces
- SFTP: Servidores con acceso SFTP
- Local: Almacenamiento en el servidor (bind mount)
- Retención configurable: Por defecto 730 días (2 años)
- Restauración segura: Backup automático pre-restore
- Credenciales encriptadas: Fernet encryption usando SECRET_KEY
- Ir a Settings → Backups
- Activar backups programados
- Configurar frecuencia (diario/semanal/mensual)
- Seleccionar hora UTC
- Elegir backend de almacenamiento
- Configurar credenciales del storage
- Probar conexión
- Guardar
Para almacenamiento local, el directorio de backups debe ser un bind mount:
# docker-compose.yml
services:
api:
volumes:
- ./backups:/app/backups# En servidor, crear directorio antes de deploy
sudo mkdir -p /opt/openjornada/backups
sudo chown 1000:1000 /opt/openjornada/backupsPara backups locales, usar API_REPLICAS=1 para evitar conflictos. Con S3/SFTP se pueden usar múltiples réplicas.
La API incluye un sistema de recordatorios por SMS para trabajadores que olvidan registrar la salida:
- Envío automático: El scheduler revisa jornadas abiertas cada 5 minutos
- Proveedor LabsMobile: Integración via API REST con autenticación HTTP Basic
- Plantilla personalizable: Etiquetas dinámicas ({%worker_name%}, {%company_name%}, {%hours_open%}, {%reminder_number%})
- Horario activo configurable: Solo envía dentro del horario definido (por defecto 08:00-23:00)
- Control de frecuencia: Primer recordatorio, intervalo entre recordatorios y máximo por día
- Opt-out por trabajador: Cada trabajador puede desactivar los SMS desde su perfil
- Credenciales encriptadas: Fernet encryption usando SECRET_KEY
- Balance ilimitado: Modo desarrollo sin consumir créditos reales
- Configurar variables de entorno SMS (ver sección Variables de Entorno)
- Ir a Admin → Recordatorios SMS
- Configurar horario activo y frecuencia de recordatorios
- Personalizar la plantilla del mensaje
- Activar el servicio
La API incluye un sistema completo de informes para cumplimiento laboral:
- Resumen Mensual por Trabajador: Detalle diario con entrada, salida, minutos trabajados, pausas y estado de sesión abierta
- Resumen Mensual por Empresa: Agrega todos los trabajadores activos con registros en el mes
- Informe de Horas Extra: Detecta trabajadores que superan las horas esperadas (8h/día por defecto)
| Formato | Características |
|---|---|
| CSV | Separador ;, codificación UTF-8 con BOM (compatibilidad Excel español) |
| XLSX | 2 hojas: Resumen + Detalle Diario, estilos profesionales |
| A4 apaisado, tablas formateadas, pie de cumplimiento legal |
- Hash SHA-256 en cada registro de tiempo (campo
integrity_hash) - Hash de exportaciones devuelto en cabecera HTTP
X-Report-Hash - Firma mensual del trabajador: El trabajador puede firmar sus registros mensuales; estado consultable (últimos 12 meses)
- Pie legal: "Generado por OpenJornada. Registro conforme al art. 34.9 ET y RD-Ley 8/2019."
Todos los timestamps se almacenan en UTC. Los informes agrupan por día natural en zona horaria local (por defecto Europe/Madrid). El parámetro timezone permite ajustar a cualquier zona IANA.
El proyecto incluye tests de integración end-to-end que validan el flujo completo:
# Instalar dependencias
pip install -r requirements.txt
# Ejecutar todos los tests
pytest
# Ejecutar con output detallado
pytest -v -s
# Ejecutar solo tests de integración
pytest tests/integration/ -vTests de Integración (tests/integration/):
| Test | Descripción |
|---|---|
test_01_create_company |
Crea empresa y verifica en BD |
test_02_create_worker |
Crea trabajador asociado |
test_03_create_entry_record |
Registra entrada |
test_04_create_exit_record |
Registra salida con duración |
test_05_create_change_request |
Crea petición de cambio |
test_06_approve_change_request |
Aprueba petición |
test_07_verify_final_state |
Verifica consistencia API ↔ BD |
test_99_cleanup |
Limpia datos de test |
Tests Unitarios (tests/unit/):
| Módulo | Tests | Descripción |
|---|---|---|
test_reports.py |
68 | IntegrityService, modelos de informes, ReportService (process_day_records, group_records_by_day), ExportService (CSV/XLSX/PDF), permisos |
test_sms_service.py |
24 | SmsService: inicialización (env, DB, fallback), envío (disabled, sin balance, éxito, fallo), reload |
test_scheduler_sms.py |
17 | Scheduler SMS: horario activo, intervalos, máx recordatorios, opt-out, sin teléfono, umbrales |
# Ejecutar tests unitarios
pytest tests/unit/ -v
# Ejecutar tests de informes específicamente
pytest tests/unit/test_reports.py -vPara documentación completa de testing, ver docs/TESTING.md.
# Ejecutar tests en contenedor
docker-compose exec api pytest tests/integration/ -vLa carpeta scripts/ contiene scripts de verificación manual:
# Verificar sistema de incidencias
python scripts/test_incidents.py
# Verificar recuperación de contraseña
python scripts/verify_password_reset.pyPara más información sobre los scripts disponibles, consulta scripts/README.md.
Consulta la carpeta docs/ para más información:
- TESTING.md - Tests de integración
- TESTING_STRATEGY.md - Estrategia de testing
- PERMISSIONS_IMPLEMENTATION.md - Sistema de permisos
- INCIDENTS_API.md - Sistema de incidencias
- PASSWORD_RESET_IMPLEMENTATION.md - Recuperación de contraseña
docker-compose logs -f apidocker-compose exec api bashdocker-compose exec mongodb mongoshLa imagen oficial está disponible en GitHub Container Registry:
# Última versión
docker pull ghcr.io/openjornada/openjornada-api:latest
# Versión específica
docker pull ghcr.io/openjornada/openjornada-api:1.0.0Plataformas soportadas: linux/amd64, linux/arm64
Para despliegue en producción:
- Usa
docker-compose.prod.yml - Configura variables de entorno seguras
- Usa un SECRET_KEY fuerte
- Configura SMTP real
- Deshabilita DEBUG
- Configura CORS apropiadamente
- Usa HTTPS
- Configura backups de MongoDB
GNU Affero General Public License v3.0 (AGPL-3.0) - Ver archivo LICENSE en la raíz del proyecto.
OpenJornada es un proyecto desarrollado por HappyAndroids.
Las contribuciones son bienvenidas. Por favor abre un issue antes de hacer cambios grandes.
- Sitio web: www.openjornada.es
- Desarrollado por: HappyAndroids
- Email: info@openjornada.es
Un proyecto de HappyAndroids | OpenJornada