Rafael Lopez

descargas

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*
1 +export const ssr = false;
This diff is collapsed. Click to expand it.