Plataforma completa de gestion automatizada de archivos de decoracion virtual en OneDrive Business: sincronizacion en tiempo real, archivado programado, monitorizacion de calidad, dashboard web con SSO y alertas por email.
Gestiona el ciclo de vida completo de los archivos de decoracion virtual: desde que un colaborador sube imagenes hasta que se archivan en el historico, con monitorizacion, limpieza y reportes automaticos.
Detecta nuevas carpetas PARA_ENTREGAR via Delta Query y las copia automaticamente a IDEALISTA. Retry con backoff, copias concurrentes (5 hilos), notificacion por email a cada copia, y auto-limpieza de origenes tras X dias.
Cada ciclo (~5min) escanea carpetas PRODUCCION_DD-MM-YYYY y mueve imagenes JPG/PNG a IDEALISTA/Calidad. Elimina carpetas vacias de mas de 3 dias. Informe diario combinado por email.
Mueve archivos (cualquier extension) de sincronitzacio/RECOPILACION a IDEALISTA/CALIDAD/RECOPILACION cada ciclo. Edad minima configurable para no mover archivos en proceso de copia.
Semanal. Archiva carpetas de proyectos (_es/_it/_pt) de #PRODUCCIO con mas de 7 dias al OneDrive historico (decoraciovirtualhistoric). Copia recursiva cross-drive + eliminacion de origen.
Semanal. Archiva carpetas PRODUCCION_* con mas de 210 dias de IDEALISTA/CALIDAD al historico. Excluye carpetas DEBUG y RECOPILACION. Cross-drive a cuenta historica.
Semanal. Archiva archivos de IDEALISTA/CALIDAD/RECOPILACION con mas de 30 dias al historico, organizados por fecha (YYYY-MM-DD). Batch de 1000 archivos, borra origen tras copia.
Diario. Elimina carpetas de proyectos en UPLOADS que ya fueron copiados y tienen mas de 30 dias. Recorre toda la estructura colaborador/pais/proyecto.
Detecta tours 360 nuevos o modificados en /360/IDEALISTA via Delta Query. Descarga de OneDrive y sube al bucket S3 (tour360.yaencontre.com) con boto3. Thread separado para no bloquear el sync de uploads. Soporta re-subida selectiva (solo archivos modificados).
Servicio Windows con webapp Flask, reverse proxy Nginx con HTTPS, autenticacion Azure AD SSO, y conexion a OneDrive via Microsoft Graph API.
La funcionalidad principal del sistema. Detecta subidas de colaboradores externos y las replica automaticamente en la estructura de produccion.
FLUJO SYNC UPLOADS 1. detect_new_uploads() Delta Query a /sincronitzacio/UPLOADS Busca cambios en carpetas PARA_ENTREGAR con contenido Parsea: UPLOADS/{colaborador}/PAISES/{pais}/{proyecto}/PARA_ENTREGAR → INSERT INTO pending_projects (attempts=0) 2. process_pending_projects() [ThreadPoolExecutor, 5 hilos] Espera wait_minutes (10 min) desde deteccion Para cada proyecto pendiente: → merge_copy_folder() PARA_ENTREGAR → IDEALISTA/{pais}/{proyecto} Crea carpeta destino si no existe Copia archivos con replace si origen es mas reciente Preserva archivos solo-destino → OK: INSERT INTO processed_projects (COPIED/OVERWRITTEN) send_copy_notification() email con lista de archivos → FAIL: attempts++ → retry (max 3) → si agotado: FAILED 3. cleanup_copied_sources() Elimina origen de proyectos copiados con >30 dias Marca source_deleted=1 en processed_projects
Usa delta de Graph API para detectar solo cambios incrementales. Mantiene el deltaLink persistente en sync_state. Si expira (410 Gone), hace rescan con cutoff configurable.
ThreadPoolExecutor con max_concurrent_copies configurable (default 5). Lock global para stats thread-safe. Timeout por copia de 1800s con polling adaptativo.
No sobreescribe todo a ciegas. Compara timestamps: solo reemplaza si origen es mas reciente. Mantiene archivos que solo existen en destino. Crea carpetas destino si no existen.
Se ejecutan en cada ciclo del scheduler (~5 min). Mueven archivos de las carpetas de entrada a la estructura de produccion.
Origen: /sincronitzacio/CALIDAD/PRODUCCION_*/IA/*.{jpg,jpeg,png}
Destino: /IDEALISTA/Calidad/{PRODUCCION_*}/
Usa move_item (PATCH) para mover en la misma unidad (mas eficiente que copy+delete).
Sobreescribe si ya existe en destino (conflictBehavior: replace).
Elimina carpetas PRODUCCION_* con mas de max_folder_age_days dias.
Edad minima de archivo configurable para evitar mover archivos en proceso de escritura.
Origen: /sincronitzacio/RECOPILACION/* (cualquier extension)
Destino: /IDEALISTA/CALIDAD/RECOPILACION/
Mueve todos los archivos con edad superior a min_file_age_minutes (default 1 min).
Sin filtro de extension. Usa move_item (PATCH) con replace.
Registra ejecucion con estadisticas en task_executions solo si hay actividad.
Informe diario combinado: A la hora configurada en report_time + 5min, se envia un email con el resumen del dia de ambos monitors: archivos movidos, errores y ciclos ejecutados. Los destinatarios se configuran de forma independiente.
Se ejecutan automaticamente en el dia y hora configurados. Tambien se pueden lanzar on-demand desde el dashboard (solo admins).
| Tarea | Origen | Destino | Umbral | Cuenta destino |
|---|---|---|---|---|
| Archivo Produccion | #PRODUCCIO/{colab}/*_{es,it,pt} |
DecoracioVirtualHistoric/#PRODUCCIO/{colab} |
7 dias — diario 03:00 | decoraciovirtualhistoric@ |
| Archivo Calidad | IDEALISTA/CALIDAD/PRODUCCION_* |
DecoracioVirtualHistoric/IDEALISTA/CALIDAD |
210 dias — diario 01:00 | decoraciovirtualhistoric@ |
| Archivo Recopilacion | IDEALISTA/CALIDAD/RECOPILACION/* |
DecoracioVirtualHistoric/.../RECOPILACION/YYYY-MM-DD |
30 dias — diario 02:00 | decoraciovirtualhistoric@ |
| Limpieza UPLOADS | UPLOADS/{colab}/PAISES/{pais}/{proy} |
Se eliminan | 30 dias — semanal | — |
Las tareas de archivo usan cross-drive copy: copian de la cuenta de trabajo (decoraciovirtual@) a la cuenta historica (decoraciovirtualhistoric@) via Graph API, resolviendo el drive ID de destino dinamicamente. Tras la copia exitosa, eliminan el origen.
Cada ejecucion envia un email de reporte inmediato con estadisticas.
El Archivo Produccion desciende a subcarpetas de colaborador (#PRODUCCIO/{colaborador}/{proyecto}) replicando la estructura en destino.
Accesible via HTTPS con Azure AD SSO. Roles User y Admin. Dark theme responsive.
Vista general con 7 cards: estado de cada tarea, ultimo ciclo, resumen de hoy (copiados/errores/pendientes). Indicador de scheduler activo/detenido.
Estadisticas del dia, cola de pendientes con intentos y errores, busqueda AJAX con filtros (estado, fechas, texto) y paginacion de 20 registros. Boton reintentar en proyectos fallidos.
Cards con estadisticas de Calidad y Recopilacion: movidos/errores hoy, ultimo ciclo. Auto-refresh cada 60s. Gear icon para config inline.
3 cards (Produccion, Calidad, Recopilacion) con historial de las 20 ultimas ejecuciones. Boton "Ejecutar" on-demand (solo admin). Gear icon para schedule/umbral.
Card con historial de ejecuciones de cleanup. Boton on-demand para admin. Eliminados/omitidos/errores por ejecucion.
Estadisticas del dia (subidos/errores), tours pendientes, busqueda AJAX con filtros y paginacion. Botones reintentar (FAILED) y re-subir selectivo (UPLOADED: solo archivos modificados).
Solo admin. Visor de logs SQLite con filtros por nivel (INFO/WARNING/ERROR), modulo, rango de fechas y texto libre. Paginacion de 200 registros. Purga manual configurable.
Solo admin. Cards para: Notificaciones, Reporte diario (SMTP, destinatarios), S3 Sync, Alertas (umbrales), Mantenimiento DB, Sesion. Guardado instantaneo con validacion server-side.
Cada card de tarea tiene un icono ⚙ que abre un modal de settings inline
donde el admin puede cambiar configuracion especifica (intervalos, umbrales, dias, destinatarios email) sin necesidad de acceder al servidor.
Los cambios se guardan en app-config.json y el scheduler los recoge en el siguiente ciclo.
Todos los emails son HTML con estadisticas visuales. Destinatarios configurables por tipo. SMTP interno sin autenticacion.
| Tipo | Cuando | Contenido | Destinatarios |
|---|---|---|---|
| Notificacion por copia | Inmediato tras cada sync exitoso | Proyecto copiado: colaborador, pais, archivos PARA_ENTREGAR con tamanos | notification.email_to |
| Reporte diario sync | A report_time (20:00) |
Resumen del dia: detectados, copiados, errores, pendientes + detalle por proyecto | sync.email_to o reporting.email_to |
| Reporte diario monitors | A report_time + 5min |
Calidad + Recopilacion: movidos, errores, ciclos del dia | calidad.email_to o reporting.email_to |
| Reporte de tarea | Inmediato tras archive/cleanup | Archivados/eliminados/errores con stat cards | {tarea}.email_to o reporting.email_to |
| Alerta de errores | Cuando se supera umbral (max 1/dia/tipo) | Tipo de error, conteo, detalle de proyectos fallidos | alerts.email_to o reporting.email_to |
| Notificacion S3 | Inmediato tras cada tour subido a S3 | Tour subido: nombre, archivos, tamano total, duracion | s3_sync.email_to |
Comprueba umbrales cada ciclo del scheduler. Solo alerta por errores definitivos (post-retry). Maximo una alerta por tipo y dia.
Cuenta proyectos FAILED hoy (agotaron reintentos). Tambien detecta pendientes con 2+ intentos fallidos. Umbral: 5/dia.
Cuenta ciclos consecutivos con excepcion no controlada. Si el scheduler falla 3 veces seguidas, algo va muy mal. Umbral: 3.
Cuenta ejecuciones con estado ERROR hoy por tarea (archive, cleanup, recopilacion). Umbral: 2/tarea/dia.
Cuenta archivos fallidos acumulados en el dia para calidad y recopilacion_monitor. Umbral: 10 archivos/dia.
Single Sign-On con Microsoft Entra ID. Dos niveles de acceso basados en roles del App Registration.
FLUJO DE LOGIN 1. Usuario accede a https://decomanager.sys.idealista 2. @login_required redirige a /auth/login 3. MSAL genera authorization URL → redirige a Azure AD 4. Usuario se autentica con credenciales corporativas 5. Azure AD callback a /auth/callback con auth code 6. MSAL adquiere token → extrae id_token_claims → name, email, roles[], oid 7. Sesion Flask con expiracion configurable (12h default) ROLES User → Dashboard, Sync, Monitors, Archivo, Limpieza (solo lectura) Admin → Todo lo anterior + Settings, Ejecutar on-demand, Gear icons
Base de datos ligera, sin servidor. WAL mode para lecturas concurrentes, autocommit para evitar locks entre threads.
| Tabla | Proposito | Registros tipicos |
|---|---|---|
sync_state |
Key-value para estado persistente: delta_link, alertas enviadas, errores consecutivos | ~10 claves |
pending_projects |
Cola de proyectos detectados esperando ser copiados. Retry counter + last_error | 0-20 (transitorio) |
processed_projects |
Log de proyectos procesados: COPIED/FAILED/OVERWRITTEN/SIMULATED | Cientos/dia en pico |
task_executions |
Historial de todas las ejecuciones de tareas con stats y estado | Varios por dia |
task_items |
Items individuales de sync (para detalle de notificacion) | Purgado cada 30 dias |
daily_reports |
Registro de reportes enviados por dia y tipo (sync, monitors, s3_sync) | 3/dia |
s3_pending_tours |
Cola de tours detectados esperando subida a S3. Incluye since_dt para re-subida selectiva |
0-10 (transitorio) |
s3_processed_tours |
Historial de tours subidos a S3: UPLOADED/FAILED/SIMULATED. files_count, total_bytes | Decenas/semana |
Base de datos de logs: Ademas de la DB principal, existe logs/logs.db (SQLite separada) que recibe todos los logs del servicio via SQLiteLogHandler. Escritura en buffer (20 registros o 5s) para no impactar rendimiento. Accesible desde el panel web (solo admin) con filtros por modulo, nivel y fecha.
Mantenimiento automatico: El scheduler purga registros antiguos periodicamente. Procesados se retienen 30 dias, fallidos 180 dias. Intervalo de purga configurable (default 24h). Migraciones: Auto-migracion al arrancar. Detecta esquema actual y aplica cambios incrementales (v2: status SIMULATED, v3: source_deleted, v4: report_type).
Todas las operaciones sobre OneDrive Business se realizan via Microsoft Graph REST API v1.0 con autenticacion por certificado X.509 desde el almacen de Windows.
| Operacion | Metodo Graph | Uso |
|---|---|---|
get_user_drive_id(email) |
GET /users/{email}/drives | Resolver drive ID de cualquier cuenta OneDrive |
invoke_delta() |
GET /drives/{id}/root/delta | Detectar cambios incrementales en UPLOADS |
list_children() |
GET /drives/{id}/items/{id}/children | Listar contenido de carpetas (paginado) |
copy_item() |
POST /drives/{id}/items/{id}/copy | Copia asincrona con polling (cross-drive) |
move_item() |
PATCH /drives/{id}/items/{id} | Mover dentro del mismo drive (monitors) |
delete_item() |
DELETE /drives/{id}/items/{id} | Eliminar archivos/carpetas (ignora 404) |
create_folder() |
POST /drives/{id}/items/{id}/children | Crear carpetas con conflict handling |
merge_copy_folder() |
Combinacion de operaciones | Copia inteligente: solo reemplaza si mas reciente |
copy_folder_recursive() |
Combinacion de operaciones | Copia recursiva del arbol completo (archive) |
Autenticacion: MSAL con certificado X.509 almacenado en el Windows Certificate Store.
El thumbprint se configura en graph.certificate_thumbprint.
Tambien soporta certificados PEM/PFX (modo certificate_file) y client secret para desarrollo.
Token cacheado en memoria con renovacion automatica.
Dos servicios Windows (WinSW): uno para la aplicacion Python y otro para Nginx como reverse proxy HTTPS.
Servicio WinSW que ejecuta run_webapp.py con Waitress (4 threads) en puerto 8085. Auto-restart on failure. Logs rolling 10MB.
Servicio WinSW para Nginx. SSL/HTTP2 en :443, redirect :80→:443. HSTS, X-Frame-Options, X-Content-Type-Options. Static cache 30 dias.
deploy.ps1: git pull master, pip install, restart servicio, verificacion. Un solo comando para actualizar produccion.
ESTRUCTURA DE ARCHIVOS decoracio-virtual-manager/ ├── config/ │ ├── app-config.json Configuracion runtime │ └── app-config.example.json Template ├── db/ │ ├── database.py Conexion + migraciones │ └── schema.sql Esquema DDL ├── services/ │ ├── graph_auth.py MSAL autenticacion │ ├── graph_onedrive.py Graph API operations │ ├── scheduler.py Orquestador daemon │ ├── sync_processor.py Core sync logic │ ├── calidad_monitor.py Monitor imagenes │ ├── recopilacion_monitor.py Monitor archivos │ ├── archive_projects.py Archivado diario (nested collaborators) │ ├── archive_recopilacion.py Archivado recopilacion │ ├── cleanup_uploads.py Limpieza UPLOADS │ ├── s3_sync_processor.py Deteccion + subida tours 360 │ ├── s3_client.py Wrapper boto3 con filtro since_dt │ ├── email_reporter.py 6 tipos de email │ └── error_alerts.py Alertas por umbral ├── db/ │ ├── database.py Conexion + migraciones │ ├── schema.sql Esquema DDL │ └── log_db.py SQLiteLogHandler + query_logs() ├── logs/ │ ├── dvm.log Log rotativo aplicacion │ └── logs.db SQLite logs (separada de la DB principal) ├── webapp/ │ ├── app.py Flask factory │ ├── routes/ 9 blueprints (incl. s3_sync, logs) │ ├── templates/ 12 templates Jinja2 │ └── utils/auth.py Decorators + helpers (admin_required) ├── run_webapp.py Entry point ├── requirements.txt 7 dependencias ├── deploy.ps1 Script de despliegue ├── nginx.conf Reverse proxy config └── *-service.xml Definiciones WinSW
Un unico archivo app-config.json gobierna todo el comportamiento. Editable desde la web (admins) o directamente en disco. El scheduler recarga cada ciclo.
Polling interval, wait minutes, max attempts, concurrent copies, copy timeout, auto-delete days, email_to
Enabled, max folder age, min file age, extensions, email_to para informe diario
Enabled, schedule day/time, days threshold, destination email/paths, exclusions, email_to
Enabled, schedule day/time, days threshold, email_to
Enabled, sync/task/monitor/scheduler thresholds, email_to
Report time, SMTP config, email_from, email_to default + overrides por tipo
Bucket name, region, wait minutes, cutoff hours, max attempts, concurrent uploads, notificacion email. Credenciales S3 solo en JSON (no en UI)
Redirect URI, session hours. Graph: tenant, client, cert thumbprint
Retention days (procesados/fallidos), purge interval, log_retention_days
Lo que empezo como 3 scripts independientes se ha convertido en un servicio completo con interfaz web.
| Scripts PowerShell (antes) | Decoracio Virtual Manager (ahora) | |
|---|---|---|
| Ejecucion | Task Scheduler, semanal | Servicio 24/7, polling cada 5 min |
| Deteccion | No existia (solo archivado) | Delta Query en tiempo real |
| Sync UPLOADS | No existia | Deteccion + copia + notificacion + auto-limpieza |
| Visibilidad | Logs en disco + email diario | Dashboard web en tiempo real + 5 tipos de email |
| Configuracion | Archivo .psd1 en servidor | UI web con validacion + hot-reload |
| Autenticacion | Certificado para Graph (solo) | Certificado + Azure AD SSO para web |
| Alertas | No existian | Umbrales configurables, 1 alerta/tipo/dia |
| On-demand | Ejecucion manual del script | Boton en web (admin) |
| Base de datos | No existia (estado en logs) | SQLite con historial, retry queue, stats |
| Monitor de archivos | Calidad semanal + Recopilacion semanal | Cada 5 min (alta frecuencia) + archivado diario |
| Tours 360 a S3 | No existia | S3 Sync 360: deteccion Delta Query + upload boto3 + re-subida selectiva |
| Logs | Solo ficheros en disco | SQLite logs.db con visor web filtrable (modulo, nivel, fecha) |