# Alpha → RUMBO — Decisiones y Aprendizajes > Documento vivo. Cada patrón, utilidad y decisión de Alpha que se reutilizará en RUMBO. > K-20: Documentar learnings → feed a RUMBO. **Actualizado**: 2026-05-26 --- ## 1. Utilidades TypeScript ### 1.1 Limpieza de HTML (`clean-html.ts`) **Problema**: KAPPA devuelve descripciones con HTML inline (`

`, ``, ``). RUMBO recibirá contenido similar de múltiples fuentes (actas .docx, correos, web). **Solución**: ```typescript // src/services/clean-html.ts export function stripHtml(html: string): string { return html .replace(/<[^>]*>/g, '') // eliminar tags .replace(/ /g, ' ') // entidades HTML .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, "'") .replace(/\s+/g, ' ') // normalizar espacios .trim() } ``` **Dónde usarlo en RUMBO**: - Pipeline de ingesta: después de parsear .docx, .html, o APIs que devuelvan HTML - Antes de enviar texto a la IA (DeepSeek) para ahorrar tokens - Antes de guardar en SQLite/Turso **Alternativas evaluadas**: DOMParser (requiere DOM, no disponible en Node/SSR), cheerio (dependencia extra). Regex simple es suficiente para el 95% de los casos. --- ### 1.2 Puente Tauri ↔ Frontend (`tauri-db.ts`) **Problema**: `invoke()` de Tauri es tipado como `Promise`. Sin tipos, cada llamada requiere casting manual. **Solución**: Un archivo de servicio que envuelve todos los comandos Tauri con tipos explícitos: ```typescript export const tauriDb = { getUsers(): Promise { return invoke('get_users') }, saveUser(user: AlphaUserRecord): Promise { return invoke('save_user', { user }) }, // ... todos los comandos tipados } ``` **Por qué sirve para RUMBO**: - Mismo patrón con los comandos de transcripción, documentos, etc. - Un solo archivo = una sola fuente de verdad de la API Rust↔TS - Facilita el autocompletado en el IDE --- ### 1.3 Store Pattern (Pinia + sync bidireccional) **Problema**: Datos vienen de KAPPA (remoto) pero se extienden localmente (Turso). Hay que mergear ambas fuentes. **Solución en `users.ts`**: ```typescript async function fetchAll() { const [rawUsers, page1, localUsers, localCells] = await Promise.all([ kappa.getUsers(), // remoto kappa.getEmployees(1), // remoto tauriDb.getUsers(), // local (Turso) tauriDb.getCells(), // local (Turso) ]) const localMap = new Map(localUsers.map(u => [u.id, u])) users.value = buildUsers(rawUsers, employees.value, localMap) syncUsersToTurso(users.value) // persistir merge } ``` **Patrón**: Fetch remoto + fetch local → merge (local pisa remoto para campos extendidos) → sync inverso. **Para RUMBO**: Mismo patrón con: - KAPPA API (remoto) + SQLite (local) para HUs - OpenRouter (remoto) + caché local para respuestas IA - Archivos locales + metadatos en SQLite --- ### 1.4 AG Grid + Tema Shadcn **Problema**: Necesitábamos una tabla potente (filtros, ordenamiento, paginación) pero con el estilo visual de shadcn-vue. **Solución**: AG Grid Community + archivo CSS que mapea variables shadcn: ```css /* src/assets/ag-grid-alpha.css */ .ag-theme-alpha-shadcn { --ag-background-color: var(--card); --ag-header-background-color: var(--muted); --ag-border-color: var(--border); --ag-row-hover-color: var(--accent); --ag-font-family: var(--font-sans); /* ... */ } ``` **Importante**: En Vite, importar AG Grid CSS directamente en `main.ts` (no con `@import` en CSS), porque Vite procesa mejor los imports JS: ```typescript // main.ts import 'ag-grid-community/styles/ag-grid.css' import './assets/ag-grid-alpha.css' ``` **Para RUMBO**: Usar AG Grid para tablas de HUs, Work Items, métricas. El tema se reutiliza cambiando solo el nombre de clase. --- ### 1.5 SVG Logo Inline vs `` **Problema**: El SVG del logo de Alpha se veía negro en tema oscuro. `` no permite `currentColor`. **Intentos**: 1. `` — no funcionó en todos los casos 2. Componente Vue inline con `fill="currentColor"` — funcionó pero era complejo 3. Al final, `` fue suficiente una vez corregido el path **Lección**: Para SVGs simples, `` con `dark:invert` basta. Para SVGs que necesitan heredar color del tema, crear componente Vue con el SVG inline usando `fill="currentColor"`. --- ## 2. Decisiones de Arquitectura ### 2.1 SQLite local-first con sync a remoto | Fuente | Dirección | Frecuencia | |--------|-----------|------------| | KAPPA → Turso | Pull | On-demand (al abrir vista) | | KAPPA ← Turso | Push | Solo campos locales (rol, célula) | | Turso ↔ UI | Bidireccional | En tiempo real (reactivo) | **Para RUMBO**: Mismo modelo. La fuente de verdad es el archivo local. KAPPA es solo un espejo para compartir datos entre máquinas. ### 2.2 Limpieza de datos en el frontend **Decisión**: Limpiar HTML en TypeScript (no en Rust). **Razón**: - Las APIs externas (KAPPA) se consumen desde TS vía `fetch()` - La limpieza es transformación de presentación, no de negocio - Rust solo recibe datos ya limpios para persistir **Para RUMBO**: Limpiar en el pipeline de ingesta (TypeScript), antes de pasar a Rust para transcripción o a OpenRouter para análisis. ### 2.3 Tablas separadas vs JSON embebido **Decisión**: Usar tablas relacionales para usuarios, células, proyectos. No JSON embebido. **Razón**: - SQLite soporta JOINs eficientes - Los datos deben ser consultables desde DBeaver/externos - Facilita reportes y métricas (SQL directo) **Para RUMBO**: Mantener schema relacional. No caer en "guardar todo como JSON" por comodidad. --- ## 3. Patrones de UI ### 3.1 Card con degradado sutil ```html ``` Degradado en modo claro, color sólido en oscuro. Tomado del bloque `dashboard-01` de shadcn. ### 3.2 Layout de vista: Stats → Cards → Tabla ``` ┌─ Header (título + badge) ──────────┐ ├─ Stats (tarjetas por categoría) ───┤ ├─ Cards (vista principal) ──────────┤ └─ AG Grid (tabla completa) ─────────┘ ``` Aplicado en UsersView. Reutilizable para HUs, proyectos, documentos. ### 3.3 Badges de rol por color ```typescript const badgeColors: Record = { BA: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400', DEV: 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400', PM: 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400', // ... } ``` **Para RUMBO**: Mismo patrón para estados de HU (backlog, in progress, done), prioridades, tipos de work item. --- ## 4. Lecciones aprendidas ### 4.1 Rust warnings no son errores Los warnings de Rust (variables no usadas, structs sin construir) no impiden que la app compile y ejecute. Solo indican código que puede limpiarse. ### 4.2 DBeaver + SQLite con espacios en path macOS con home en volumen externo produce paths con espacios. DBeaver requiere path sin espacios. Solución: symlink a `/tmp/`. ### 4.3 AG Grid en Vite El CSS de AG Grid debe importarse en `main.ts` (JS import), no con `@import` en CSS. La razón es que Vite resuelve mejor los módulos JS que los `@import` de node_modules. ### 4.4 iCloud sync no es git Los archivos en iCloud se sincronizan automáticamente, pero `node_modules/` y `src-tauri/target/` deben estar en `.gitignore`. Cada máquina necesita `bun install` y `cargo build` propios. --- ## 5. Lo que NO funcionó | Intento | Resultado | Alternativa | |---------|-----------|-------------| | DOMParser para limpiar HTML | Requiere DOM, error en SSR | Regex simple (`stripHtml`) | | `@import` de AG Grid en CSS | Vite no lo resolvió | `import` en `main.ts` | | `sharp` con Bun | Error de binario nativo | Python PIL (ya instalado) | | Pasar SVG como componente | Complejo, muchos paths | `` con `dark:invert` | | Driver LibSQL en DBeaver | Pide token (es para Cloud) | Driver SQLite clásico | --- ## 6. Checklist para RUMBO Cosas que ya están resueltas en Alpha y RUMBO debe heredar: - [ ] Utilidad `stripHtml()` (`clean-html.ts`) - [ ] Patrón `tauri-db.ts` (puente tipado Rust↔TS) - [ ] Tema AG Grid + shadcn (`ag-grid-alpha.css` → `ag-grid-rumbo.css`) - [ ] Store pattern con merge remoto + local - [ ] Schema SQLite relacional (no JSON) - [ ] Card con degradado sutil - [ ] Badges de estado/rol por color - [ ] Layout Stats → Cards → Tabla - [ ] Import AG Grid CSS en `main.ts` - [ ] SVG logo con `dark:invert` - [ ] Documentación de métricas PMI (`metricas_pmi.md`)