- 11-compound-indices.sql: 14 compound indices for common queries - docs/JSONB-SCHEMAS.md: 50+ TypeScript interfaces documenting JSONB fields - DDL-EXECUTION-ORDER.md: Updated to include compound indices step Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
782 lines
15 KiB
Markdown
782 lines
15 KiB
Markdown
# JSONB Schemas Documentation - ERP Construccion
|
|
|
|
**Version:** 1.0.0
|
|
**Fecha:** 2026-02-03
|
|
**Proyecto:** erp-construccion
|
|
|
|
---
|
|
|
|
## Descripcion
|
|
|
|
Este documento define los schemas esperados para los campos JSONB en la base de datos de ERP Construccion. Los campos JSONB almacenan datos flexibles/extensibles sin estructura rigida de tablas relacionales.
|
|
|
|
---
|
|
|
|
## Convenciones
|
|
|
|
### Notacion
|
|
|
|
- `{}` - Objeto JSON
|
|
- `[]` - Array JSON
|
|
- `?` - Campo opcional
|
|
- `type` - Tipo esperado (string, number, boolean, date)
|
|
|
|
### Validacion
|
|
|
|
Los schemas deben validarse en el backend antes de insertar datos. Se recomienda usar JSON Schema o Zod para validacion.
|
|
|
|
---
|
|
|
|
## Schema: construction
|
|
|
|
### fraccionamientos.metadata
|
|
|
|
```typescript
|
|
interface FraccionamientoMetadata {
|
|
// Informacion legal
|
|
escritura_publica?: string;
|
|
notario?: string;
|
|
numero_registro_publico?: string;
|
|
fecha_registro?: string; // YYYY-MM-DD
|
|
|
|
// Permisos
|
|
permiso_uso_suelo?: string;
|
|
fecha_permiso_uso_suelo?: string;
|
|
permiso_construccion?: string;
|
|
fecha_permiso_construccion?: string;
|
|
|
|
// Urbanizacion
|
|
porcentaje_urbanizacion?: number; // 0-100
|
|
servicios_instalados?: string[]; // ['agua', 'luz', 'drenaje', 'gas']
|
|
|
|
// Contacto
|
|
contacto_nombre?: string;
|
|
contacto_telefono?: string;
|
|
contacto_email?: string;
|
|
|
|
// Financiamiento
|
|
credito_puente?: boolean;
|
|
banco_financiador?: string;
|
|
monto_credito?: number;
|
|
|
|
// Seguros
|
|
poliza_rc?: string;
|
|
vigencia_poliza_rc?: string;
|
|
|
|
// Custom fields
|
|
[key: string]: any;
|
|
}
|
|
```
|
|
|
|
### prototipos.metadata
|
|
|
|
```typescript
|
|
interface PrototipoMetadata {
|
|
// Especificaciones tecnicas
|
|
estructura?: string; // 'concreto', 'acero', 'mixta'
|
|
acabados?: {
|
|
pisos?: string;
|
|
muros?: string;
|
|
plafones?: string;
|
|
cocina?: string;
|
|
banos?: string;
|
|
};
|
|
|
|
// Equipamiento incluido
|
|
equipamiento?: string[]; // ['calentador', 'tinaco', 'hidroneumatico']
|
|
|
|
// Renders y materiales de venta
|
|
fotos_galeria?: string[]; // URLs
|
|
video_recorrido?: string;
|
|
brochure_pdf?: string;
|
|
|
|
// Precios por concepto
|
|
desglose_precio?: {
|
|
terreno?: number;
|
|
construccion?: number;
|
|
equipamiento?: number;
|
|
gastos_escrituracion?: number;
|
|
};
|
|
|
|
// Custom fields
|
|
[key: string]: any;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Schema: finance
|
|
|
|
### bank_accounts.metadata
|
|
|
|
```typescript
|
|
interface BankAccountMetadata {
|
|
// Acceso banca electronica
|
|
banca_electronica?: {
|
|
url?: string;
|
|
usuario_consulta?: string;
|
|
tiene_transferencias?: boolean;
|
|
limite_diario?: number;
|
|
limite_mensual?: number;
|
|
};
|
|
|
|
// Documentos
|
|
contrato_url?: string;
|
|
estado_cuenta_url?: string;
|
|
|
|
// Autorizadores
|
|
firmas_autorizadas?: Array<{
|
|
nombre: string;
|
|
cargo: string;
|
|
limite_firma?: number;
|
|
}>;
|
|
|
|
// Integraciones
|
|
api_config?: {
|
|
provider?: string;
|
|
api_key_ref?: string; // Referencia a secret manager
|
|
webhook_url?: string;
|
|
};
|
|
|
|
// Custom fields
|
|
[key: string]: any;
|
|
}
|
|
```
|
|
|
|
### bank_movements.raw_data
|
|
|
|
```typescript
|
|
interface BankMovementRawData {
|
|
// Datos originales del banco
|
|
referencia_banco?: string;
|
|
concepto_banco?: string;
|
|
tipo_movimiento_banco?: string;
|
|
codigo_movimiento?: string;
|
|
|
|
// Datos de importacion
|
|
imported_from?: 'api' | 'csv' | 'pdf' | 'manual';
|
|
import_date?: string;
|
|
original_row?: Record<string, any>;
|
|
|
|
// Matching info
|
|
auto_matched?: boolean;
|
|
match_score?: number;
|
|
match_candidates?: string[]; // IDs de posibles matches
|
|
}
|
|
```
|
|
|
|
### bank_reconciliation.reconciliation_items
|
|
|
|
```typescript
|
|
interface ReconciliationItems {
|
|
matched: Array<{
|
|
bank_movement_id: string;
|
|
erp_movement_id: string;
|
|
match_date: string;
|
|
match_type: 'auto' | 'manual';
|
|
amount: number;
|
|
}>;
|
|
|
|
unmatched_bank: Array<{
|
|
bank_movement_id: string;
|
|
amount: number;
|
|
date: string;
|
|
description: string;
|
|
}>;
|
|
|
|
unmatched_erp: Array<{
|
|
erp_movement_id: string;
|
|
amount: number;
|
|
date: string;
|
|
description: string;
|
|
}>;
|
|
|
|
adjustments: Array<{
|
|
type: 'charge' | 'commission' | 'interest' | 'other';
|
|
amount: number;
|
|
description: string;
|
|
date: string;
|
|
}>;
|
|
}
|
|
```
|
|
|
|
### cash_flow_projection.income_breakdown / expense_breakdown
|
|
|
|
```typescript
|
|
interface CashFlowBreakdown {
|
|
categories: Array<{
|
|
category: string;
|
|
subcategories: Array<{
|
|
name: string;
|
|
projected: number;
|
|
actual?: number;
|
|
variance?: number;
|
|
notes?: string;
|
|
}>;
|
|
total_projected: number;
|
|
total_actual?: number;
|
|
}>;
|
|
|
|
total: number;
|
|
currency: string;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Schema: hse
|
|
|
|
### programa_seguridad.metas
|
|
|
|
```typescript
|
|
interface ProgramaSeguridad_Metas {
|
|
indicadores: Array<{
|
|
indicador_id: string;
|
|
meta_anual: number;
|
|
metas_mensuales?: number[]; // 12 valores
|
|
tolerancia_inferior?: number;
|
|
tolerancia_superior?: number;
|
|
}>;
|
|
|
|
objetivos: Array<{
|
|
descripcion: string;
|
|
fecha_limite: string;
|
|
responsable_id?: string;
|
|
estado?: 'pendiente' | 'en_progreso' | 'completado';
|
|
evidencia_url?: string;
|
|
}>;
|
|
}
|
|
```
|
|
|
|
### documento_stps.datos_documento
|
|
|
|
```typescript
|
|
interface DocumentoSTPS_DatosDocumento {
|
|
// Para DC-3 (Constancias)
|
|
dc3?: {
|
|
folio_constancia: string;
|
|
nombre_curso: string;
|
|
duracion_horas: number;
|
|
fecha_capacitacion: string;
|
|
nombre_instructor: string;
|
|
registro_stps_instructor: string;
|
|
agente_capacitador: string;
|
|
registro_agente: string;
|
|
};
|
|
|
|
// Para ST-7 (Dictamen)
|
|
st7?: {
|
|
numero_dictamen: string;
|
|
unidad_verificacion: string;
|
|
fecha_verificacion: string;
|
|
resultado: 'favorable' | 'condicionado' | 'negativo';
|
|
vigencia_hasta: string;
|
|
observaciones?: string[];
|
|
};
|
|
|
|
// Campos genericos
|
|
[key: string]: any;
|
|
}
|
|
```
|
|
|
|
### tipo_permiso_trabajo.documentos_requeridos
|
|
|
|
```typescript
|
|
interface PermisoTrabajo_DocumentosRequeridos {
|
|
documentos: Array<{
|
|
nombre: string;
|
|
descripcion?: string;
|
|
obligatorio: boolean;
|
|
formato_aceptado?: string[]; // ['pdf', 'jpg', 'png']
|
|
plantilla_url?: string;
|
|
}>;
|
|
}
|
|
```
|
|
|
|
### tipo_permiso_trabajo.requisitos_personal
|
|
|
|
```typescript
|
|
interface PermisoTrabajo_RequisitosPersonal {
|
|
roles: Array<{
|
|
rol: 'ejecutor' | 'supervisor' | 'vigia' | 'operador';
|
|
cantidad_minima: number;
|
|
capacitaciones_requeridas?: string[]; // IDs de capacitaciones
|
|
certificaciones_requeridas?: string[];
|
|
}>;
|
|
|
|
epp_obligatorio?: string[]; // IDs de EPP del catalogo
|
|
examen_medico_requerido?: boolean;
|
|
}
|
|
```
|
|
|
|
### tipo_permiso_trabajo.equipos_requeridos
|
|
|
|
```typescript
|
|
interface PermisoTrabajo_EquiposRequeridos {
|
|
equipos: Array<{
|
|
descripcion: string;
|
|
cantidad: number;
|
|
especificaciones?: string;
|
|
certificacion_requerida?: boolean;
|
|
}>;
|
|
|
|
herramientas: Array<{
|
|
descripcion: string;
|
|
cantidad: number;
|
|
}>;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Schema: assets
|
|
|
|
### equipment.specifications
|
|
|
|
```typescript
|
|
interface EquipmentSpecifications {
|
|
// Motor
|
|
motor?: {
|
|
tipo?: string;
|
|
marca?: string;
|
|
modelo?: string;
|
|
potencia_hp?: number;
|
|
combustible?: string;
|
|
capacidad_tanque_lt?: number;
|
|
};
|
|
|
|
// Dimensiones
|
|
dimensiones?: {
|
|
largo_m?: number;
|
|
ancho_m?: number;
|
|
alto_m?: number;
|
|
peso_kg?: number;
|
|
};
|
|
|
|
// Capacidades
|
|
capacidades?: {
|
|
carga_max_kg?: number;
|
|
volumen_m3?: number;
|
|
alcance_m?: number;
|
|
};
|
|
|
|
// Llantas/Rodamiento
|
|
rodamiento?: {
|
|
tipo?: string; // 'neumatico', 'orugas', 'mixto'
|
|
cantidad?: number;
|
|
medida?: string;
|
|
};
|
|
|
|
// Custom fields
|
|
[key: string]: any;
|
|
}
|
|
```
|
|
|
|
### maintenance_plan.activities
|
|
|
|
```typescript
|
|
interface MaintenancePlanActivities {
|
|
activities: Array<{
|
|
sequence: number;
|
|
name: string;
|
|
description?: string;
|
|
duration_minutes?: number;
|
|
skill_required?: string;
|
|
|
|
checklist: Array<{
|
|
item: string;
|
|
type: 'check' | 'measurement' | 'photo';
|
|
required: boolean;
|
|
expected_value?: string | number;
|
|
tolerance?: number;
|
|
}>;
|
|
|
|
safety_notes?: string[];
|
|
}>;
|
|
}
|
|
```
|
|
|
|
### maintenance_plan.required_parts / required_tools
|
|
|
|
```typescript
|
|
interface MaintenancePlanParts {
|
|
parts: Array<{
|
|
part_number?: string;
|
|
description: string;
|
|
quantity: number;
|
|
unit: string;
|
|
estimated_cost?: number;
|
|
supplier_id?: string;
|
|
}>;
|
|
}
|
|
|
|
interface MaintenancePlanTools {
|
|
tools: Array<{
|
|
name: string;
|
|
specification?: string;
|
|
quantity: number;
|
|
}>;
|
|
}
|
|
```
|
|
|
|
### maintenance_order.activities_checklist
|
|
|
|
```typescript
|
|
interface MaintenanceOrderChecklist {
|
|
completed_activities: Array<{
|
|
activity_index: number;
|
|
completed_at: string;
|
|
completed_by: string;
|
|
|
|
checklist_results: Array<{
|
|
item_index: number;
|
|
passed: boolean;
|
|
value?: string | number;
|
|
photo_url?: string;
|
|
notes?: string;
|
|
}>;
|
|
}>;
|
|
|
|
overall_result: 'pass' | 'fail' | 'partial';
|
|
technician_notes?: string;
|
|
}
|
|
```
|
|
|
|
### maintenance_order.photos_before / photos_after / documents
|
|
|
|
```typescript
|
|
interface MaintenanceOrderPhotos {
|
|
photos: Array<{
|
|
url: string;
|
|
description?: string;
|
|
taken_at?: string;
|
|
taken_by?: string;
|
|
location?: string;
|
|
}>;
|
|
}
|
|
|
|
interface MaintenanceOrderDocuments {
|
|
documents: Array<{
|
|
url: string;
|
|
name: string;
|
|
type: 'report' | 'invoice' | 'warranty' | 'other';
|
|
uploaded_at?: string;
|
|
uploaded_by?: string;
|
|
}>;
|
|
}
|
|
```
|
|
|
|
### equipment_telemetry.raw_data
|
|
|
|
```typescript
|
|
interface EquipmentTelemetryRawData {
|
|
// Datos crudos del dispositivo
|
|
device_id: string;
|
|
timestamp: string;
|
|
signal_strength?: number;
|
|
battery_level?: number;
|
|
|
|
// Payload del sensor
|
|
payload: Record<string, any>;
|
|
|
|
// Procesamiento
|
|
processed?: boolean;
|
|
processing_errors?: string[];
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Schema: documents
|
|
|
|
### document_types.metadata
|
|
|
|
```typescript
|
|
interface DocumentTypeMetadata {
|
|
// Reglas de nomenclatura
|
|
naming_convention?: {
|
|
prefix?: string;
|
|
separator?: string;
|
|
include_date?: boolean;
|
|
date_format?: string;
|
|
sequence_length?: number;
|
|
};
|
|
|
|
// Restricciones
|
|
max_file_size_mb?: number;
|
|
allowed_extensions?: string[];
|
|
max_versions?: number;
|
|
|
|
// Workflow por defecto
|
|
default_workflow_id?: string;
|
|
auto_start_workflow?: boolean;
|
|
|
|
// Retencion
|
|
retention_years?: number;
|
|
auto_archive?: boolean;
|
|
}
|
|
```
|
|
|
|
### documents.custom_fields
|
|
|
|
```typescript
|
|
interface DocumentCustomFields {
|
|
// Campos dinamicos segun tipo de documento
|
|
[field_name: string]: {
|
|
value: any;
|
|
label?: string;
|
|
type?: 'text' | 'number' | 'date' | 'select' | 'boolean';
|
|
};
|
|
}
|
|
```
|
|
|
|
### document_versions.extracted_metadata
|
|
|
|
```typescript
|
|
interface DocumentExtractedMetadata {
|
|
// Metadatos extraidos del archivo
|
|
author?: string;
|
|
title?: string;
|
|
subject?: string;
|
|
keywords?: string[];
|
|
creation_date?: string;
|
|
modification_date?: string;
|
|
|
|
// Para PDFs
|
|
pdf_version?: string;
|
|
page_count?: number;
|
|
is_encrypted?: boolean;
|
|
has_forms?: boolean;
|
|
|
|
// Para imagenes
|
|
width?: number;
|
|
height?: number;
|
|
color_space?: string;
|
|
dpi?: number;
|
|
|
|
// GPS si disponible
|
|
gps_coordinates?: {
|
|
latitude: number;
|
|
longitude: number;
|
|
};
|
|
|
|
// OCR
|
|
ocr_text?: string;
|
|
ocr_confidence?: number;
|
|
}
|
|
```
|
|
|
|
### approval_workflows.steps
|
|
|
|
```typescript
|
|
interface ApprovalWorkflowSteps {
|
|
steps: Array<{
|
|
step_number: number;
|
|
name: string;
|
|
type: 'single' | 'any' | 'all' | 'percentage';
|
|
|
|
// Aprobadores
|
|
approvers: Array<{
|
|
type: 'user' | 'role' | 'department';
|
|
id: string;
|
|
}>;
|
|
|
|
// Para type='percentage'
|
|
required_percentage?: number;
|
|
// Para type='any' o 'all'
|
|
required_count?: number;
|
|
|
|
// Tiempo limite
|
|
deadline_hours?: number;
|
|
reminder_hours?: number;
|
|
escalation_user_id?: string;
|
|
|
|
// Acciones permitidas
|
|
allow_comments?: boolean;
|
|
allow_attachments?: boolean;
|
|
require_signature?: boolean;
|
|
}>;
|
|
}
|
|
```
|
|
|
|
### annotations.style
|
|
|
|
```typescript
|
|
interface AnnotationStyle {
|
|
// Para todas las anotaciones
|
|
color?: string; // Hex color
|
|
opacity?: number; // 0-1
|
|
|
|
// Para lineas
|
|
stroke_width?: number;
|
|
stroke_style?: 'solid' | 'dashed' | 'dotted';
|
|
arrow_start?: boolean;
|
|
arrow_end?: boolean;
|
|
|
|
// Para formas
|
|
fill_color?: string;
|
|
fill_opacity?: number;
|
|
border_radius?: number;
|
|
|
|
// Para texto
|
|
font_family?: string;
|
|
font_size?: number;
|
|
font_weight?: 'normal' | 'bold';
|
|
text_align?: 'left' | 'center' | 'right';
|
|
text_decoration?: 'none' | 'underline' | 'strikethrough';
|
|
|
|
// Para stamps
|
|
stamp_text?: string;
|
|
stamp_rotation?: number;
|
|
}
|
|
```
|
|
|
|
### document_audit.action_details
|
|
|
|
```typescript
|
|
interface DocumentAuditActionDetails {
|
|
// Contexto de la accion
|
|
ip_address?: string;
|
|
user_agent?: string;
|
|
session_id?: string;
|
|
|
|
// Datos especificos por tipo de accion
|
|
view?: {
|
|
page_viewed?: number;
|
|
duration_seconds?: number;
|
|
};
|
|
|
|
download?: {
|
|
format?: string;
|
|
};
|
|
|
|
edit?: {
|
|
fields_changed?: string[];
|
|
previous_values?: Record<string, any>;
|
|
new_values?: Record<string, any>;
|
|
};
|
|
|
|
share?: {
|
|
shared_with?: string[];
|
|
permissions?: string[];
|
|
expires_at?: string;
|
|
};
|
|
|
|
workflow?: {
|
|
action?: 'approve' | 'reject' | 'request_changes';
|
|
step_number?: number;
|
|
comments?: string;
|
|
};
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Schema: infonavit
|
|
|
|
### derechohabiente.metadata
|
|
|
|
```typescript
|
|
interface DerechohabienteMetadata {
|
|
// Datos adicionales INFONAVIT
|
|
puntos_infonavit?: number;
|
|
monto_credito_aprobado?: number;
|
|
subsidio_aprobado?: number;
|
|
|
|
// Documentos
|
|
identificacion_url?: string;
|
|
constancia_situacion_fiscal_url?: string;
|
|
comprobante_domicilio_url?: string;
|
|
acta_nacimiento_url?: string;
|
|
|
|
// Historial crediticio
|
|
score_buro?: number;
|
|
fecha_consulta_buro?: string;
|
|
|
|
// Referencias
|
|
referencias_personales?: Array<{
|
|
nombre: string;
|
|
telefono: string;
|
|
parentesco: string;
|
|
}>;
|
|
|
|
// Custom fields
|
|
[key: string]: any;
|
|
}
|
|
```
|
|
|
|
### lote_infonavit.metadata
|
|
|
|
```typescript
|
|
interface LoteInfonavitMetadata {
|
|
// Especificaciones vivienda
|
|
tipo_vivienda?: string;
|
|
valor_vivienda?: number;
|
|
ecotecnologias?: string[];
|
|
|
|
// Avaluo
|
|
numero_avaluo?: string;
|
|
fecha_avaluo?: string;
|
|
valor_avaluo?: number;
|
|
valuador?: string;
|
|
|
|
// ROC
|
|
roc_asignado?: string;
|
|
fecha_asignacion_roc?: string;
|
|
|
|
// Custom fields
|
|
[key: string]: any;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Validacion con Zod (Ejemplo)
|
|
|
|
```typescript
|
|
import { z } from 'zod';
|
|
|
|
// Schema para bank_accounts.metadata
|
|
export const BankAccountMetadataSchema = z.object({
|
|
banca_electronica: z.object({
|
|
url: z.string().url().optional(),
|
|
usuario_consulta: z.string().optional(),
|
|
tiene_transferencias: z.boolean().optional(),
|
|
limite_diario: z.number().positive().optional(),
|
|
limite_mensual: z.number().positive().optional(),
|
|
}).optional(),
|
|
|
|
contrato_url: z.string().url().optional(),
|
|
estado_cuenta_url: z.string().url().optional(),
|
|
|
|
firmas_autorizadas: z.array(z.object({
|
|
nombre: z.string(),
|
|
cargo: z.string(),
|
|
limite_firma: z.number().optional(),
|
|
})).optional(),
|
|
|
|
api_config: z.object({
|
|
provider: z.string().optional(),
|
|
api_key_ref: z.string().optional(),
|
|
webhook_url: z.string().url().optional(),
|
|
}).optional(),
|
|
}).passthrough(); // Allow additional fields
|
|
|
|
// Uso
|
|
const validateMetadata = (data: unknown) => {
|
|
return BankAccountMetadataSchema.parse(data);
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## Referencias
|
|
|
|
- `DDL-EXECUTION-ORDER.md` - Orden de ejecucion DDL
|
|
- `@ESTANDAR-DATABASE` - Estandares de base de datos
|
|
- TypeScript interfaces en backend
|
|
|
|
---
|
|
|
|
*Documentacion creada: 2026-02-03 - ST-P2-003*
|