CreaRack-SL

El backup completo se crea eligiendo qué viaja: árbol de secciones y dominios (v1.74.0)

Valor para el usuario

Hasta ahora, crear un backup completo solo preguntaba por los vídeos de Signage (v1.72.0) — el resto de la organización viajaba entero, sin poder ver ni elegir qué había dentro. Desde v1.74.0, el diálogo “Full System Backup” abre un árbol con TODO lo que va a viajar, con conteos reales: las secciones del dashboard (Maps, Rows, Rooms y “No Map”, cada una desplegable para ver sus racks y cuántos equipos tiene) y los dominios completos (Monitoring, Wireless, UPS, DSM —con los vídeos como sub-opción bajo él—, Observatory/ITSM, Terminal, Cables y Catálogo). Todo viene marcado por defecto, así que el backup completo de siempre sigue siendo un solo click; desmarcar algo genera un backup parcial, que se descarga como ..._partial.zip y lo declara en su manifest para que nunca se confunda con una copia completa.

Diseñado con Edu en el grill de la mañana del 21-08. Es la primera de cuatro piezas de esta ventana del task #236 — faltan el modo “actualizar en vez de duplicar”, el modal de restauración con el mismo árbol, y un informe final claro.

Cómo usarla

  1. Admin → Backup & Restore → “Full System Backup” (botón de crear).
  2. El cliente llama a GET /api/racks/backup/full/inventory (sustituye al antiguo /estimate) y pinta el árbol en el modal backup-create-modal — secciones del dashboard con sus racks y dominios con conteos, incluido el peso de los vídeos de Signage bajo DSM.
  3. El botón “All/None” (toggleBackupTreeAll()) marca o desmarca todo de golpe; desmarcar DSM deshabilita y desmarca automáticamente el sub-selector de vídeos.
  4. Al confirmar, readBackupTreeSelection() arma {blueprint_ids, include_nomap, domains} — si todo sigue marcado, se envía selection: null (backup completo clásico, byte-compatible).
  5. POST /api/racks/backup/full/start recibe selection (además de include_signage_videos) y encola run_full_backup con ella.
  6. La tarea Huey poda la maleta con prune_backup_data() ANTES de serializar el ZIP; el manifest resultante lleva partial: true + la selección, y el fichero se nombra con el sufijo _partial.

Implementación

  • racks/api/export/backup_selection.py (nuevo, 266 LOC): build_backup_inventory(org) arma el árbol — reutiliza la regla de sección del dashboard (“un rack pertenece al mapa de su primera colocación activa; sin colocación → No Map”, la misma que pinta racks.views.index) y calcula conteos por dominio (monitoring, wireless, ups, dsm, itsm, terminal, cables, catalog). normalize_selection(payload) valida/normaliza lo que envía el cliente (None/no-dict → sin selección = completo). prune_backup_data(org, data, selection) poda data en sitio: primero los racks por sección (reutilizando filter_backup_selection() de [[feature—racks—restore-selectivo-v171]]), luego los planos no elegidos, luego las colecciones completas de los dominios desmarcados, y por último los huérfanos cruzados que deja la caída de fichas de página (cables y referencias de proyectos/players). Reglas decididas en el grill: un parcial solo lleva contenido VIVO (la papelera solo viaja en el completo); los grupos (RackGroup) y las fichas sin página asignada viajan siempre (son el pegamento).
  • racks/api/export/backup.py: write_full_backup_zip() gana el parámetro selection — si no es None, poda antes de serializar y marca manifest["partial"] = True + manifest["selection"]. El endpoint GET /backup/full/estimate se retira; GET /backup/full/inventory lo sustituye devolviendo build_backup_inventory(org) completo (los vídeos de Signage ya viajan dentro de domains.dsm). POST /backup/full/start acepta ahora {"include_signage_videos": bool, "selection": {...}} en el body.
  • racks/tasks.py: run_full_backup(job_id, org_id, include_signage_videos=False, selection=None) propaga la selección a write_full_backup_zip y añade el sufijo _partial al nombre del ZIP cuando hay selección.
  • Frontend (static/js/alpine-components.js, templates/base.html, static/css/components.css): buildBackupTree() pinta el árbol a partir del inventario (checkbox por sección/dominio, desplegable con la lista de racks); readBackupTreeSelection() lo convierte en el payload de selección; el modal nuevo backup-create-modal sustituye al antiguo backup-options-modal (solo vídeos) de [[feature—backup-restore—signage-videos-opcionales-v1-72-0]]. Cache-busting manual a alpine-components.js?v=3 en templates/base.html (footgun conocido del proyecto: JS sin hash de build).
  • i18n: 28 strings EN nuevos con su capa ES vía scripts/i18n/add_backup_tree_strings.py (patrón polib ya usado en features anteriores de esta task).
  • Tests: tests/api/test_backup_selective.py (6 casos nuevos) + 1 adaptado en tests/api/test_backup_scope.py. Área backup/restore verificada en Docker: 22 tests + mypy en verde.

Commits relacionados

  • 1b3de40d (2026-08-21) — feat(backups): motor del backup selectivo por secciones y dominios + diálogo de creación con árbol completo (task #236, ventana) - v1.74.0 (#405).

Véase también

  • [[feature—racks—restore-selectivo-v171]]
  • [[feature—backup-restore—extended-domains-v1-70-0]]
  • [[feature—backup-restore—signage-videos-opcionales-v1-72-0]]
  • [[feature—backup-restore—manifest-verificacion-v1-69-0]]
  • [[entity—racks—endpoint—backup-full-start]]
  • [[entity—racks—service—run-full-backup]]
  • [[entity—core—service—backup-service]]
  • [[crearack-tech—admin—backup-restore]]