Base de datos CreaRack Pro · explicación coloquial
Base de datos CreaRack Pro · explicación coloquial
Resumen para alguien que entra al proyecto y quiere entender qué se guarda, dónde y por qué sin enterarse de cada columna. Si buscas el schema completo con FKs e índices, ve a [[crearack-tech—bd—tecnico]].
En una frase
CreaRack Pro guarda todo en una sola base de datos PostgreSQL 18. No hay Mongo, no hay Redis para datos persistentes, no hay servicios separados. Una BD, ~55 tablas, todas viviendo bajo el paraguas de una entidad raíz: la Organization (el cliente SaaS).
Por qué PostgreSQL y no otra cosa
| Razón | Detalle |
|---|---|
| Madurez | El estándar para SaaS serios. 30 años de batalla. |
| Multi-tenancy nativo | Row-Level Security (RLS) sin librerías raras. Te lo explico abajo. |
| JSONB | Campos JSON con índices = lo mejor de SQL + NoSQL. Lo usamos en model_data, management_config, encrypted_data. |
| Sin proveedor único | Si mañana hay que mudarse, PG corre en cualquier sitio (Hetzner, AWS, on-prem). |
| Equipo lo conoce | Lo que dominas es siempre mejor que lo nuevo de moda. |
La idea clave: multi-tenancy con RLS
CreaRack Pro es SaaS: un cliente NO puede ver los datos de otro cliente. Punto. Pero implementarlo bien tiene truco.
Hacemos dos capas de aislamiento que trabajan juntas:
Capa 1 · Django ORM (programador)
Cada vez que escribimos código que consulta la BD, filtramos por organización:
device = get_object_or_404(Device, id=device_id, rack__organization=org)
# ^^^^^^^^^^^^^^^^^^^^^^
# esto es OBLIGATORIO
Capa 2 · PostgreSQL RLS (la red de seguridad)
Si un programador se olvida del filtro (humanos somos humanos), PostgreSQL bloquea la consulta igualmente. Magia: cada request HTTP setea una variable de sesión (SET app.current_org_id = '123') y PG aplica políticas RLS automáticamente a 35 tablas:
USING (organization_id = current_setting('app.current_org_id')::int)
Es como tener un guardia de seguridad en la BD: aunque el programador deje la puerta abierta, el guardia mira el carnet de la organización antes de entregar la fila.
Implementado en v1.0.50 tras una auditoría de seguridad. Detalle técnico en [[crearack-tech—bd—tecnico]] § RLS.
Mapa mental: las 7 apps
CreaRack Pro tiene 7 apps Django, cada una con sus modelos. Esta es la jerarquía conceptual:
erDiagram
Organization ||--o{ User : "tiene"
Organization ||--o{ Rack : "es dueña de"
Organization ||--o{ Blueprint : "es dueña de"
Organization ||--o{ MonitoringTarget : "monitoriza"
Organization ||--o{ SignagePlayer : "controla"
Organization }o--|| Plan : "está suscrita a"
Plan }o--o{ SaaSModule : "incluye"
Rack ||--o{ Device : "contiene"
Rack }o--o{ RackGroup : "agrupado en"
Blueprint ||--o{ BlueprintPlacement : "ubica"
BlueprintPlacement }o--|| Rack : "muestra"
MonitoringTarget ||--o{ AIInsight : "genera"
AIInsight }o--o{ IncidentGroup : "agrupado en"
Y aquí qué hace cada app:
| App | Para qué sirve | Modelos clave |
|---|---|---|
| core | Multi-tenancy, usuarios, permisos, auditoría | Organization, User, Plan, SaaSModule, SystemLog, StoredCredential |
| racks | Diseñador visual de racks (Konva.js) | Rack, Device, RackGroup, Stencil, BoxCategory, ConfigBackup |
| blueprints | Mapas de infraestructura (Auto-Plan AI) | Blueprint, BlueprintPlacement, MapAnnotation, AIPrompt |
| monitoring | Observatorio de red + ITSM + CNS (Network Sentinel AI) | MonitoringTarget, AIInsight, IncidentGroup, SLAPolicy, Runbook, MaintenanceWindow |
| network | Inteligencia de vendors, MIBs, conexiones de puertos | VendorProfile, CustomMib, DeviceProfile, PortConnection |
| terminal | Scripts SSH + Local Agent (failover Sentinel) | Script, AgentInstance |
| signage | Digital Signage CMS (cartelería) | SignagePlayer, MediaAsset, Playlist, Schedule, ClientProject |
Qué tablas son “globales” (no por organización)
La regla general es todo lleva organization_id NOT NULL. Pero hay excepciones — datos del sistema que comparten todos:
| Tabla | Por qué es global |
|---|---|
core_systemlog | Logs del sistema (visibles por todos) |
core_scripttemplate | Templates de scripts pre-instalados |
racks_boxcategory | Categorías base de cajas (Server, Switch, etc.) |
racks_stencil | Stencils de fabricantes (Cisco, HP, Dell…) compartidos |
monitoring_monitoringalert | Alertas globales |
network_vendorprofile | Catálogo de vendors (Cisco, Juniper, Aruba…) |
network_signagevendoradapter | Adapters de vendors signage (Samsung MDC, LG, PJLink) |
En estas tablas, organization_id puede ser NULL (= global). El ORM hace un OR para que cada tenant vea lo suyo + lo global:
stencil = Stencil.objects.get(
Q(organization=org) | Q(organization__isnull=True),
id=stencil_id,
)
Tips para el día a día
Si quieres añadir un campo nuevo a un modelo
- Editar
<app>/models.py docker compose exec web python manage.py makemigrationsdocker compose exec web python manage.py migrate- Verificar que el campo respeta RLS (si la tabla está protegida, ver lista en [[crearack-tech—bd—tecnico]])
- Commit (el hook
bib_report_changese quejará si te lo saltas)
Si necesitas consultar la BD a pelo (debug)
Hay un usuario dani_readonly con SELECT en todas las tablas. Cuando conectas por psql directo, RLS se bypasea (no hay app.current_org_id seteado), así que ves la data de todos los tenants. Es intencional, para diagnóstico.
psql postgres://dani_readonly:PASS@crearack-prod:5432/crearack
Si quieres mirar lo de UN tenant específico
SET app.current_org_id = '123'; -- el ID del tenant
SELECT * FROM racks_rack; -- ahora solo ves los suyos
SET app.current_org_id = '0'; -- vuelves a ver todo
Backups · cómo funcionan
Dos niveles:
| Nivel | Qué cubre | Cuándo |
|---|---|---|
| pg_dump diario | Toda la BD entera (dump físico) | Cron servidor PROD, 3:00 AM |
| Backup per-tenant | ZIP con backup_data.json (14 entity types) + media uploads por organización | Huey task run_org_backups, 3:30 AM |
El segundo permite descargar el backup de UN solo cliente sin tener que hacer un restore completo. Útil para exportar/migrar.
¿Y Valkey, qué pinta?
Valkey (compatible Redis) NO guarda datos persistentes. Solo:
- Cache de queries pesadas (TTL corto)
- Broker para Huey (cola de tareas async)
- Channels backend para WebSockets (Django Channels)
Si Valkey se cae, perdemos la cola y los WebSockets pero la BD sigue intacta. Por eso no entra en backups.
Para el otro lado: la BD del workspace
CreaRack Pro y workspace tienen BDs distintas y filosofías distintas:
| Aspecto | CreaRack Pro | Workspace |
|---|---|---|
| Motor | PostgreSQL 18 | Cloudflare D1 (SQLite distribuido) |
| Ubicación | Hetzner CCX (1 nodo) | Cloudflare edge (replicado global) |
| Modelos | 55 (Django ORM) | ~25 tablas (SQL plano) |
| Multi-tenant | Sí (RLS) | No (uso interno equipo de 3) |
| Backups | pg_dump + per-tenant | Wrangler export (CF) |
Si quieres entender el workspace, ve a [[workspace-tech—bd—coloquial]] (versión coloquial) o [[workspace-tech—bd—tecnico]] (técnico).
Véase también
- [[crearack-tech—bd—tecnico]] — Schema técnico completo, FKs, índices, RLS detallado
- [[workspace-tech—bd—coloquial]] — Hermana coloquial de workspace
- [[crearack-tech—general—feature-catalog]] — Qué puede hacer CreaRack Pro
Documentation/guides/DATABASE_ADMIN_GUIDE.md— Manual operativo (en el repo)