Card #5 · Modelado de base de datos
De Firestore (documentos anidados, reglas abiertas) a PostgreSQL relacional, con aislamiento real por empresa y sin un solo ENUM fijo.
Nada de ENUM de Postgres ni listas fijas con CHECK. Todo lo que era un conjunto de valores fijos en Firestore (status, prioridad, rol, moneda...) es acá una tabla de catálogo: id, code, label, sort_order. Agregar un status o una moneda nueva es un INSERT, nunca una migración de schema — justo el problema que ya sufriste antes con enums.
Esta página es un mapa de lectura rápida. Para el diagrama real, con zoom y las líneas de relación dibujadas automáticamente, copiá el contenido de docs/db/schema.dbml y pegalo en dbdiagram.io — es gratis y no requiere cuenta para visualizar.
Reemplaza las 4 colecciones de Firestore que duplicaban la misma información (platformUsers, platformWorkspaces, teamMembers, teamAccess) por 4 tablas limpias, sin duplicación.
Cuenta global de usuario — refleja la identidad de Keycloak.
Una fila por empresa/tenant.
Quién pertenece a qué workspace y con qué rol.
Nivel de acceso por módulo, una fila por (miembro, módulo). Módulo nuevo = INSERT en modules, nunca ALTER TABLE.
Directorio de clientes de cada empresa.
Cotización, precio, instalación, aprobación del cliente y estado de producción viven en una sola fila — igual que hoy viven en un solo documento de Firestore. Solo los arrays 1:muchos se volvieron tablas hijas.
Entidad central: trabajo/estimado, con precio, instalación, aprobación pública y tablero de producción todo junto.
Materiales usados, qty × precio.
Ítems del presupuesto/cotización.
Pagos recibidos contra el trabajo.
Imágenes de diseño subidas (Cloudinary).
Bitácora de notas internas.
Auditoría: cambios de estado, pagos, inventario.
Detalle detrás del total de anticipo.
Bitácora del tablero de producción.
Ítems de stock.
Ledger de entrada/salida/ajuste de stock.
Directorio de proveedores.
Órdenes de compra.
Ítems de la orden de compra.
Categorías definidas por cada empresa (reemplaza texto libre).
Plantillas que generan gastos automáticos cada mes.
Gastos normales y generados automáticamente.
Fotos/comprobantes.
Todas comparten la misma estructura: id, code, label, sort_order. Esta es la pieza central que evita los ENUMs — agregar un valor nuevo es un INSERT en la tabla correspondiente.
| Tabla | Códigos sembrados hoy |
|---|---|
| account_statuses | pending, active, blocked |
| roles | owner, admin, employee, readonly |
| modules | clients, jobs, expenses, inventory, providers, purchases, users, dashboard, reports, production, advance_control, backup |
| permission_levels | none, view, edit, delete, manage |
| currencies | USD (código ISO 4217 — agregar otra moneda es un INSERT) |
| job_statuses | quote, approved, design, production, installation, delivered, paid, cancelled |
| job_priorities | low, medium, high |
| installation_statuses | pending, confirmed, en_route, rescheduled, completed, cancelled |
| estimate_statuses | draft, sent, approved, changes_requested, rejected |
| design_statuses | pending, sent, approved, changes_requested |
| price_modes | manual, quote |
| discount_types | percent, fixed |
| production_stages | design, approval, production, ready_to_install, installation_scheduled, completed |
| advance_entry_types | material, purchase, labor, expense, installation, other |
| advance_entry_statuses | pending, purchased, paid |
| inventory_movement_types | in, out, adjustment |
| purchase_order_statuses | draft, sent, partial, received, cancelled |