Skip to content

Repository files navigation

🇬🇧 Read in English

OpenJornada API

Backend API para el sistema OpenJornada, construido con FastAPI y MongoDB.

🚀 Características

  • 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)
  • Gestión de Ausencias y Vacaciones: Módulo opcional por empresa (absence_management_enabled) con política configurable (días/año, cómputo laborable o natural, tipos de ausencia, antelación, medio día/horas, periodos bloqueados, máximo de solapamiento), solicitud y aprobación de un nivel con auditoría y transición atómica, saldo calculado al vuelo, justificantes en GridFS, validación (solapamientos, blackout, saldo) e integración con el informe mensual (los días aprobados no cuentan como jornada faltante). Endpoints /api/absences y /api/absence-policies

📋 Requisitos

  • Python 3.11+
  • MongoDB 7.0+
  • Docker y Docker Compose (recomendado)
  • Dependencias adicionales para informes: openpyxl 3.1.2, reportlab 4.1.0

🛠️ Instalación

Con Docker (Recomendado)

# 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

Sin Docker

# 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.main

🔧 Configuración

Variables de Entorno

Crea un archivo .env basado en .env.example:

# API Configuration
API_PORT=8000
API_HOST=0.0.0.0
DEBUG=True

# Security
# SECRET_KEY es OBLIGATORIA: la API no arranca si falta o está vacía.
SECRET_KEY=your_secret_key_here
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30

# Rate limiting del login (POST /api/token)
LOGIN_RATE_LIMIT=5/minute

# CORS: orígenes permitidos separados por comas (nunca "*" con credenciales)
CORS_ALLOWED_ORIGINS=http://localhost:5173,http://localhost:3000,http://localhost:3001

# 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=0

Stripe es opcional; sin claves la API funciona sin límites.

👥 Gestión de Usuarios API

La 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>

Ejemplo: Crear usuario admin

python -m api.manage_api_users create admin admin@example.com admin

📚 Documentación API

Una vez que la API esté corriendo, puedes acceder a:

🏗️ Estructura del Proyecto

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

🔐 Sistema de Permisos

Roles Disponibles

  • 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

Permisos por Rol

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

📊 Colecciones de MongoDB

Workers

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

TimeRecords

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

Companies

Empresas del sistema:

  • Campos: name, created_at, updated_at
  • Soft delete: deleted_at, deleted_by

APIUsers

Usuarios administradores:

  • Campos: username, email, hashed_password, role, is_active
  • Roles: admin, tracker, inspector

Incidents

Incidencias reportadas por trabajadores:

  • Campos: worker_id, description, status
  • Estados: pending, in_review, resolved

MonthlySignatures

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

Settings

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

SmsLogs

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)

Backups

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

🔄 Flujos Principales

Registro de Jornada

  1. Trabajador se autentica con email/password
  2. Sistema valida credenciales
  3. Verifica empresa asociada
  4. Comprueba último registro
  5. Si último es "exit" o no existe → crea "entry"
  6. Si último es "entry" → crea "exit" con duración
  7. Validación crítica: No permite entrada simultánea en múltiples empresas

Recuperación de Contraseña

  1. Trabajador solicita reset vía email
  2. Sistema genera token seguro (válido 1 hora)
  3. Envía email con enlace de recuperación
  4. Trabajador usa token para establecer nueva contraseña
  5. Rate limit: máximo 3 intentos por hora

📝 Endpoints Principales

Autenticación

  • POST /api/token - Obtener JWT token

Empresas (Admin only)

  • GET /api/companies/ - Listar empresas
  • POST /api/companies/ - Crear empresa
  • PATCH /api/companies/{id} - Actualizar empresa
  • DELETE /api/companies/{id} - Eliminar empresa

Trabajadores (Admin)

  • GET /api/workers/ - Listar trabajadores
  • POST /api/workers/ - Crear trabajador
  • PUT /api/workers/{id} - Actualizar trabajador
  • DELETE /api/workers/{id} - Eliminar trabajador

Trabajadores (Público)

  • POST /api/workers/my-companies - Obtener empresas del trabajador
  • PATCH /api/workers/change-password - Cambiar contraseña
  • POST /api/workers/forgot-password - Solicitar reset de contraseña
  • POST /api/workers/reset-password - Restablecer contraseña

Registros de Jornada

  • 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

Incidencias

  • POST /api/incidents/ - Crear incidencia (público con auth)
  • GET /api/incidents/ - Listar incidencias (admin)
  • PATCH /api/incidents/{id} - Actualizar incidencia (admin)

Informes y Exportación (Admin/Inspector)

  • GET /api/reports/monthly - Resumen mensual de empresa
  • GET /api/reports/monthly/worker/{worker_id} - Resumen mensual de trabajador
  • GET /api/reports/overtime - Informe de horas extra
  • GET /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

Informes del Trabajador (Auth por request)

  • POST /api/reports/worker/monthly - Ver resumen mensual propio
  • POST /api/reports/worker/monthly/sign - Firmar registros mensuales
  • POST /api/reports/worker/signatures/status - Estado de firmas (últimos 12 meses)

Configuración (Admin only)

  • GET /api/settings/ - Obtener configuración
  • PATCH /api/settings/ - Actualizar configuración

Backups (Admin only)

  • GET /api/backups/ - Listar backups
  • POST /api/backups/trigger - Crear backup manual
  • GET /api/backups/{id} - Detalle de backup
  • DELETE /api/backups/{id} - Eliminar backup
  • POST /api/backups/{id}/restore - Restaurar desde backup
  • GET /api/backups/{id}/download-url - URL de descarga
  • POST /api/backups/test-connection - Probar conexión storage
  • GET /api/backups/schedule/status - Estado del scheduler

SMS (Admin only)

  • GET /api/sms/credits - Créditos y estado del proveedor SMS
  • GET /api/sms/config - Obtener configuración SMS de la empresa
  • PATCH /api/sms/config - Actualizar configuración SMS
  • GET /api/sms/template - Obtener plantilla de mensaje SMS
  • PUT /api/sms/template - Actualizar plantilla
  • POST /api/sms/template/reset - Restaurar plantilla por defecto
  • GET /api/sms/stats - Estadísticas de envío
  • GET /api/sms/history - Historial de SMS enviados
  • DELETE /api/sms/history - Limpiar historial
  • POST /api/workers/{id}/sms/send - Enviar SMS manual a trabajador

Políticas de Ausencias (Admin only)

  • GET /api/absence-policies/{company_id} - Obtener la política de ausencias de la empresa
  • PUT /api/absence-policies/{company_id} - Crear/actualizar la política y su catálogo de tipos
  • GET /api/absence-policies/{company_id}/types - Catálogo de tipos de la empresa

Ausencias y Vacaciones (Admin)

  • GET /api/absences/ - Listar solicitudes (filtros: company_id obligatorio, status, worker_id, start_date, end_date)
  • GET /api/absences/{id} - Detalle (incluye validation_errors si está pendiente)
  • PATCH /api/absences/{id} - Aprobar/rechazar
  • GET /api/absences/calendar - Calendario de equipo (vista admin)
  • GET /api/absences/attachments/{attachment_id} - Descargar justificante

Ausencias y Vacaciones (Trabajador - Auth por request)

  • POST /api/absences/ - Crear solicitud
  • POST /api/absences/me - Listar solicitudes propias
  • POST /api/absences/me/balance - Saldo de vacaciones
  • POST /api/absences/me/{id}/cancel - Cancelar (solo si pendiente)
  • POST /api/absences/me/calendar - Calendario de equipo (sin tipo/motivo)
  • POST /api/absences/me/types - Catálogo de tipos de la empresa
  • POST /api/absences/attachments - Subir justificante (multipart) → attachment_id

💾 Sistema de Backups

La API incluye un sistema completo de copias de seguridad de MongoDB:

Características

  • 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

Configuración desde Admin UI

  1. Ir a Settings → Backups
  2. Activar backups programados
  3. Configurar frecuencia (diario/semanal/mensual)
  4. Seleccionar hora UTC
  5. Elegir backend de almacenamiento
  6. Configurar credenciales del storage
  7. Probar conexión
  8. Guardar

Configuración Docker para Backups Locales

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/backups

Nota sobre Réplicas

Para backups locales, usar API_REPLICAS=1 para evitar conflictos. Con S3/SFTP se pueden usar múltiples réplicas.

📱 Sistema de Recordatorios SMS

La API incluye un sistema de recordatorios por SMS para trabajadores que olvidan registrar la salida:

Características

  • 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

Configuración

  1. Configurar variables de entorno SMS (ver sección Variables de Entorno)
  2. Ir a Admin → Recordatorios SMS
  3. Configurar horario activo y frecuencia de recordatorios
  4. Personalizar la plantilla del mensaje
  5. Activar el servicio

📊 Sistema de Informes y Exportación

La API incluye un sistema completo de informes para cumplimiento laboral:

Informes Disponibles

  • 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)

Formatos de Exportación

Formato Características
CSV Separador ;, codificación UTF-8 con BOM (compatibilidad Excel español)
XLSX 2 hojas: Resumen + Detalle Diario, estilos profesionales
PDF A4 apaisado, tablas formateadas, pie de cumplimiento legal

Integridad y Cumplimiento

  • Hash SHA-256 calculado y almacenado (campo integrity_hash) en el momento de crear cada registro de tiempo. GET /api/reports/integrity/{record_id} recalcula el hash a partir de los campos actuales y lo compara con el almacenado, devolviendo un status explícito:
    • verified: el registro no ha sido alterado desde su creación.
    • tampered: un campo hasheado (worker_id, company_id, type, timestamp, duration_minutes, created_at) fue modificado directamente en la base de datos sin pasar por el flujo de corrección auditado.
    • legacy: el registro es anterior a esta capability y no tiene integrity_hash almacenado (no implica manipulación). Puede poblarse con python -m api.manage_integrity backfill.
    • Las correcciones aprobadas vía change-request recalculan el hash automáticamente, así que un cambio legítimo y auditado no se marca como manipulación.
    • Importante: esto es evidencia de manipulación para terceros sin acceso a la base de datos (auditores, trabajadores, la nube gestionada), no una garantía criptográfica frente a quien administra el propio servidor/base de datos (autoalojado).
  • 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."

Zona Horaria

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.

🧪 Testing

Tests de Integración

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/ -v

Tests Disponibles

Tests 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 -v

Para documentación completa de testing, ver docs/TESTING.md.

Con Docker

# Ejecutar tests en contenedor
docker-compose exec api pytest tests/integration/ -v

Scripts de Verificación Manual

La 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.py

Para más información sobre los scripts disponibles, consulta scripts/README.md.

📖 Documentación Adicional

Consulta la carpeta docs/ para más información:

🐛 Debugging

Ver logs en tiempo real

docker-compose logs -f api

Acceder al contenedor

docker-compose exec api bash

Verificar conexión a MongoDB

docker-compose exec mongodb mongosh

🐳 Imagen Docker

La 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.0

Plataformas soportadas: linux/amd64, linux/arm64

🚀 Despliegue en Producción

Para despliegue en producción:

  1. Usa docker-compose.prod.yml
  2. Configura variables de entorno seguras
  3. Usa un SECRET_KEY fuerte
  4. Configura SMTP real
  5. Deshabilita DEBUG
  6. Configura CORS apropiadamente
  7. Usa HTTPS
  8. Configura backups de MongoDB

📄 Licencia

GNU Affero General Public License v3.0 (AGPL-3.0) - Ver archivo LICENSE en la raíz del proyecto.

👨‍💻 Autor

OpenJornada es un proyecto desarrollado por HappyAndroids.

🤝 Contribuciones

Las contribuciones son bienvenidas. Por favor abre un issue antes de hacer cambios grandes.

🔗 Enlaces


Un proyecto de HappyAndroids | OpenJornada

About

🕐 API REST para sistema de registro de jornada laboral. FastAPI + MongoDB. Open source (AGPL-3.0)

Topics

Resources

Contributing

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages