Saltar al contenido
Proyectos

quienpagapp

Una PWA sin registro para dividir gastos en pesos y dólares. Los grupos viven detrás de un link secreto que compartís por WhatsApp, y los tickets se leen automáticamente con OCR asistido por IA.

Año
2026
Rol
Diseño, desarrollo
Stack
TypeScript, Next.js, Tailwind CSS, Drizzle, Postgres, Cloudflare R2, Gemini, Playwright
Abrir la app

Cuentas de bar de los viernes y almuerzos de oficina, divididos en pesos uruguayos y dólares, entre gente que no va a instalar otra app ni crear otra cuenta. quienpagapp hace exactamente eso y nada más: un grupo es un link secreto que pegás en el chat de WhatsApp, y cualquiera que lo tenga puede cargar un gasto.

Sin cuentas, a propósito

No hay tabla de usuarios. El ID de un grupo es un nanoid de 21 caracteres, unos 128 bits de espacio, así que los links no se pueden enumerar. Quién sos dentro de cada grupo vive en el local storage del navegador, junto con la lista de grupos que visitaste. Login por SMS y magic link se consideraron y se descartaron: costo y fricción sin beneficio a esta escala.

Manejo del dinero

Los saldos en UYU y USD se llevan por separado, sin tipos de cambio ni conversiones. Los montos se guardan como NUMERIC(12,2), nunca como float. Las partes se precalculan al crear o editar un gasto, así que un saldo es una suma y no un recálculo. Las deudas se muestran como quién le debe a quién según quién pagó, sin una pasada global de “simplificar deudas”, porque la respuesta predecible le gana a la óptima cuando cuatro amigos están cerrando la cuenta del bar. Los borrados son lógicos, así que el historial sobrevive. Cada participante puede listar sus medios de cobro, MercadoPago, BROU, Prex o texto libre, para que saldar quede a un toque del saldo.

Tickets

Sacás una foto del ticket y Gemini lo lee: total, moneda y líneas con cantidades. Eso convierte la división por línea, donde cada ítem va a quienes lo consumieron, en una función real y no en una demo. El OCR está detrás de una abstracción de proveedor para poder cambiar el modelo si el free tier cambia, con reintento y fallback cubiertos por tests. Las fotos van a Cloudflare R2. Zod valida tanto la entrada del usuario como la respuesta del modelo.

Costo

Todo corre en free tiers: Vercel, Neon Postgres, Cloudflare R2 y Google AI Studio. Costo mensual esperado: cero. La región de Vercel está fijada en São Paulo, la más cercana a Montevideo. En local, una URL de base de datos vacía cae a PGlite, así que el proyecto corre sin ningún servicio externo. Vitest cubre splits, saldos, rate limiting y las rutas de API críticas.

Tecnología

  • Next.js 16 App Router sobre Turbopack, TypeScript strict, Tailwind CSS 4 y componentes shadcn/ui sobre Base UI. Frontend y rutas de API serverless viven en el mismo repo; nada queda siempre prendido.
  • Drizzle ORM sobre Neon Postgres, con el esquema aplicado en runtime en el primer request después de un deploy. En local, una URL de base vacía cae a PGlite, un Postgres en proceso, así que la app corre sin ningún servicio externo.
  • Gemini 2.5 Flash-Lite lee las fotos de tickets y devuelve total, moneda y líneas como JSON validado por Zod. El OCR vive detrás de una interfaz de proveedor con reintento y fallback, así que el modelo se puede cambiar sin tocar la app.
  • Cloudflare R2 a través del SDK de S3 con subidas prefirmadas para las fotos de tickets, con fallback al sistema de archivos local en desarrollo.
  • nanoid para IDs de grupo de 21 caracteres, un rate limiter blando en memoria sobre la API y borrados lógicos en todo el modelo.
  • PWA: manifest, íconos generados y un service worker pasante, así que se instala en el teléfono sin ninguna caché offline que mantener.
  • Vitest para splits, saldos, rate limiting y las rutas de API críticas; fixtures de Playwright para end-to-end; Biome para lint y formato.