Blueprint · Modelo blueprints
Blueprint · Modelo blueprints
Propósito
Blueprint es el canvas infinito (floorplan o topología) sobre el que el Map Editor coloca racks, dibuja anotaciones y traza cables. Contenedor raíz multi-tenancy: cada instancia pertenece a una Organization y nunca cruza fronteras. Soporta soft delete (papelera) mediante deleted_at; los eliminados se ocultan de listados activos sin destruir datos ni relaciones. El campo mode distingue tres usos del mismo canvas: "map" (plano libre, default), "room" (Sala: coloca Filas vía RoomRowPlacement) y "row" (Fila: coloca Racks vía BlueprintPlacement) — el motor Konva es compartido, el modo solo cambia las restricciones de colocación y la UI.
Contrato
Campos:
| Campo | Tipo | Default | Notas |
|---|---|---|---|
name | CharField(100) | — | Nombre visible |
image_path | CharField(200) | "" | Ruta relativa fondo, con namespacing <org_id>/bp{id}_{slug}_{ts}{ext} desde el fix #252 (2026-08-23) — antes era plana con el nombre de fichero del usuario, lo que permitía colisión y borrado cruzado entre organizaciones. Ver [[incident—20260823—blueprint-fondos-cross-org]] |
mode | CharField(10) | "map" | "map" (plano libre) / "room" (Sala) / "row" (Fila) |
scale | FloatField | 1.0 | Factor de escala canvas |
bg_opacity | FloatField | 1.0 | Opacidad fondo (0-1) |
show_bg | BooleanField | True | Mostrar/ocultar fondo |
routing_mode | CharField(20) | "manhattan" | Algoritmo enrutado cables |
dark_mode | BooleanField | False | Tema oscuro |
cable_spread | IntegerField | 12 | Separación cables paralelos (px) |
cable_curvature | FloatField | 1.0 | Curvatura cables |
cable_width | FloatField | 2.0 | Grosor línea cables (px) |
sort_order | IntegerField(null) | None | Orden manual en el dashboard |
organization | FK(Organization, CASCADE) | — | Tenant |
created_at | DateTimeField(auto_now_add) | — | Creación |
deleted_at | DateTimeField(null, db_index) | — | Soft-delete |
Métodos:
soft_delete()—deleted_at = timezone.now(), persiste conupdate_fields.restore()—deleted_at = None, persiste.is_deleted(property) —Truesideleted_at is not None.__str__()— devuelvename.
Meta:
- Índice compuesto
idx_bp_org_deletedsobre(organization, deleted_at)para acelerar filtrodeleted_at__isnull=True.
Borrado seguro del fondo (_remove_bg_file_if_unreferenced, task #252):
blueprints/api/blueprints.py expone _remove_bg_file_if_unreferenced(org, rel_path), usada al reemplazar fondo (update_blueprint_bg), al borrar fondo (delete_blueprint_bg) y al borrado definitivo (trash.py: permanent_delete_blueprint, empty_blueprint_trash). Solo borra un fichero si vive en el espacio de la organización actual (prefijo <org_id>/) y ningún otro Blueprint de esa organización lo referencia — con RLS activo no puede ver referencias de otras organizaciones, así que nunca borra fuera del propio espacio. El comando cleanup_blueprint_backgrounds (management command, ensayo en seco por defecto) limpia a mano los huérfanos legacy que este código no puede tocar. Detalle completo: [[incident—20260823—blueprint-fondos-cross-org]].
Clonado (clone_blueprint, task #253):
El clon conserva mode (antes se perdía, produciendo un “Mapa” vacío al clonar una Sala) y, si mode == "room", replica las RoomRowPlacement de las filas colocadas. Clonar un Blueprint en mode == "row" se rechaza con 400: compartiría los mismos racks en vez de copiarlos (los placements apuntan al mismo Rack); el clon real de una Fila vive en su propia página (clone_rack).
Dependencias entrantes
| Módulo | Archivo | Rol |
|---|---|---|
BlueprintService | blueprints/services/blueprints.py | CRUD: list, get, create, update_placement, bulk_update_placements, update_background |
AutoPlanService | blueprints/services/autoplan.py | Crea racks, placements y anotaciones desde análisis IA |
| API blueprints | blueprints/api/blueprints.py | REST: listar, crear, clonar, settings, borrar, imagen fondo |
| API trash | blueprints/api/trash.py | Papelera: listar trashed, restaurar, eliminar permanente, vaciar |
| Backup/Restore | racks/api/export/backup.py, restore.py | Exportación e importación de org |
| Search | core/api/search.py | Búsqueda global por nombre en tenant |
| Data integrity | core/tasks.py | Valida que placements no crucen fronteras de tenant |
Dependencias salientes
Organization(core.models) — FK CASCADE.BlueprintPlacement(blueprints.models) — reverseplacements; posiciona racks.MapAnnotation(blueprints.models) — reverseannotations; paredes, textos, zonas,rack_connection.RoomRowPlacement(blueprints.models) — reverserow_placements(como Sala) /placed_in_rooms(como Fila); posiciona Filas dentro de Salas.Rack(racks.models) — indirecta vía BlueprintPlacement; también referenciado enAutoPlanService.create_blueprint_entities.
Ejemplos
# Crear blueprint nuevo
bp = BlueprintService.create_blueprint(
organization=org,
data={"name": "Sala CPD-1", "routing_mode": "manhattan", "dark_mode": True}
)
# Patrón estándar (excluye papelera)
Blueprint.objects.filter(organization=org, deleted_at__isnull=True)
# Mover a papelera y restaurar
bp.soft_delete()
bp.restore()
Related
entity--blueprints--model--blueprintplacement— posición (x, y, rotation, style_props) de rack sobre el blueprint.entity--blueprints--model--mapannotation— elementos gráficos: paredes, textos, símbolos, conexiones.entity--racks--model--rack— entidad colocada vía BlueprintPlacement.concept--blueprints--map-editor— frontend canvas infinito que consume los endpoints.concept--blueprints--auto-plan— flujo IA que digitaliza imagen y puebla blueprint.concept--saas--multi-tenancy— el aislamiento por organización que el fix #252 restauró también en el filesystem.incident--20260823--blueprint-fondos-cross-org— incidente de fondos compartidos entre organizaciones y su fix.
Véase también
- [[entity—blueprints—model—blueprintplacement]]
- [[entity—blueprints—model—mapannotation]]
- [[entity—racks—model—rack]]
- [[concept—blueprints—map-editor]]
- [[concept—blueprints—auto-plan]]
- [[concept—saas—multi-tenancy]]
- [[incident—20260823—blueprint-fondos-cross-org]]