# gastos-europa

Proyecto para consolidar, clasificar y revisar gastos del viaje Europa entre Sebas y Vicky.

## Objetivo
- juntar capturas y texto extraído en un solo lugar
- recalcular totales desde datos parseados, no desde texto del chat
- marcar a quién corresponde cada gasto
- separar viaje vs no-viaje
- dejar una app web persistente para futuras visitas

## Estructura
- `raw/images/` screenshots originales
- `raw/extracted-text.txt` texto extraído/manual de screenshots de Sebas
- `raw/vicky-manual.txt` gastos de Vicky cargados manualmente
- `derived/transactions.json` dataset normalizado principal
- `derived/transactions.csv` export tabular
- `derived/summary.json` agregados calculados
- `data/allocations.json` persistencia server-side de marcas
- `app/build_dataset.py` parser + enriquecimiento + recálculo
- `app/server.py` backend local de la app web
- `analysis.html` frontend principal

## Modelo de datos
Cada movimiento queda con:
- `paid_by`: `S` o `V`
- `amount_usd`: monto numérico final
- `type`: `expense`, `income`, `zero`
- `trip_scope`: `europe_trip` o `non_trip`
- `category_guess`
- `allocation`: clasificación manual (`S->S`, `S->V+S`, `S->V`, `V->V`, `V->V+S`, `V->S`)
- `description`, `description_confidence`, `description_source`

## Reglas actuales importantes
- totales y subtotales salen de `derived/transactions.json`, regenerado por `app/build_dataset.py`
- no se suman montos “a ojo” desde el chat
- fees bancarios quedan separados
- `Deel Balance` e ingresos/transferencias no cuentan como gasto
- Airbnb de las capturas Deel `photo-1389..1391` cuenta como alojamiento del viaje Europa
- movimientos `0.00` quedan como `type=zero` y no afectan sumas
- puede haber duplicados entre pending/posted de las capturas bancarias originales; revisar antes de cierre final

## App web
- URL pública: `/gastos-europa/`
- URL completa: `https://ballbox-first.emperor-ratio.ts.net/gastos-europa/`
- Backend local: `127.0.0.1:18896`
- Persistencia de marcas: `data/allocations.json`
- Service: `gastos-europa.service`

## Filtros soportados
UI:
- búsqueda
- scope
- tipo
- quién pagó
- categoría
- clasificado sí/no

Query string:
- `q`
- `trip`
- `typ`
- `paidBy`
- `cat`
- `classified`

Ejemplos:
- `?classified=no`
- `?paidBy=S&classified=no`
- `?trip=europe_trip&paidBy=V&classified=no`

## Operación
Regenerar dataset después de tocar fuentes:

```bash
python3 /home/sebas/work/gastos-europa/app/build_dataset.py
```

Ver backend:

```bash
systemctl status gastos-europa.service
curl http://127.0.0.1:18896/healthz
```

## Pendientes típicos al volver
- deduplicar pending/posted
- revisar descripciones de baja confianza
- cargar más gastos de Vicky o Sebas
- exportar balance neto final entre ambos
