Skip to content
Projects

quienpagapp

A no-signup PWA for splitting group expenses in UYU and USD. Groups live behind a secret link you share on WhatsApp, and receipts are read automatically with AI-powered OCR.

Year
2026
Role
Design, engineering
Stack
TypeScript, Next.js, Tailwind CSS, Drizzle, Postgres, Cloudflare R2, Gemini, Playwright
Open the app

Friday bar tabs and office lunches, split in Uruguayan pesos and US dollars, among people who will not install another app or create another account. quienpagapp does exactly that and nothing else: a group is a secret link you paste into the WhatsApp chat, and anyone holding it can add an expense.

No accounts, on purpose

There is no users table. A group ID is a 21-character nanoid, about 128 bits of space, so links cannot be enumerated. Who you are inside each group lives in your browser’s local storage, along with the list of groups you have visited. SMS and magic-link logins were considered and dropped: cost and friction for no benefit at this scale.

Money handling

UYU and USD balances are kept separate, with no exchange rates and no conversion. Amounts are stored as NUMERIC(12,2), never as floats. Shares are precomputed when an expense is created or edited, so a balance is a sum rather than a recomputation. Debts are shown as who owes whom according to who paid, without a global “simplify debts” pass, because the predictable answer beats the optimal one when four friends are settling a bar tab. Deletes are soft, so the history survives. Each participant can list their payment methods, MercadoPago, BROU, Prex or free text, so settling up is one tap away from the balance.

Receipts

Take a photo of the receipt and Gemini reads it: total, currency, and line items with quantities. That turns itemized splits, where each line goes to the people who consumed it, into a real feature rather than a demo. The OCR sits behind a provider abstraction so the model can be swapped if the free tier changes, with retry and fallback covered by tests. Photos land in Cloudflare R2. Zod validates both user input and the model’s response.

Cost

Everything runs on free tiers: Vercel, Neon Postgres, Cloudflare R2 and Google AI Studio. Expected monthly cost: zero. The Vercel region is pinned to São Paulo, the closest one to Montevideo. Locally, an empty database URL falls back to PGlite, so the project runs without any external service. Vitest covers splits, balances, rate limiting and the critical API routes.

Technology

  • Next.js 16 App Router on Turbopack, TypeScript strict, Tailwind CSS 4 and shadcn/ui components on top of Base UI. Frontend and serverless API routes live in the same repo; nothing is always on.
  • Drizzle ORM over Neon Postgres, with the schema applied at runtime on the first request after a deploy. Locally, an empty database URL falls back to PGlite, an in-process Postgres, so the app runs with no external service.
  • Gemini 2.5 Flash-Lite reads receipt photos and returns total, currency and line items as JSON validated by Zod. The OCR lives behind a provider interface with retry and fallback, so the model can be swapped without touching the app.
  • Cloudflare R2 through the S3 SDK with presigned uploads for receipt photos, with a local filesystem fallback in development.
  • nanoid for 21-character group IDs, an in-memory soft rate limiter on the API, and soft deletes throughout.
  • PWA: manifest, generated icons and a pass-through service worker, so it installs on a phone without any offline caching to maintain.
  • Vitest for splits, balances, rate limiting and the critical API routes; Playwright fixtures for end-to-end; Biome for lint and format.