Showing
3 changed files
with
1 additions
and
228 deletions
BUSQUEDA.md
deleted
100644 → 0
| 1 | -# Lógica del Buscador | ||
| 2 | - | ||
| 3 | -## Resumen | ||
| 4 | -Buscador instantáneo con Fuse.js en cliente. Busca en clasificadores presupuestarios y navega a vistas de detalle. | ||
| 5 | - | ||
| 6 | -## Decisiones de Diseño | ||
| 7 | - | ||
| 8 | -### Motor de búsqueda | ||
| 9 | -- **Tecnología**: Fuse.js (cliente) | ||
| 10 | -- **Razón**: ~1,400 registros totales (~600 entidades + ~450 objetos + ~380 rubros), cabe en memoria, búsqueda instantánea sin latencia | ||
| 11 | - | ||
| 12 | -### Configuración Fuse.js | ||
| 13 | -```javascript | ||
| 14 | -const fuseOptions = { | ||
| 15 | - keys: [ | ||
| 16 | - { name: 'nombre_normalizado', weight: 0.6 }, | ||
| 17 | - { name: 'sigla_normalizada', weight: 0.2 }, | ||
| 18 | - { name: 'codigo_normalizado', weight: 0.2 } | ||
| 19 | - ], | ||
| 20 | - threshold: 0.4, | ||
| 21 | - distance: 100, | ||
| 22 | - includeScore: true, | ||
| 23 | - includeMatches: true, | ||
| 24 | - minMatchCharLength: 2, | ||
| 25 | - ignoreLocation: true | ||
| 26 | -}; | ||
| 27 | -``` | ||
| 28 | - | ||
| 29 | -### Tolerancia a errores | ||
| 30 | -- Normalización de acentos ("andres" → "andrés") | ||
| 31 | -- Case-insensitive ("UMSA" = "umsa") | ||
| 32 | -- Fuzzy matching ("univercidad" → "universidad") | ||
| 33 | - | ||
| 34 | -### Comportamiento | ||
| 35 | -| Parámetro | Valor | | ||
| 36 | -|-----------|-------| | ||
| 37 | -| Debounce | 250ms | | ||
| 38 | -| Mínimo caracteres | 2 | | ||
| 39 | -| Máximo resultados | 15 | | ||
| 40 | -| Navegación | Flechas ↑↓ + Enter + scroll de mouse | | ||
| 41 | - | ||
| 42 | -## Estructura del Índice | ||
| 43 | - | ||
| 44 | -### Índice unificado (implementado) | ||
| 45 | -Todos los clasificadores en un solo array con `tipo`: | ||
| 46 | - | ||
| 47 | -```javascript | ||
| 48 | -// src/lib/services/search.js | ||
| 49 | -const searchData = [ | ||
| 50 | - // Entidades | ||
| 51 | - { | ||
| 52 | - tipo: 'entidad', | ||
| 53 | - codigo: 139, | ||
| 54 | - nombre: 'Universidad Mayor De San Andrés', | ||
| 55 | - sigla: 'UMSA', | ||
| 56 | - contexto: 'Universidades Públicas', | ||
| 57 | - años: 20, | ||
| 58 | - nombre_normalizado: 'universidad mayor de san andres', | ||
| 59 | - sigla_normalizada: 'umsa', | ||
| 60 | - codigo_normalizado: '139' | ||
| 61 | - }, | ||
| 62 | - // Objetos de gasto | ||
| 63 | - { | ||
| 64 | - tipo: 'objeto_gasto', | ||
| 65 | - codigo: '25100', | ||
| 66 | - nombre: 'Pasajes', | ||
| 67 | - sigla: null, | ||
| 68 | - contexto: 'Objeto del Gasto · Partida', | ||
| 69 | - nivel: 'partida', | ||
| 70 | - nombre_normalizado: 'pasajes', | ||
| 71 | - sigla_normalizada: '', | ||
| 72 | - codigo_normalizado: '25100' | ||
| 73 | - }, | ||
| 74 | - // Rubros | ||
| 75 | - { | ||
| 76 | - tipo: 'rubro', | ||
| 77 | - codigo: 13000, | ||
| 78 | - nombre: 'INGRESOS POR IMPUESTOS', | ||
| 79 | - sigla: null, | ||
| 80 | - contexto: 'Rubro · Tipo', | ||
| 81 | - nivel: 'tipo', | ||
| 82 | - nombre_normalizado: 'ingresos por impuestos', | ||
| 83 | - sigla_normalizada: '', | ||
| 84 | - codigo_normalizado: '13000' | ||
| 85 | - } | ||
| 86 | -] | ||
| 87 | -``` | ||
| 88 | - | ||
| 89 | -### Fuentes de datos | ||
| 90 | -- **Entidades**: tabla `ppto.clas_institucional` | ||
| 91 | -- **Objetos de gasto**: tabla `ppto.clas_objetos` | ||
| 92 | -- **Rubros**: tabla `ppto.clas_rubros` | ||
| 93 | - | ||
| 94 | -## Columnas de Búsqueda | ||
| 95 | - | ||
| 96 | -### Entidades (clas_institucional) | ||
| 97 | -| Columna | Buscar | Mostrar | | ||
| 98 | -|---------|--------|---------| | ||
| 99 | -| `desc_entidad` | ✓ | ✓ nombre principal | | ||
| 100 | -| `sigla_entidad` | ✓ | ✓ entre paréntesis | | ||
| 101 | -| `desc_area` | ✗ | ✓ contexto | | ||
| 102 | -| `n_gestiones` | ✗ | ✓ "X años de datos" | | ||
| 103 | -| `entidad` | ✗ | para URL | | ||
| 104 | - | ||
| 105 | -### Objetos de gasto (clas_objetos) | ||
| 106 | -| Columna | Buscar | Mostrar | | ||
| 107 | -|---------|--------|---------| | ||
| 108 | -| `desc_objeto` | ✓ | ✓ nombre principal | | ||
| 109 | -| `objeto` | ✓ | ✓ código (monospace) | | ||
| 110 | -| `nivel` | ✗ | ✓ contexto ("Objeto del Gasto · Partida") | | ||
| 111 | - | ||
| 112 | -### Rubros (clas_rubros) | ||
| 113 | -| Columna | Buscar | Mostrar | | ||
| 114 | -|---------|--------|---------| | ||
| 115 | -| `desc_rubros` | ✓ | ✓ nombre principal | | ||
| 116 | -| `rubro` | ✓ | ✓ código (monospace) | | ||
| 117 | -| `nivel` | ✗ | ✓ contexto ("Rubro · Tipo") | | ||
| 118 | - | ||
| 119 | -## Flujo de Búsqueda | ||
| 120 | - | ||
| 121 | -``` | ||
| 122 | -1. CARGA INICIAL | ||
| 123 | - App monta → descarga clasificadores → construye índice Fuse.js | ||
| 124 | - | ||
| 125 | -2. USUARIO ESCRIBE | ||
| 126 | - Input → debounce 250ms → si ≥2 chars → Fuse.search() | ||
| 127 | - | ||
| 128 | -3. RESULTADOS | ||
| 129 | - Fuse devuelve matches → renderizar lista con highlighting | ||
| 130 | - | ||
| 131 | -4. SELECCIÓN | ||
| 132 | - Click o Enter → navegar a URL según tipo | ||
| 133 | -``` | ||
| 134 | - | ||
| 135 | -## Estructura de URLs | ||
| 136 | - | ||
| 137 | -``` | ||
| 138 | -/entidad/[codigo] → /entidad/139 | ||
| 139 | -/objeto/[codigo] → /objeto/25100 | ||
| 140 | -/rubro/[codigo] → /rubro/13000 | ||
| 141 | -``` | ||
| 142 | - | ||
| 143 | -## Formato de Resultados | ||
| 144 | - | ||
| 145 | -Resultados agrupados por tipo de clasificador: | ||
| 146 | - | ||
| 147 | -``` | ||
| 148 | -┌─────────────────────────────────────────────────────┐ | ||
| 149 | -│ 🔍 [Buscar entidad, objeto de gasto o rubro...] │ | ||
| 150 | -├─────────────────────────────────────────────────────┤ | ||
| 151 | -│ ENTIDADES │ | ||
| 152 | -├─────────────────────────────────────────────────────┤ | ||
| 153 | -│ Universidad Mayor De San Andrés (UMSA) │ | ||
| 154 | -│ Universidades Públicas │ | ||
| 155 | -├─────────────────────────────────────────────────────┤ | ||
| 156 | -│ OBJETOS DEL GASTO │ | ||
| 157 | -├─────────────────────────────────────────────────────┤ | ||
| 158 | -│ 25100 Pasajes │ | ||
| 159 | -│ Objeto del Gasto · Partida │ | ||
| 160 | -├─────────────────────────────────────────────────────┤ | ||
| 161 | -│ RUBROS │ | ||
| 162 | -├─────────────────────────────────────────────────────┤ | ||
| 163 | -│ 13000 INGRESOS POR IMPUESTOS │ | ||
| 164 | -│ Rubro · Tipo │ | ||
| 165 | -└─────────────────────────────────────────────────────┘ | ||
| 166 | -``` | ||
| 167 | - | ||
| 168 | -### Diferencias visuales | ||
| 169 | -- **Entidades**: Nombre + (sigla) en primera línea | ||
| 170 | -- **Objetos de gasto**: Código (monospace) + Nombre en primera línea | ||
| 171 | -- **Rubros**: Código (monospace) + Nombre en primera línea | ||
| 172 | - | ||
| 173 | -## Estados del Buscador | ||
| 174 | - | ||
| 175 | -| Estado | Qué mostrar | | ||
| 176 | -|--------|-------------| | ||
| 177 | -| Vacío (< 2 chars) | Placeholder o sugerencias | | ||
| 178 | -| Cargando índice | Spinner / "Cargando..." | | ||
| 179 | -| Buscando | Nada (es instantáneo) | | ||
| 180 | -| Con resultados | Lista de resultados | | ||
| 181 | -| Sin resultados | "No se encontraron resultados para 'xyz'" | | ||
| 182 | -| Error | "Error al cargar datos" | | ||
| 183 | - | ||
| 184 | -## Estructura de Archivos | ||
| 185 | - | ||
| 186 | -``` | ||
| 187 | -src/lib/ | ||
| 188 | -├── components/ | ||
| 189 | -│ └── search/ | ||
| 190 | -│ ├── SearchBox.svelte ← Input + lógica de búsqueda | ||
| 191 | -│ ├── SearchResults.svelte ← Lista de resultados | ||
| 192 | -│ └── SearchResultItem.svelte ← Item individual | ||
| 193 | -├── services/ | ||
| 194 | -│ ├── supabase.js ← Cliente Supabase | ||
| 195 | -│ └── search.js ← Inicialización Fuse.js | ||
| 196 | -├── stores/ | ||
| 197 | -│ └── searchStore.js ← Estado: query, results, loading | ||
| 198 | -├── utils/ | ||
| 199 | -│ └── normalize.js ← Normalización de texto | ||
| 200 | -└── data/ | ||
| 201 | - └── index.js ← Carga y construcción del índice | ||
| 202 | -``` | ||
| 203 | - | ||
| 204 | -## Estado de Implementación | ||
| 205 | - | ||
| 206 | -| Clasificador | Estado | Tabla | | ||
| 207 | -|--------------|--------|-------| | ||
| 208 | -| Entidades | ✅ Implementado | `ppto.clas_institucional` | | ||
| 209 | -| Objetos de gasto | ✅ Implementado | `ppto.clas_objetos` | | ||
| 210 | -| Rubros | ✅ Implementado | `ppto.clas_rubros` | | ||
| 211 | -| Fuente de financiamiento | ⏳ Pendiente | - | | ||
| 212 | -| Geográfico | ⏳ Pendiente | - | | ||
| 213 | - | ||
| 214 | -## Trabajo Futuro | ||
| 215 | - | ||
| 216 | -### Índice pre-computado | ||
| 217 | -Posibilidad de pre-computar el índice en servidor y servir como JSON estático para mejorar tiempo de carga inicial. | ||
| 218 | - | ||
| 219 | -### Migración a servidor | ||
| 220 | -Si el índice supera ~20,000 registros: | ||
| 221 | -1. Habilitar extensión `pg_trgm` en PostgreSQL | ||
| 222 | -2. Crear índices GIN en columnas de búsqueda | ||
| 223 | -3. Cambiar de Fuse.js a queries con `similarity()` o `%` operator | ||
| 224 | -4. El componente de UI se mantiene igual, solo cambia el servicio | ||
| 225 | - | ||
| 226 | ---- | ||
| 227 | - | ||
| 228 | -*Documento de referencia para la implementación del buscador* |
src/routes/descargas/+page.js
0 → 100644
| 1 | +export const ssr = false; |
tablas.md
deleted
100644 → 0
This diff is collapsed. Click to expand it.
-
Please register or login to post a comment