Skip to main content

Data Models

The Tanqueo Backend API uses TypeScript interfaces to define data models with strong type safety. All interfaces are defined in src/types/index.ts.

Core Entities

Usuario (User)

Represents authenticated users in the system:
export interface Usuario {
  id: string;           // UUID from Supabase Auth
  email: string;        // User email address
  nombre: string;       // Full name
  rol: string;          // User role (admin, operator, etc.)
  creado_en?: string;   // Creation timestamp
}
Usage:
  • Attached to req.user after authentication
  • Retrieved from usuarios table joined with Supabase Auth

AuthRequest

Extended Express Request with authentication data:
import { Request } from 'express';
import { SupabaseClient } from '@supabase/supabase-js';

export interface AuthRequest extends Request {
  user?: Usuario;                  // Authenticated user
  accessToken?: string;            // JWT access token
  supabase?: SupabaseClient;       // User-authenticated Supabase client
}
Usage:
  • All protected route handlers receive AuthRequest
  • req.supabase has RLS policies applied automatically

Authentication Models

LoginRequest

export interface LoginRequest {
  email: string;
  password: string;
}

LoginResponse

export interface LoginResponse {
  user: Usuario;
  access_token: string;
  refresh_token: string;
  expires_at: number;      // Unix timestamp
  expires_in: number;      // Seconds (typically 3600)
}
Example:
{
  "user": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "email": "[email protected]",
    "nombre": "Juan Pérez",
    "rol": "admin"
  },
  "access_token": "eyJhbGci...",
  "refresh_token": "v1.MRjrcL...",
  "expires_at": 1709564400,
  "expires_in": 3600
}

Fuel Tracking (Tanqueos)

Tanqueo

Base entity for fuel operations:
export interface Tanqueo {
  id?: number;
  fecha: string;                      // Date (YYYY-MM-DD)
  
  // Optional fields depending on operation type
  conductor_id?: number | null;
  placa_id?: number | null;
  tipo_combustible?: string | null;   // DIESEL, GASOLINA, etc.
  valor_tanqueo?: number | null;      // Total cost
  cantidad_galones?: number | null;   // Gallons refueled
  costo_por_galon?: number | null;    // Cost per gallon
  valor_anticipo?: number | null;     // Advance payment
  saldo_disponible?: number | null;   // Available balance
  
  // Required fields
  bomba_id: number;                   // Fuel pump ID
  area_operacion_id: number;          // Operating area ID
  concepto: string;                   // Concept/reason
  tipo_operacion: string;             // TANQUEO, ANTICIPO, etc.
  observacion?: string | null;        // Notes
  horometro?: number | null;          // Hour meter reading
  
  // Audit fields
  creado_por?: string;
  actualizado_por?: string;
  actualizado_en?: string;
}

TanqueoRelacion

Enriched view with joined relationships:
export interface TanqueoRelacion {
  idx: number;                   // Row index
  id: number;
  fecha: string;
  
  // Foreign key IDs
  conductor_id: number;
  placa_id: number;
  bomba_id: number;
  area_operacion_id: number;
  
  // Joined display values
  conductor: string;             // Driver name
  placa: string;                 // Vehicle plate
  bomba: string;                 // Pump name
  area_operacion: string;        // Area name
  
  // Fuel data
  tipo_combustible: string;
  valor_tanqueo: number;
  cantidad_galones: number;
  horometro: number | null;
  costo_por_galon: number | null;
  valor_anticipo: number | null;
  saldo_disponible: number;
  
  concepto: string;
  tipo_operacion: string;
  observacion: string | null;
}
Example:
{
  "id": 1542,
  "fecha": "2026-03-04",
  "conductor": "Juan Pérez",
  "placa": "ABC123",
  "bomba": "Bomba Central",
  "area_operacion": "Zona Norte",
  "tipo_combustible": "DIESEL",
  "valor_tanqueo": 250000,
  "cantidad_galones": 50,
  "costo_por_galon": 5000,
  "concepto": "Operación rutina",
  "tipo_operacion": "TANQUEO"
}

TanqueoFilters

export interface TanqueoFilters {
  conductor?: string;           // Partial match
  placa?: string;               // Partial match
  bomba?: string;               // Partial match
  area_operacion?: string;      // Partial match
  tipo_combustible?: string;    // Exact match
  concepto?: string;            // Exact match
  fecha_inicio?: string;        // Greater than or equal
  fecha_fin?: string;           // Less than or equal
}

PaginatedResponse

export interface PaginatedResponse {
  data: TanqueoRelacion[];
  pagination: {
    page: number;
    limit: number;
    total: number;
    totalPages: number;
  };
}

Maintenance (Engrases)

Engrase

export interface Engrase {
  id?: number;
  fecha: string;
  conductor_id: number;
  placa_id: number;
  area_operacion_id: number;
  
  // Service costs
  lavado: number;               // Wash cost
  engrase: number;              // Lubrication cost
  otros: number;                // Other costs
  suma?: number;                // Total (calculated)
  
  observaciones?: string | null;
  
  // Audit fields
  creado_por?: string;
  actualizado_por?: string;
  actualizado_en?: string;
}

EngraseRelacion

export interface EngraseRelacion {
  idx: number;
  id: number;
  fecha: string;
  
  conductor_id: number;
  conductor: string;            // Joined name
  placa_id: number;
  placa: string;                // Joined plate
  area_operacion_id: number;
  area_operacion: string;       // Joined area
  
  lavado: number;
  engrase: number;
  otros: number;
  suma: number;                 // Total cost
  observaciones: string | null;
}

Document Management

DocumentoVehiculo

export interface DocumentoVehiculo {
  id?: number;
  placa_id: number;
  area_operacion_id: number;
  
  // Expiration dates
  fecha_vencimiento_soat?: string | null;    // SOAT (mandatory insurance)
  fecha_vencimiento_rtm?: string | null;     // Technical review
  fecha_vencimiento_poliza?: string | null;  // Insurance policy
  
  // Document files (URLs or paths)
  pdf_soat?: string | null;
  pdf_rtm?: string | null;
  tarjeta_propiedad?: string | null;         // Property card
  pdf_poliza?: string | null;
  
  creado_por?: string;
  actualizado_por?: string;
  actualizado_en?: string;
}

Fleet Management

Vehiculo

export interface Vehiculo {
  id: number;
  placa_id: number;
  empresa_id: number | null;
  operacion_id: number | null;
  created_at?: string;
  
  // Relations (populated when joined)
  areas_placas?: { placa: string };
  empresas?: { empresa: string };
  areas_operacion?: { nombre: string };
  vehiculo_caracteristicas?: VehiculoCaracteristicas;
}

VehiculoCaracteristicas

export interface VehiculoCaracteristicas {
  vehiculo_id: number;
  
  // Foreign keys to catalog tables
  marca_id: number | null;
  tipo_vehiculo_id: number | null;
  clase_vehiculo_id: number | null;
  combustible_id: number | null;
  marca_compactadora_id: number | null;
  
  // Specifications
  nro_ejes: string | null;      // Number of axles
  nro_llantas: string | null;   // Number of tires
  anio: string | null;          // Year (text field)
  linea: string | null;         // Model line
  nro_serie: string | null;     // Serial number
  
  // Relations
  cat_marca?: CatMarca;
  cat_tipo_vehiculo?: CatTipoVehiculo;
  cat_clase_vehiculo?: CatClaseVehiculo;
  cat_combustible?: CatCombustible;
  cat_marca_compactadora?: CatMarcaCompactadora;
}

Catalog Entities

export interface CatMarca {
  id: number;
  nombre: string;
}

export interface CatTipoVehiculo {
  id: number;
  nombre: string;
}

export interface CatClaseVehiculo {
  id: number;
  nombre: string;
}

export interface CatCombustible {
  id: number;
  nombre: string;
}

export interface CatMarcaCompactadora {
  id: number;
  nombre: string;
}

Budget Management

MaestroRubro

Hierarchical budget categories:
export interface MaestroRubro {
  id: number;
  nivel: number;                              // Hierarchy level
  codigo: string;
  nombre: string;
  tipo: 'DEPENDENCIA' | 'GRUPO_RUBRO' | 'RUBRO';
  codigo_concatenado: string | null;
  abreviatura: string | null;
  activo: boolean;
  rubro_padre_id: number | null;              // Parent category
}

Presupuesto

export interface Presupuesto {
  id?: number;
  empresa_id: number;
  vehiculo_id: number | null;
  area_operacion_id: number;
  grupo_rubro_id: number;
  rubro_id: number;
  anio: number;                               // Budget year
  estado: 'BORRADOR' | 'APROBADO';            // Draft or approved
  empleado_id?: number | null;
  created_at?: string;
}

PresupuestoItem

export interface PresupuestoItem {
  id?: number;
  presupuesto_id: number;
  tipo_presupuesto_id: number;
  concepto_presupuesto_id: number;
  frecuencia_mes: number;                     // Monthly frequency
  meses_aplicables: number[];                 // Array: [1,2,3,...,12]
  valor_unitario: number;
  valor_total: number;
}

PresupuestoConItems

Complete budget with line items:
export interface PresupuestoConItems extends Presupuesto {
  items: PresupuestoItem[];
  
  // Joined relations
  vehiculo?: { placa: string };
  area_operacion?: { nombre: string };
  grupo_rubro?: { nombre: string; codigo: string };
  rubro?: { nombre: string; codigo: string };
}

Maintenance Planning

TipoMantenimiento

export interface TipoMantenimiento {
  id: number;
  tipo: string;              // PREVENTIVO, CORRECTIVO, etc.
}

PlanMantenimiento

export interface PlanMantenimiento {
  id: number;
  vehiculo_id: number;
  tipo_mantenimiento_id: number;
  nombre: string;
  activo: boolean;
  
  // Relations
  vehiculo?: Vehiculo;
  tipo_mantenimiento?: TipoMantenimiento;
  condiciones?: PlanCondicion[];
}

PlanCondicion

Maintenance trigger conditions:
export interface PlanCondicion {
  id: number;
  plan_id: number;
  tipo_condicion_id: number;
  valor: number;             // Threshold value
  unidad: string;            // Unit (km, hours, days, etc.)
  
  tipo_condicion?: TipoCondicion;
}

export interface TipoCondicion {
  id: number;
  codigo: string;
  nombre: string;
}

MantenimientoEvento

Actual maintenance performed:
export interface MantenimientoEvento {
  id: number;
  plan_id: number;
  vehiculo_id: number;
  fecha: string;
  descripcion: string | null;
  taller_id: number | null;  // Workshop/garage
  costo: number | null;
  hr_evento: number | null;  // Hour meter at event
  km_evento: number | null;  // Odometer at event
  observaciones: string | null;
  
  // Relations
  plan_mantenimiento?: PlanMantenimiento;
  vehiculo?: Vehiculo;
  talleres?: { nombre: string };
}

Type Safety Benefits

TypeScript interfaces provide:

Compile-Time Validation

Catch type errors before runtime

IDE Autocomplete

IntelliSense support in editors

Documentation

Self-documenting code with type hints

Refactoring Safety

Rename and restructure with confidence

Using Types in Controllers

Example controller with proper typing:
import { AuthRequest, Tanqueo, TanqueoRelacion, PaginatedResponse } from '../types';

export const tanqueosController = {
  async getAll(req: AuthRequest, res: Response): Promise<void> {
    // TypeScript knows req.user exists and has Usuario shape
    const userId = req.user?.id;
    
    // TypeScript validates query result matches TanqueoRelacion[]
    const { data, error } = await supabase
      .from('tanqueo_relaciones')
      .select('*');
    
    // Response type is enforced
    const response: PaginatedResponse = {
      data: data || [],
      pagination: { /* ... */ }
    };
    
    res.json(response);
  }
};

Database Schema Alignment

TypeScript interfaces should match the PostgreSQL schema. When the database schema changes, update the corresponding interfaces in src/types/index.ts.
Nullable fields in the database (null allowed) must be marked with | null in TypeScript to accurately reflect the data model.

Build docs developers (and LLMs) love