# DATABASE-SCHEMA.md - ERP Transportistas **Version:** 1.0.0 **Fecha:** 2026-01-26 **Engine:** PostgreSQL 15+ con PostGIS **Total Schemas:** 8 especializados + heredados **Total Tablas:** ~98 propias + heredadas --- ## Resumen de Schemas | Schema | Tablas | ENUMs | DDL File | Estado | |--------|--------|-------|----------|--------| | transport | ~25 | ~10 | 01-transport-schema-ddl.sql | 100% | | fleet | ~15 | ~8 | 02-fleet-schema-ddl.sql | 100% | | tracking | ~10 | ~5 | 03-tracking-schema-ddl.sql | 100% | | fuel | ~8 | ~4 | 04-fuel-schema-ddl.sql | 100% | | maintenance | ~12 | ~6 | 05-maintenance-schema-ddl.sql | 100% | | carriers | ~8 | ~4 | 06-carriers-schema-ddl.sql | 100% | | billing | ~10 | ~5 | 07-billing-transport-ddl.sql | 100% | | compliance | ~10 | ~5 | 08-compliance-schema-ddl.sql | 100% | --- ## Schema: transport ### Descripcion Ordenes de transporte, embarques, viajes y rutas. ### Tablas Principales ```sql -- Ordenes de Transporte CREATE TABLE transport.ordenes_transporte ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES auth.tenants(id), numero VARCHAR(20) NOT NULL, cliente_id UUID NOT NULL, status transport.status_ot NOT NULL DEFAULT 'BORRADOR', fecha_solicitud TIMESTAMPTZ NOT NULL, fecha_requerida TIMESTAMPTZ, origen_id UUID NOT NULL, destino_id UUID NOT NULL, peso_kg DECIMAL(10,2), volumen_m3 DECIMAL(10,2), valor_declarado DECIMAL(12,2), instrucciones TEXT, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- Embarques (agrupacion de OTs) CREATE TABLE transport.embarques ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, numero VARCHAR(20) NOT NULL, viaje_id UUID, status transport.status_embarque NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Viajes CREATE TABLE transport.viajes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, numero VARCHAR(20) NOT NULL, unidad_id UUID NOT NULL, operador_id UUID NOT NULL, remolque_id UUID, status transport.status_viaje NOT NULL DEFAULT 'PLANEADO', fecha_salida_programada TIMESTAMPTZ, fecha_salida_real TIMESTAMPTZ, fecha_llegada_programada TIMESTAMPTZ, fecha_llegada_real TIMESTAMPTZ, km_inicial INTEGER, km_final INTEGER, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Paradas del viaje CREATE TABLE transport.paradas_viaje ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), viaje_id UUID NOT NULL REFERENCES transport.viajes(id), secuencia INTEGER NOT NULL, tipo transport.tipo_parada NOT NULL, -- ORIGEN, DESTINO, ESCALA ubicacion_id UUID NOT NULL, eta TIMESTAMPTZ, ata TIMESTAMPTZ, -- Actual Time of Arrival etd TIMESTAMPTZ, atd TIMESTAMPTZ, -- Actual Time of Departure status transport.status_parada NOT NULL ); ``` ### ENUMs ```sql CREATE TYPE transport.status_ot AS ENUM ( 'BORRADOR', 'CONFIRMADA', 'PLANEADA', 'EN_TRANSITO', 'ENTREGADA', 'FACTURADA', 'CERRADA', 'CANCELADA' ); CREATE TYPE transport.status_viaje AS ENUM ( 'PLANEADO', 'DESPACHADO', 'EN_TRANSITO', 'EN_DESTINO', 'ENTREGADO', 'CERRADO', 'CANCELADO' ); CREATE TYPE transport.tipo_parada AS ENUM ( 'ORIGEN', 'DESTINO', 'ESCALA', 'CRUCE_FRONTERA' ); ``` --- ## Schema: fleet ### Descripcion Unidades, remolques, operadores y documentos. ### Tablas Principales ```sql -- Unidades (tractoras, cajas) CREATE TABLE fleet.unidades ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, numero_economico VARCHAR(20) NOT NULL, tipo fleet.tipo_unidad NOT NULL, marca VARCHAR(50), modelo VARCHAR(50), ano INTEGER, placa VARCHAR(15), numero_serie VARCHAR(50), capacidad_kg DECIMAL(10,2), status fleet.status_unidad NOT NULL DEFAULT 'DISPONIBLE', km_actual INTEGER, proximo_servicio_km INTEGER, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Operadores CREATE TABLE fleet.operadores ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, numero_empleado VARCHAR(20) NOT NULL, nombre VARCHAR(100) NOT NULL, apellido_paterno VARCHAR(50) NOT NULL, apellido_materno VARCHAR(50), rfc VARCHAR(13), curp VARCHAR(18), licencia_federal VARCHAR(20), licencia_vencimiento DATE, status fleet.status_operador NOT NULL DEFAULT 'ACTIVO', telefono VARCHAR(15), created_at TIMESTAMPTZ DEFAULT NOW() ); -- Documentos de unidades CREATE TABLE fleet.documentos_unidades ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), unidad_id UUID NOT NULL REFERENCES fleet.unidades(id), tipo fleet.tipo_documento_unidad NOT NULL, numero VARCHAR(50), fecha_emision DATE, fecha_vencimiento DATE, archivo_url TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); ``` ### ENUMs ```sql CREATE TYPE fleet.tipo_unidad AS ENUM ( 'TRACTOCAMION', 'RABON', 'TORTON', 'CAJA_SECA', 'CAJA_REFRIGERADA', 'PLATAFORMA', 'LOWBOY', 'TANQUE' ); CREATE TYPE fleet.status_unidad AS ENUM ( 'DISPONIBLE', 'EN_VIAJE', 'EN_MANTENIMIENTO', 'FUERA_SERVICIO', 'BAJA' ); CREATE TYPE fleet.status_operador AS ENUM ( 'ACTIVO', 'EN_VIAJE', 'DESCANSO', 'VACACIONES', 'INCAPACIDAD', 'BAJA' ); ``` --- ## Schema: tracking ### Descripcion Eventos GPS, geocercas, alertas, ETA. ### Tablas Principales ```sql -- Eventos de tracking CREATE TABLE tracking.eventos ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, unidad_id UUID NOT NULL, viaje_id UUID, tipo tracking.tipo_evento NOT NULL, latitud DECIMAL(10,7) NOT NULL, longitud DECIMAL(10,7) NOT NULL, velocidad_kmh INTEGER, rumbo INTEGER, odometro INTEGER, timestamp_gps TIMESTAMPTZ NOT NULL, timestamp_server TIMESTAMPTZ DEFAULT NOW(), datos_extra JSONB ); -- Geocercas CREATE TABLE tracking.geocercas ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, nombre VARCHAR(100) NOT NULL, tipo tracking.tipo_geocerca NOT NULL, geometria GEOMETRY(POLYGON, 4326), radio_metros INTEGER, -- para circulares activa BOOLEAN DEFAULT true, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Alertas CREATE TABLE tracking.alertas ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, viaje_id UUID, unidad_id UUID, tipo tracking.tipo_alerta NOT NULL, severidad tracking.severidad_alerta NOT NULL, mensaje TEXT NOT NULL, leida BOOLEAN DEFAULT false, created_at TIMESTAMPTZ DEFAULT NOW() ); ``` --- ## Schema: fuel ### Descripcion Combustible, peajes, gastos de viaje. ### Tablas Principales ```sql -- Cargas de combustible CREATE TABLE fuel.cargas_combustible ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, viaje_id UUID, unidad_id UUID NOT NULL, operador_id UUID NOT NULL, estacion VARCHAR(100), litros DECIMAL(8,2) NOT NULL, precio_litro DECIMAL(8,4) NOT NULL, total DECIMAL(10,2) NOT NULL, odometro INTEGER, tipo_pago fuel.tipo_pago NOT NULL, numero_vale VARCHAR(30), fecha TIMESTAMPTZ NOT NULL, latitud DECIMAL(10,7), longitud DECIMAL(10,7), created_at TIMESTAMPTZ DEFAULT NOW() ); -- Control de rendimiento CREATE TABLE fuel.control_rendimiento ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), unidad_id UUID NOT NULL, periodo_inicio DATE NOT NULL, periodo_fin DATE NOT NULL, km_recorridos INTEGER NOT NULL, litros_consumidos DECIMAL(10,2) NOT NULL, rendimiento_real DECIMAL(6,2) NOT NULL, -- km/litro rendimiento_esperado DECIMAL(6,2), variacion_porcentaje DECIMAL(5,2), alerta_generada BOOLEAN DEFAULT false ); ``` --- ## Schema: compliance ### Descripcion Carta Porte CFDI 3.1, HOS, inspecciones. ### Tablas Principales ```sql -- Carta Porte CREATE TABLE compliance.cartas_porte ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, viaje_id UUID NOT NULL, tipo_cfdi compliance.tipo_cfdi NOT NULL, -- INGRESO, TRASLADO version_carta_porte VARCHAR(10) DEFAULT '3.1', uuid_cfdi UUID, folio_fiscal VARCHAR(50), fecha_timbrado TIMESTAMPTZ, status compliance.status_carta_porte NOT NULL, xml_firmado TEXT, pdf_url TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Registro HOS (Horas de Servicio) CREATE TABLE compliance.registros_hos ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, operador_id UUID NOT NULL, fecha DATE NOT NULL, horas_conduccion DECIMAL(4,2), horas_servicio DECIMAL(4,2), horas_descanso DECIMAL(4,2), status compliance.status_hos NOT NULL, notas TEXT ); ``` --- ## Extensiones Requeridas ```sql CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE EXTENSION IF NOT EXISTS "pgcrypto"; CREATE EXTENSION IF NOT EXISTS "postgis"; -- Para tracking geografico CREATE EXTENSION IF NOT EXISTS "pg_trgm"; -- Para busquedas ``` --- ## RLS (Row Level Security) Todas las tablas implementan RLS por tenant: ```sql ALTER TABLE transport.ordenes_transporte ENABLE ROW LEVEL SECURITY; CREATE POLICY tenant_isolation ON transport.ordenes_transporte USING (tenant_id = current_setting('app.tenant_id')::UUID); ``` --- ## Referencias - DDL completo: `database/ddl/` - Inventario: `orchestration/inventarios/DATABASE_INVENTORY.yml` - Entities: `ENTITIES-CATALOG.md` --- *Ultima actualizacion: 2026-01-26*