App mobile-first para registrar gastos por categoría, sin enfoque contable. Permite cargar una foto de un recibo/comprobante y usa un modelo con visión (vía OpenRouter) para pre-llenar el monto, comercio, fecha y categoría sugerida — siempre confirmables antes de guardar.
- Backend: PocketBase (SQLite + auth + almacenamiento de archivos, un solo binario).
- Frontend: Next.js (App Router) + Tailwind CSS, pensado como PWA instalable.
- Extracción de recibos: modelo con visión vía OpenRouter (SDK
openaiapuntando a su API), llamado solo desde el servidor (/api/extract-receipt). El modelo se elige por env var (OPENROUTER_MODEL), así que se puede cambiar o complementar sin tocar código.
pocketbase/ Dockerfile + migraciones (schema versionado como código)
web/ App Next.js
docker-compose.yml Levanta ambos servicios juntos
- Backend:
cd pocketbase && docker build -t orden-fin-pb . && docker run -p 8090:8090 -v pb_data:/pb/pb_data orden-fin-pbLas migraciones crean las coleccionescategories(con 8 categorías precargadas) yexpensesautomáticamente al primer arranque. - Entra a
http://localhost:8090/_/, crea el superusuario admin de PocketBase, y luego crea un registro en la colecciónusers(ese es el usuario con el que inicias sesión en la app — distinto del superusuario admin). - Frontend:
cd web && cp .env.example .env.local(ajustaOPENROUTER_API_KEYyOPENROUTER_MODEL), luegonpm install && npm run dev. - Abre
http://localhost:3000, inicia sesión con el usuario creado en el paso 2.
cp .env.example .env # completa OPENROUTER_API_KEY y OPENROUTER_MODEL
docker compose up --build
PocketBase queda en :8090, la app en :3000.
- Crea un nuevo recurso tipo Docker Compose en Coolify apuntando a este repo (usa
docker-compose.ymlde la raíz). - Define las variables de entorno del proyecto en Coolify:
NEXT_PUBLIC_PB_URL(la URL pública que le asignes al serviciopocketbase, ej.https://pb.tudominio.com),OPENROUTER_API_KEY/OPENROUTER_MODEL, yPB_APP_EMAIL/PB_APP_PASSWORD(credenciales del usuario de la app, usadas server-side por/api/mcp— ver más abajo).- Importante:
NEXT_PUBLIC_PB_URLse hornea en el build del frontend (es una env var pública de Next.js), así que debe estar disponible como build arg al construirweb, no solo en runtime.
- Importante:
- Asigna dominios/HTTPS a cada servicio (
pocketbaseyweb) desde Coolify. - Monta un volumen persistente para
pb_data(ya está declarado en el compose) para que los datos sobrevivan a los redeploys. - Tras el primer deploy, entra a
https://pb.tudominio.com/_/, crea el superusuario admin y el usuario de la app (mismo paso 2 de desarrollo local).
El volumen de datos usa el nombre ${PB_DATA_VOLUME:-orden_fin_pb_data} en vez de dejar que Coolify lo nombre solo — así se evita que dos recursos de Coolify (uno por rama) terminen compartiendo o pisando el mismo volumen de PocketBase por accidente. Si vas a tener staging y producción en el mismo servidor:
- En el recurso de producción, define la env var
PB_DATA_VOLUME=orden_fin_pb_data_prod. - En el recurso de staging, define
PB_DATA_VOLUME=orden_fin_pb_data_staging.
Con eso cada entorno crea y usa su propio volumen Docker, sin importar cómo Coolify nombre el proyecto internamente. Verifica en docker volume ls (por SSH al VPS) que efectivamente aparezcan como dos volúmenes distintos antes de meter datos reales en staging.
La app expone un servidor MCP de solo lectura en /api/mcp (transporte Streamable HTTP), para que un agente en otro servidor —como Hermes— pueda consultar tus gastos sin nunca poder escribir/borrar nada.
- Inicia sesión en la app y entra a Ajustes (ícono ⚙️ en el header) →
/ajustes. - Ponle un nombre a la clave (ej. "Hermes VPS") y genera una API key. El token completo (
of_...) se muestra una sola vez — cópialo ahí mismo, PocketBase solo guarda su hash. - Configura tu agente MCP para apuntar a
https://tu-dominio.com/api/mcpconAuthorization: Bearer <token>. Ejemplo de config de Hermes:mcp_servers: orden_fin: url: "https://tu-dominio.com/api/mcp" headers: Authorization: "Bearer of_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- Si una clave se filtra o ya no la usas, revócala desde
/ajustes— el endpoint la rechaza al siguiente request, sin redeploy.
Tools disponibles: list_expenses (filtra por fecha/categoría/etiqueta), get_summary (totales agrupados por categoría o etiqueta), list_categories, list_tags, list_subscriptions. No hay tools de escritura — mantiene el principio del proyecto de que el usuario siempre confirma antes de guardar.
Requiere las env vars PB_APP_EMAIL/PB_APP_PASSWORD (ver arriba) — el servidor las usa para autenticarse como el usuario de la app y así validar claves y consultar datos.
- La versión de PocketBase está fijada en
pocketbase/Dockerfile(ARG PB_VERSION). Revisa releases y actualízala si quieres una más reciente. - Los íconos de
web/public/icons/icon.svgson un placeholder simple. Para que la app se vea bien instalada en iOS (que requiere PNG, no SVG, para el ícono de home screen), genera un set real de íconos (ej. con realfavicongenerator.net) y reemplázalos antes de compartir la app fuera de tu propio celular. - El middleware solo verifica que exista la cookie de sesión de PocketBase, no la valida contra el servidor en cada request — suficiente para uso personal, pero no es una barrera de seguridad fuerte si más adelante agregas más usuarios.
- Fuera de alcance por ahora (a propósito): presupuestos, reportes/gráficos, multi-moneda, multi-usuario.
Resumen de mejoras mayores por período (no exhaustivo — ver git log para el detalle completo).
- Registro de gastos por categoría con extracción automática de recibos (monto, comercio, fecha, categoría sugerida) vía Claude vision, siempre confirmable antes de guardar.
- Flujo de edición y borrado de gastos.
- Deploy parametrizado para correr staging y producción como recursos separados en el mismo VPS (puertos y volumen de datos independientes).
- Sistema de tags: crear, asignar a gastos y filtrar el listado por tag.
- Desglose de gasto por tag en la página de resumen.
- Se removió
capture="environment"del input de subida de recibos: en mobile forzaba abrir la cámara directo y ocultaba la opción de elegir desde la galería (en desktop el atributo se ignora, por eso el bug no era visible ahí). Ahora el selector nativo de archivos se comporta igual en todas las plataformas.
- Endpoint
/api/mcp(solo lectura) para que agentes externos (ej. Hermes) consulten gastos, categorías y etiquetas vía Streamable HTTP. - Página
/ajustespara generar, listar y revocar las API keys que autentican esas conexiones, sin necesidad de tocar el servidor — rotar una clave filtrada toma un click.
- Reemplazado
@anthropic-ai/sdkpor el SDKopenaiapuntando a OpenRouter (OPENROUTER_API_KEY+OPENROUTER_MODEL), para poder cambiar o complementar el modelo de visión sin tocar código.
- Nueva colección
subscriptions(dueño, monto, frecuencia de cobro, próxima renovación, estado) con relación opcional desdeexpenses, para vincular un gasto puntual a la suscripción que lo originó. - Sección
/suscripciones: listado con total mensual estimado, alerta de renovaciones dentro de 7 días, alta/edición/borrado, y botón "Marcar como renovada" que avanza la fecha según el ciclo de cobro. - El formulario de gasto ahora permite (opcionalmente) asociar el gasto a una suscripción existente.
- Nueva tool de MCP
list_subscriptionspara que agentes externos también puedan consultarlas. - Atajo "Convertir en suscripción" desde el detalle de un gasto ya registrado: pre-llena nombre/monto/próxima renovación y vincula el gasto automáticamente al guardar, sin pasar por crear-la-suscripción-y-luego-editar-el-gasto.
- Sugerencia automática de suscripción: si el comercio de un gasto nuevo coincide con el nombre de una suscripción activa (ej. "Netflix" un mes después), el formulario pre-selecciona esa suscripción — el usuario igual confirma al guardar, no se vincula nada solo.