# 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 (`<p>`, `<span style="...">`, `<strong>`). 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(/&nbsp;/g, ' ')          // entidades HTML
    .replace(/&amp;/g, '&')
    .replace(/&lt;/g, '<')
    .replace(/&gt;/g, '>')
    .replace(/&quot;/g, '"')
    .replace(/&#39;/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<any>`. 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<AlphaUserRecord[]> {
    return invoke('get_users')
  },
  saveUser(user: AlphaUserRecord): Promise<number> {
    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 `<img>`

**Problema**: El SVG del logo de Alpha se veía negro en tema oscuro. `<img>` no permite `currentColor`.

**Intentos**:
1. `<img class="dark:invert">` — no funcionó en todos los casos
2. Componente Vue inline con `fill="currentColor"` — funcionó pero era complejo
3. Al final, `<img class="dark:invert">` fue suficiente una vez corregido el path

**Lección**: Para SVGs simples, `<img>` 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
<Card class="bg-gradient-to-t from-primary/5 to-card shadow-xs dark:bg-card">
```

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<string, string> = {
  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 | `<img>` 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`)
