caso de estudio · 2026

Aplicación a medida / PWA
Finanzas personales

Finanzas personales

01

el reto

Necesitaba una aplicación de finanzas propia: que siguiera mi dinero a mi manera y, sobre todo, que no me obligara a pagar la mensualidad de una aplicación de terceros. Las aplicaciones del mercado resuelven el caso medio, y el mío no lo es. Vivo en París y cobro en euros, pero sigo teniendo cuentas y deudas en pesos colombianos; declaro en Francia como asalariado y auto-entrepreneur a la vez, con obligaciones también en Colombia. Ninguna herramienta genérica mezcla bien tres monedas, ni entiende que comprar un ETF dentro del bróker no es un gasto. Y el problema de fondo de toda app de finanzas no son los gráficos, es hacer el seguimiento y anotar los movimientos. Si registrar un café obliga a abrir la app y elegir cuenta, categoría y fecha, a la tercera semana se deja de hacer y los números dejan de valer. El verdadero reto era que apuntar no costara casi nada.

02

la solución

Construí una aplicación completa para mi propio uso, con la estética de mi marca personal y de este sitio: el mismo mosaico lima y gris, sin mayúsculas, instalable en el móvil como una app más. Seis secciones (resumen, cuentas, ingresos y gastos, deudas, inversiones y asesor) sobre un modelo de datos pensado para mi caso: cada importe se guarda en su moneda y solo se convierte al mostrarlo, con tipos de cambio del día; los traspasos entre cuentas propias y los aportes a inversión no cuentan como gasto; y un gasto pagado con una cuenta es una sola pareja enlazada, entre por donde entre. Para que apuntar no cueste, hay cuatro entradas: el formulario, una caja de texto libre que la IA convierte en filas editables, los pagos con Apple Pay, que llegan solos a través de un atajo del iPhone, y Siri, al que le dicto el gasto. Encima, dos asesores con IA, uno financiero y otro fiscal, que leen mis cifras del mes y responden con un resumen, no con un sermón.

03

el resultado

La uso a diario, en el ordenador y en el teléfono. Los pagos con Apple Pay aparecen en la app segundos después de pagar, marcados «por revisar»; un gasto en efectivo se lo dicto a Siri sin abrir nada; y el asesor me dice cómo voy con mis propias cifras. Sin ninguna suscripción: la IA corre en el plan gratuito de Groq, los datos en Firebase y el servidor en mi propio VPS con Coolify, junto a este sitio. Es una app privada: solo entra mi cuenta de Google, con dos candados que se comprueban por separado, las reglas de Firestore y el servidor. 12 065 líneas de TypeScript, 30 commits y 37 tests sobre la aritmética del dinero, que es la única parte en la que un error no se ve en pantalla hasta que ya ha pasado.

dimensión

el proyecto en cifras

12 065

líneas de TypeScript, app y servidor

37

tests sobre la aritmética del dinero

3

monedas: euro, dólar y peso colombiano, convertidas al mostrar

4

maneras de apuntar un gasto

2

asesores con IA: financiero y fiscal

0 €

de suscripción al mes

lo que cambia

coste recurrente

Ninguno. Sin mensualidad de una app de terceros: la IA va en el plan gratuito de Groq y el servidor comparte VPS con este sitio.

apuntar

Casi sin fricción. Apple Pay entra solo, Siri toma el dictado y el texto libre se convierte en filas. Apuntar dejó de ser la parte que se abandona.

a mi medida

Tres monedas, deudas en pesos, doble fiscalidad Francia–Colombia y un bróker cuyas compras no son gasto. Nada de eso cabía en una app genérica.

móvil

pensada para el teléfono

cifras simuladas

Donde más se usa: la llevo a diario en el móvil. Instalable como PWA, revisada hasta 360 px de ancho sin scroll horizontal, con la navegación en una barra inferior de seis iconos. A la izquierda, el resumen del mes; en el centro, el registro rápido; a la derecha, las inversiones.

captura

cuatro maneras de apuntar un gasto

Una app de finanzas vale lo que valen sus datos, y los datos dependen de que apuntar no dé pereza. Por eso la mitad del trabajo no está en las pantallas, sino en las entradas: cuatro caminos, de más a menos esfuerzo, que acaban todos en el mismo guardado.

  1. 01

    el formulario

    El camino clásico, con cuenta, categoría, fecha y notas. Un gasto pagado con una cuenta crea a la vez el gasto, el movimiento de la cuenta y el nuevo saldo en una sola escritura atómica: o se guarda todo, o nada.

  2. 02

    texto libre

    «almuerzo 12 revolut y uber 8,50 ayer». El servidor se lo pasa a un modelo pequeño que devuelve JSON con varios gastos, fechas relativas y la cuenta nombrada; lo valida, y la app lo muestra en filas editables con lo que queda del presupuesto de cada categoría. Si la IA no responde, cae a un análisis local: el primer número y los nombres de categoría y cuenta que aparezcan en el texto.

  3. 03

    apple pay, automático

    Una automatización de Atajos del iPhone salta con cada pago de Wallet y envía importe, comercio y tarjeta al servidor. Este asocia la tarjeta a la cuenta por su nombre, pide la categoría a la IA y guarda gasto, saldo y movimiento en una transacción, marcado «por revisar». En la app aparecen la pastilla «por revisar · ok» y un aviso en las notificaciones.

  4. 04

    siri, al dictado

    «Oye Siri, apunta un gasto», y lo que dicte pasa por el mismo intérprete que el texto libre y por el mismo guardado que Apple Pay. El servidor responde con una frase corta que el atajo lee en voz alta, para saber qué se ha apuntado sin mirar la pantalla.

funcionalidad

lo que hay dentro

resumen

« tu mes »
  • Cuatro cifras del mes seleccionado (disponible, ingresos, gastos y balance), en la moneda que elija: la conversión es solo de lectura.
  • Presupuestos por categoría con su barra y lo que queda o lo que sobra, y los últimos gastos con categoría y fecha.
  • Debajo, la distribución del mes, un diagnóstico de salud financiera y un bloque plegable de análisis: patrimonio, proyección a doce meses, reto de ahorro y categorías.
  • Exportación a CSV de ingresos, gastos, deudas o todo junto, preparada para que Excel respete las tildes.
El resumen del mes. Los mismos tokens que deeagonal.com: fondo lima, losetas gris oscuro separadas por juntas de 4 px y ni una mayúscula.

ingresos y gastos

« gastos variables · gastos fijos · ingresos »
  • Gastos variables, fijos e ingresos, cada uno en su moneda.
  • Cuatro estrategias de presupuesto para el gasto variable: regla 50/30/20, frugal, flujo de caja real o límite manual, con el plan del mes desglosado y un aviso cuando se supera.
  • Cada movimiento lleva un tipo (variable, fijo, deuda o inversión) que se cambia desde su pastilla; reclasificarlo mantiene la pareja gasto ⇄ movimiento sin duplicar nada.
Con la regla 50/30/20, el límite sale de los ingresos menos fijos y deudas, y la barra dice cuánto se ha consumido.

cuentas, deudas e inversiones

« cuentas · deudas · inversiones »
  • Cuentas bancarias y efectivo, cada una en su moneda, con traspasos entre ellas que no cuentan ni como ingreso ni como gasto.
  • Deudas con interés, pago mínimo y día de cobro, ordenables por interés para atacar primero la más cara, y una calculadora de amortización.
  • Inversiones por clase de activo, con proyección de interés compuesto y metas. El movimiento se registra con el saldo que marca el bróker y la app deduce la diferencia: rendimiento, aporte o retiro.
Distribución por clase de activo y una proyección a quince años con rendimiento, horizonte y aportación ajustables.

asesor

« asesor financiero · planificación fiscal »
  • Un asesor financiero que recibe el resumen del mes seleccionado, con el gasto por categoría, ingresos y gastos reales, saldos y deudas, y responde siempre empezando por «En resumen», con tres secciones como máximo y tablas pequeñas.
  • Preguntas rápidas de un toque y el historial de la consulta más nueva a la más antigua, con las anteriores plegadas en su línea de resumen.
  • Un asesor fiscal que conoce los regímenes de España, Francia, Estados Unidos y Colombia, y la doble residencia: salarié y auto-entrepreneur a la vez, convenio Francia–Colombia, declaración de activos en el exterior.
  • Los prompts van compactados, sin ids, fechas técnicas ni campos vacíos, y el historial se limita a diez turnos, para caber en el plan gratuito.
El asesor, sobre las cifras del mes: el resumen arriba y el diagnóstico debajo, sin emojis y con importes redondeados.

pantallas

el resto de la aplicación

Cuentas: el saldo de cada una en su moneda, convertido a la de lectura para poder compararlas.
El asesor fiscal parte de un perfil: país, régimen (aquí salarié y auto-entrepreneur a la vez) y, si hace falta, un segundo país de declaración.

stack

lo que hay debajo

Interfaz

React 19 · TypeScript 5.8 · Vite 6 · Tailwind CSS 4 con el design system de deeagonal · Motion · Recharts 3 · react-markdown con tablas GFM · PWA con vite-plugin-pwa

Datos

Firebase Auth con Google · Firestore con caché persistente en IndexedDB, también sin conexión · reglas limitadas a un único email verificado · firebase-admin en el servidor

IA e integraciones

Groq por su API compatible con OpenAI, sin SDK · gpt-oss-120b para los asesores, gpt-oss-20b para interpretar gastos y como respaldo ante límite de uso · Atajos de iOS (Wallet y Siri) · ExchangeRate-API

Servidor / despliegue

Express 4 · bundle con esbuild · Docker multietapa sobre node:22-slim · Coolify en un VPS de Hostinger, con healthcheck · Vitest

arquitectura

tres capas y dos candados

La app lee y escribe sus datos directamente en Firestore; el servidor existe solo para lo que no puede vivir en el navegador: las claves de la IA, la cuenta de servicio de los atajos y los tipos de cambio. Y como se trata de mi dinero, todo tiene dos candados independientes: las reglas de Firestore solo abren mi árbol de datos a mi email verificado, y cada ruta /api del servidor comprueba por su cuenta el token de sesión y el email.

Cliente

PWA React · un único usuario

Toda la interfaz. La caché local de Firestore abre la app al instante con los últimos datos, también sin conexión, y se borra del dispositivo al cerrar sesión. Al desplegar, la app abierta se recarga sola con la versión nueva.

↕ Firestore directo, bajo reglas · /api con el ID token de Firebase

Servidor

Express en Docker · Coolify

Asesores e intérprete de gastos, tipos de cambio con caché de 6 h y dos fuentes de respaldo, endpoints de los atajos y un proxy de /__/auth para que el login de Google salga del propio dominio en la app instalada.

↕ las claves solo viven en el servidor

Servicios

Firebase

Auth con Google y Firestore. Reglas: solo mi email verificado, solo mi propio árbol.

Groq · ExchangeRate-API

Modelos abiertos para asesorar e interpretar, con respaldo ante límite de uso. Tipos de cambio diarios, con atribución.

Los atajos del iPhone no tienen sesión de Firebase: usan su propio token, de al menos 32 caracteres y comparado en tiempo constante, y el servidor escribe con firebase-admin en mi árbol de datos.

ingeniería

seis problemas reales y cómo se cerraron

Todos aparecieron usando la app con mi dinero, no en pruebas. En una app de finanzas los errores graves no se ven: la pantalla enseña una cifra perfectamente formateada que está mal.

un atajo que decía «hecho» y no guardaba nada

integración
síntoma
La automatización de Apple Pay terminaba sin error, pero el gasto no aparecía en la app y el servidor no registraba nada.
causa
La acción «Obtener contenido de URL» de Atajos usa GET por defecto. El GET no encontraba la ruta de la API y caía en la ruta comodín de la aplicación, que respondía 200 con el HTML de la página: para el atajo, todo bien.
solución
Las rutas de los atajos responden 405 a cualquier método que no sea POST, con un mensaje que dice cuál usar, y cada llamada deja una línea de registro con su motivo: sin token, token distinto, importe no válido o gasto guardado.

el mismo gasto, dos veces

datos
síntoma
Los presupuestos del mes no cuadraban: según por dónde se apuntara un gasto, contaba dos veces o no contaba.
causa
Un gasto pagado con una cuenta podía entrar como gasto variable o como movimiento de la cuenta, y eran registros independientes. Los presupuestos solo leían los primeros, y yo apunto casi todo como movimiento.
solución
Ahora son una pareja enlazada, en la que cada lado guarda el id del otro, que se crea, se edita y se borra junta en una escritura atómica, entre por el formulario, por el registro rápido o por Apple Pay. El gasto del mes une las dos fuentes sin contar nada dos veces, y las parejas antiguas sin ids se reconocen por cuenta, fecha, nombre y categoría. Con test.

cambiar de moneda reescribía el dinero

moneda
síntoma
Al cambiar la moneda base, los importes guardados se recalculaban con un tipo fijo y se sobrescribían.
causa
La moneda base se trataba como un dato, cuando es una preferencia de lectura.
solución
Cada importe se guarda en su moneda (la de su cuenta, en los movimientos) y solo se convierte al mostrarlo, con tipos del día y valores de reserva marcados como antiguos si la fuente falla. Los presupuestos llevan su propia moneda. Regla escrita: nunca reescribir un importe al cambiar de moneda.

comprar un etf no es gastar

modelo
síntoma
Cada compra dentro del bróker aparecía como gasto y hundía el balance del mes.
causa
Un movimiento de salida solo podía ser gasto o traspaso.
solución
Un cuarto tipo, inversión: baja el saldo de la cuenta, pero no cuenta en ningún total, presupuesto ni en lo que ve el asesor. Y en inversiones el formulario pide el saldo que marca el bróker, no la diferencia: la app la calcula y decide si es rendimiento, aporte o retiro.

pesos y dólares con el mismo símbolo

moneda
síntoma
Un importe en pesos colombianos y otro en dólares se veían idénticos: los dos con «$».
causa
Es el símbolo local de las dos monedas.
solución
El peso se muestra como «COP», también en la frase de confirmación del atajo de Apple Pay.

safari ampliaba la página al escribir

móvil
síntoma
En el iPhone, tocar un campo ampliaba la página y la dejaba así, desbordada hacia la derecha.
causa
Safari hace zoom al enfocar un campo con letra de menos de 16 px.
solución
Dos defensas, y hacen falta las dos: campos a 16 px en pantallas táctiles y maximum-scale=1 en el viewport. El pellizco para ampliar sigue funcionando.

código

dónde vive la complejidad

App.tsx
10 461
server.ts
942
services/aiService.ts
196
lib/spend.ts
150
AuthContext.tsx
138
5 archivos restantes
178

Líneas por archivo, de 12 065 en total. Toda la interfaz vive en un único App.tsx de más de diez mil líneas: es la deuda técnica declarada del proyecto. Lo que no se puede tocar sin test, es decir meses, monedas, emparejamiento de gastos y movimientos de inversión, ya salió a src/lib/ con sus 37 tests; partir App.tsx por pantallas es lo siguiente.

criterio

lo que me llevo

apuntar es el producto

Los gráficos son la parte fácil. Lo que hace que una app de finanzas sirva es que apuntar cueste un gesto: todo lo demás depende de eso.

la moneda es de lectura

Un importe se guarda en su moneda, una sola vez. Convertir es cosa de la pantalla; cualquier otra regla acaba reescribiendo dinero.

los errores de dinero no se ven

Una cifra mal calculada sale tan bien formateada como una correcta. Por eso la aritmética vive fuera de la interfaz, con tests, y el asesor recibe los mismos totales que yo veo.

Las cifras de todas las capturas son ficticias: cada importe está multiplicado por un mismo factor, así que cuadran entre sí, pero no son las mías. Aplicación privada, repositorio privado.

Instalable (PWA) App móvil Conexión con APIs Registro automático de pagos con Apple Pay Dictado de gastos a Siri Asesor financiero con IA Multimoneda
tecnologías

React·TypeScript·Vite·Tailwind CSS·PWA·Express·Firebase·Groq·Vitest·Node.js·Docker

¿un proyecto
parecido?

hablemos