[ST-P2-002,ST-P2-003] feat: Add compound indices and JSONB schema documentation
- 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>
This commit is contained in:
parent
6b02d8ab08
commit
dcdc15e162
@ -70,8 +70,9 @@ Cuando se crea una BD limpia SIN erp-core instalado previamente:
|
||||
| 9 | `schemas/08-finance-schema-ddl.sql` | Schema finance (11 tablas, 20 ENUMs) |
|
||||
| 10 | `schemas/09-assets-schema-ddl.sql` | Schema assets (11 tablas, 9 ENUMs) |
|
||||
| 11 | `schemas/10-documents-schema-ddl.sql` | Schema documents (11 tablas, 8 ENUMs) |
|
||||
| 12 | `schemas/99-rls-policies.sql` | Politicas RLS para todos los schemas |
|
||||
| 13 | `init-scripts/02-payment-terminals.sql` | Terminales de pago (opcional) |
|
||||
| 12 | `schemas/11-compound-indices.sql` | Indices compound para queries frecuentes |
|
||||
| 13 | `schemas/99-rls-policies.sql` | Politicas RLS para todos los schemas |
|
||||
| 14 | `init-scripts/02-payment-terminals.sql` | Terminales de pago (opcional) |
|
||||
|
||||
### Escenario B: Base de Datos con erp-core (Recomendado)
|
||||
|
||||
|
||||
781
docs/JSONB-SCHEMAS.md
Normal file
781
docs/JSONB-SCHEMAS.md
Normal file
@ -0,0 +1,781 @@
|
||||
# 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*
|
||||
106
schemas/11-compound-indices.sql
Normal file
106
schemas/11-compound-indices.sql
Normal file
@ -0,0 +1,106 @@
|
||||
-- ============================================================================
|
||||
-- COMPOUND INDICES - Indices compuestos para queries frecuentes
|
||||
-- Version: 1.0.0
|
||||
-- Fecha: 2026-02-03
|
||||
-- ============================================================================
|
||||
-- Proposito: Optimizar queries que filtran por tenant_id + status + created_at
|
||||
-- Patron comun en listados paginados con filtros de estado
|
||||
-- ============================================================================
|
||||
|
||||
-- ============================================================================
|
||||
-- SCHEMA: estimates
|
||||
-- ============================================================================
|
||||
|
||||
-- Indice compound para estimaciones (listado por estado y fecha)
|
||||
CREATE INDEX IF NOT EXISTS idx_estimaciones_tenant_status_created
|
||||
ON estimates.estimaciones(tenant_id, status, created_at DESC);
|
||||
|
||||
-- Indice compound para generadores (listado por estado y fecha)
|
||||
CREATE INDEX IF NOT EXISTS idx_generadores_tenant_status_created
|
||||
ON estimates.generadores(tenant_id, status, created_at DESC);
|
||||
|
||||
-- Indice compound para anticipos (busqueda por tipo y fecha)
|
||||
CREATE INDEX IF NOT EXISTS idx_anticipos_tenant_type_created
|
||||
ON estimates.anticipos(tenant_id, advance_type, created_at DESC);
|
||||
|
||||
-- ============================================================================
|
||||
-- SCHEMA: hse
|
||||
-- ============================================================================
|
||||
|
||||
-- Indice compound para incidentes (listado por estado y fecha)
|
||||
CREATE INDEX IF NOT EXISTS idx_incidentes_tenant_estado_created
|
||||
ON hse.incidentes(tenant_id, estado, created_at DESC);
|
||||
|
||||
-- Indice compound para incidentes por tipo y gravedad
|
||||
CREATE INDEX IF NOT EXISTS idx_incidentes_tenant_tipo_gravedad
|
||||
ON hse.incidentes(tenant_id, tipo, gravedad);
|
||||
|
||||
-- Indice compound para incidentes por fraccionamiento
|
||||
CREATE INDEX IF NOT EXISTS idx_incidentes_tenant_fracc_created
|
||||
ON hse.incidentes(tenant_id, fraccionamiento_id, created_at DESC);
|
||||
|
||||
-- Indice compound para capacitaciones por tipo
|
||||
CREATE INDEX IF NOT EXISTS idx_capacitaciones_tenant_tipo
|
||||
ON hse.capacitaciones(tenant_id, tipo);
|
||||
|
||||
-- ============================================================================
|
||||
-- SCHEMA: construction
|
||||
-- ============================================================================
|
||||
|
||||
-- Indice compound para fraccionamientos (listado por estado y fecha)
|
||||
CREATE INDEX IF NOT EXISTS idx_fracc_tenant_status_created
|
||||
ON construction.fraccionamientos(tenant_id, status, created_at DESC);
|
||||
|
||||
-- Indice compound para lotes (busqueda por estado y fraccionamiento)
|
||||
-- Nota: Necesitamos el fraccionamiento via manzana->etapa
|
||||
CREATE INDEX IF NOT EXISTS idx_lotes_tenant_status_created
|
||||
ON construction.lotes(tenant_id, status, created_at DESC);
|
||||
|
||||
-- Indice compound para etapas (listado por estado)
|
||||
CREATE INDEX IF NOT EXISTS idx_etapas_tenant_status_created
|
||||
ON construction.etapas(tenant_id, status, created_at DESC);
|
||||
|
||||
-- ============================================================================
|
||||
-- SCHEMA: finance
|
||||
-- ============================================================================
|
||||
|
||||
-- Indice compound para cuentas bancarias (busqueda por estado)
|
||||
CREATE INDEX IF NOT EXISTS idx_bank_accounts_tenant_status_created
|
||||
ON finance.bank_accounts(tenant_id, status, created_at DESC);
|
||||
|
||||
-- Indice compound para polizas contables (busqueda por tipo y fecha)
|
||||
CREATE INDEX IF NOT EXISTS idx_accounting_entries_tenant_type_date
|
||||
ON finance.accounting_entries(tenant_id, entry_type, entry_date DESC);
|
||||
|
||||
-- Indice compound para CxC (busqueda por estado)
|
||||
CREATE INDEX IF NOT EXISTS idx_accounts_receivable_tenant_status_created
|
||||
ON finance.accounts_receivable(tenant_id, status, created_at DESC);
|
||||
|
||||
-- Indice compound para CxP (busqueda por estado)
|
||||
CREATE INDEX IF NOT EXISTS idx_accounts_payable_tenant_status_created
|
||||
ON finance.accounts_payable(tenant_id, status, created_at DESC);
|
||||
|
||||
-- ============================================================================
|
||||
-- SCHEMA: hr
|
||||
-- ============================================================================
|
||||
|
||||
-- Indice compound para empleados (busqueda por estado)
|
||||
CREATE INDEX IF NOT EXISTS idx_employees_tenant_status_created
|
||||
ON hr.employees(tenant_id, status, created_at DESC);
|
||||
|
||||
-- ============================================================================
|
||||
-- COMENTARIOS
|
||||
-- ============================================================================
|
||||
|
||||
COMMENT ON INDEX estimates.idx_estimaciones_tenant_status_created IS
|
||||
'Indice compound para listados de estimaciones filtrados por estado, ordenados por fecha';
|
||||
|
||||
COMMENT ON INDEX hse.idx_incidentes_tenant_estado_created IS
|
||||
'Indice compound para listados de incidentes filtrados por estado, ordenados por fecha';
|
||||
|
||||
COMMENT ON INDEX construction.idx_fracc_tenant_status_created IS
|
||||
'Indice compound para listados de fraccionamientos filtrados por estado, ordenados por fecha';
|
||||
|
||||
-- ============================================================================
|
||||
-- FIN - Compound Indices
|
||||
-- ============================================================================
|
||||
Loading…
Reference in New Issue
Block a user