-- ============================================================================= -- ERP TRANSPORTISTAS - Schema Fleet DDL -- ============================================================================= -- Archivo: 02-fleet-schema-ddl.sql -- Version: 1.0.0 -- Fecha: 2026-01-25 -- Descripcion: Unidades, remolques, operadores, documentos, licencias -- ============================================================================= -- ============================================================================= -- TIPOS ENUMERADOS ADICIONALES -- ============================================================================= CREATE TYPE fleet.tipo_licencia AS ENUM ( 'A', -- Motociclista 'B', -- Automovilista particular 'C', -- Chofer particular 'D', -- Chofer público pasajeros 'E', -- Chofer público carga 'F' -- Federal (SCT) ); CREATE TYPE fleet.estado_operador AS ENUM ( 'ACTIVO', 'EN_VIAJE', 'DESCANSO', 'VACACIONES', 'INCAPACIDAD', 'SUSPENDIDO', 'BAJA' ); CREATE TYPE fleet.tipo_documento AS ENUM ( 'LICENCIA', 'INE', 'CURP', 'RFC', 'NSS', 'TARJETA_CIRCULACION', 'POLIZA_SEGURO', 'VERIFICACION', 'PERMISO_SCT', 'CERTIFICADO_FISICO', 'ANTIDOPING', 'OTRO' ); -- ============================================================================= -- TABLA: unidades (Tractoras y vehículos) -- ============================================================================= CREATE TABLE fleet.unidades ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES public.tenants(id), -- Identificación numero_economico VARCHAR(20) NOT NULL, tipo fleet.tipo_unidad NOT NULL, -- Vehículo marca VARCHAR(50), modelo VARCHAR(50), anio INT, color VARCHAR(30), numero_serie VARCHAR(50), numero_motor VARCHAR(50), -- Placas placa VARCHAR(15), placa_estado VARCHAR(50), -- SCT permiso_sct VARCHAR(50), tipo_permiso_sct VARCHAR(10), configuracion_vehicular VARCHAR(10), -- C2, C3, T3S2, etc. -- Capacidades capacidad_peso_kg DECIMAL(10, 2), capacidad_volumen_m3 DECIMAL(10, 4), capacidad_pallets INT, -- Combustible tipo_combustible VARCHAR(20), -- DIESEL, GASOLINA, GAS rendimiento_km_litro DECIMAL(6, 2), capacidad_tanque_litros DECIMAL(8, 2), -- Odómetro odometro_actual INT DEFAULT 0, odometro_ultimo_servicio INT, -- GPS tiene_gps BOOLEAN DEFAULT FALSE, gps_proveedor VARCHAR(50), gps_imei VARCHAR(50), -- Estado estado fleet.estado_unidad DEFAULT 'DISPONIBLE', ubicacion_actual_lat DECIMAL(10, 7), ubicacion_actual_lng DECIMAL(10, 7), ultima_actualizacion_ubicacion TIMESTAMPTZ, -- Propiedad es_propia BOOLEAN DEFAULT TRUE, propietario_id UUID, -- Si no es propia, referencia al carrier -- Costos costo_adquisicion DECIMAL(15, 2), fecha_adquisicion DATE, valor_actual DECIMAL(15, 2), -- Fechas importantes fecha_verificacion_proxima DATE, fecha_poliza_vencimiento DATE, fecha_permiso_vencimiento DATE, -- Activo activo BOOLEAN DEFAULT TRUE, fecha_baja DATE, motivo_baja TEXT, -- Auditoría created_at TIMESTAMPTZ DEFAULT NOW(), created_by_id UUID NOT NULL, updated_at TIMESTAMPTZ DEFAULT NOW(), updated_by_id UUID, CONSTRAINT uq_unidad_numero UNIQUE (tenant_id, numero_economico), CONSTRAINT uq_unidad_placa UNIQUE (tenant_id, placa) ); CREATE INDEX idx_unidad_tenant ON fleet.unidades(tenant_id); CREATE INDEX idx_unidad_tipo ON fleet.unidades(tenant_id, tipo); CREATE INDEX idx_unidad_estado ON fleet.unidades(tenant_id, estado); CREATE INDEX idx_unidad_activo ON fleet.unidades(tenant_id, activo) WHERE activo = TRUE; -- ============================================================================= -- TABLA: remolques -- ============================================================================= CREATE TABLE fleet.remolques ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES public.tenants(id), -- Identificación numero_economico VARCHAR(20) NOT NULL, tipo fleet.tipo_unidad NOT NULL, -- CAJA_SECA, PLATAFORMA, etc. -- Vehículo marca VARCHAR(50), modelo VARCHAR(50), anio INT, numero_serie VARCHAR(50), -- Placas placa VARCHAR(15), placa_estado VARCHAR(50), -- Dimensiones largo_metros DECIMAL(6, 2), ancho_metros DECIMAL(6, 2), alto_metros DECIMAL(6, 2), -- Capacidades capacidad_peso_kg DECIMAL(10, 2), capacidad_volumen_m3 DECIMAL(10, 4), capacidad_pallets INT, -- Refrigeración (si aplica) es_refrigerado BOOLEAN DEFAULT FALSE, marca_refrigeracion VARCHAR(50), modelo_refrigeracion VARCHAR(50), temperatura_min DECIMAL(5, 2), temperatura_max DECIMAL(5, 2), -- Estado estado fleet.estado_unidad DEFAULT 'DISPONIBLE', -- Propiedad es_propia BOOLEAN DEFAULT TRUE, propietario_id UUID, -- Fechas importantes fecha_verificacion_proxima DATE, fecha_poliza_vencimiento DATE, -- Activo activo BOOLEAN DEFAULT TRUE, -- Auditoría created_at TIMESTAMPTZ DEFAULT NOW(), created_by_id UUID NOT NULL, updated_at TIMESTAMPTZ DEFAULT NOW(), CONSTRAINT uq_remolque_numero UNIQUE (tenant_id, numero_economico) ); CREATE INDEX idx_remolque_tenant ON fleet.remolques(tenant_id); CREATE INDEX idx_remolque_tipo ON fleet.remolques(tenant_id, tipo); CREATE INDEX idx_remolque_estado ON fleet.remolques(tenant_id, estado); -- ============================================================================= -- TABLA: operadores (Conductores) -- ============================================================================= CREATE TABLE fleet.operadores ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES public.tenants(id), -- Identificación numero_empleado VARCHAR(20) NOT NULL, nombre VARCHAR(100) NOT NULL, apellido_paterno VARCHAR(100) NOT NULL, apellido_materno VARCHAR(100), nombre_completo VARCHAR(300) GENERATED ALWAYS AS ( nombre || ' ' || apellido_paterno || COALESCE(' ' || apellido_materno, '') ) STORED, -- Documentos de identidad curp VARCHAR(18), rfc VARCHAR(13), nss VARCHAR(15), -- Número Seguro Social -- Contacto telefono VARCHAR(30), telefono_emergencia VARCHAR(30), email VARCHAR(255), -- Dirección direccion TEXT, codigo_postal VARCHAR(10), ciudad VARCHAR(100), estado VARCHAR(100), -- Datos de nacimiento fecha_nacimiento DATE, lugar_nacimiento VARCHAR(100), nacionalidad VARCHAR(50) DEFAULT 'Mexicana', -- Licencia de conducir tipo_licencia fleet.tipo_licencia, numero_licencia VARCHAR(30), licencia_vigencia DATE, licencia_estado_expedicion VARCHAR(50), -- Certificaciones certificado_fisico_vigencia DATE, antidoping_vigencia DATE, capacitacion_materiales_peligrosos BOOLEAN DEFAULT FALSE, capacitacion_mp_vigencia DATE, -- Estado estado fleet.estado_operador DEFAULT 'ACTIVO', -- Unidad asignada (default) unidad_asignada_id UUID REFERENCES fleet.unidades(id), -- Métricas de desempeño calificacion DECIMAL(3, 2) DEFAULT 5.00, total_viajes INT DEFAULT 0, total_km INT DEFAULT 0, incidentes INT DEFAULT 0, -- Datos bancarios (para pagos) banco VARCHAR(100), cuenta_bancaria VARCHAR(30), clabe VARCHAR(18), -- Salario salario_base DECIMAL(12, 2), tipo_pago VARCHAR(20), -- 'FIJO', 'POR_VIAJE', 'MIXTO' -- Fechas fecha_ingreso DATE, fecha_baja DATE, motivo_baja TEXT, -- Activo activo BOOLEAN DEFAULT TRUE, -- Auditoría created_at TIMESTAMPTZ DEFAULT NOW(), created_by_id UUID NOT NULL, updated_at TIMESTAMPTZ DEFAULT NOW(), updated_by_id UUID, CONSTRAINT uq_operador_numero UNIQUE (tenant_id, numero_empleado), CONSTRAINT uq_operador_curp UNIQUE (tenant_id, curp) ); CREATE INDEX idx_operador_tenant ON fleet.operadores(tenant_id); CREATE INDEX idx_operador_estado ON fleet.operadores(tenant_id, estado); CREATE INDEX idx_operador_activo ON fleet.operadores(tenant_id, activo) WHERE activo = TRUE; CREATE INDEX idx_operador_licencia ON fleet.operadores(licencia_vigencia); -- ============================================================================= -- TABLA: documentos_flota -- ============================================================================= CREATE TABLE fleet.documentos_flota ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES public.tenants(id), -- Referencia polimórfica entidad_tipo VARCHAR(20) NOT NULL, -- 'UNIDAD', 'REMOLQUE', 'OPERADOR' entidad_id UUID NOT NULL, -- Documento tipo_documento fleet.tipo_documento NOT NULL, nombre VARCHAR(200) NOT NULL, numero_documento VARCHAR(100), descripcion TEXT, -- Vigencia fecha_emision DATE, fecha_vencimiento DATE, dias_alerta_vencimiento INT DEFAULT 30, -- Archivo archivo_url TEXT, archivo_nombre VARCHAR(255), archivo_tipo VARCHAR(50), archivo_tamano_bytes BIGINT, -- Estado verificado BOOLEAN DEFAULT FALSE, verificado_por UUID, verificado_fecha TIMESTAMPTZ, -- Activo activo BOOLEAN DEFAULT TRUE, -- Auditoría created_at TIMESTAMPTZ DEFAULT NOW(), created_by_id UUID NOT NULL, updated_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_documento_entidad ON fleet.documentos_flota(entidad_tipo, entidad_id); CREATE INDEX idx_documento_vencimiento ON fleet.documentos_flota(fecha_vencimiento) WHERE activo = TRUE; CREATE INDEX idx_documento_tipo ON fleet.documentos_flota(tenant_id, tipo_documento); -- ============================================================================= -- TABLA: asignaciones_unidad_operador -- ============================================================================= CREATE TABLE fleet.asignaciones ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES public.tenants(id), unidad_id UUID NOT NULL REFERENCES fleet.unidades(id), operador_id UUID NOT NULL REFERENCES fleet.operadores(id), remolque_id UUID REFERENCES fleet.remolques(id), -- Vigencia de asignación fecha_inicio TIMESTAMPTZ NOT NULL, fecha_fin TIMESTAMPTZ, -- Activa activa BOOLEAN DEFAULT TRUE, -- Motivo motivo VARCHAR(200), -- Auditoría created_at TIMESTAMPTZ DEFAULT NOW(), created_by_id UUID NOT NULL ); CREATE INDEX idx_asignacion_unidad ON fleet.asignaciones(unidad_id, activa); CREATE INDEX idx_asignacion_operador ON fleet.asignaciones(operador_id, activa); -- ============================================================================= -- RLS POLICIES -- ============================================================================= ALTER TABLE fleet.unidades ENABLE ROW LEVEL SECURITY; ALTER TABLE fleet.remolques ENABLE ROW LEVEL SECURITY; ALTER TABLE fleet.operadores ENABLE ROW LEVEL SECURITY; ALTER TABLE fleet.documentos_flota ENABLE ROW LEVEL SECURITY; ALTER TABLE fleet.asignaciones ENABLE ROW LEVEL SECURITY; CREATE POLICY tenant_isolation_unidades ON fleet.unidades USING (tenant_id = current_setting('app.tenant_id')::uuid); CREATE POLICY tenant_isolation_remolques ON fleet.remolques USING (tenant_id = current_setting('app.tenant_id')::uuid); CREATE POLICY tenant_isolation_operadores ON fleet.operadores USING (tenant_id = current_setting('app.tenant_id')::uuid); CREATE POLICY tenant_isolation_documentos ON fleet.documentos_flota USING (tenant_id = current_setting('app.tenant_id')::uuid); CREATE POLICY tenant_isolation_asignaciones ON fleet.asignaciones USING (tenant_id = current_setting('app.tenant_id')::uuid); -- ============================================================================= -- COMENTARIOS -- ============================================================================= COMMENT ON TABLE fleet.unidades IS 'Unidades motrices (tractoras, camiones, camionetas)'; COMMENT ON TABLE fleet.remolques IS 'Remolques, cajas, plataformas, tanques'; COMMENT ON TABLE fleet.operadores IS 'Operadores/conductores de la flota'; COMMENT ON TABLE fleet.documentos_flota IS 'Documentos de unidades, remolques y operadores'; COMMENT ON TABLE fleet.asignaciones IS 'Historial de asignaciones unidad-operador'; -- ============================================================================= -- FIN DDL FLEET -- =============================================================================