Back to DevLog

Receipt Scanner PWA: From Zero to Feature-Complete in One Session

3 min read

Just wrapped up an incredibly productive session building a receipt scanner PWA from scratch. What started as an empty folder ended up as a fully-featured mobile app with some seriously cool AI-powered receipt analysis.

The Stack

I went with Next.js 16 (App Router), TypeScript, and Tailwind CSS v4 for the foundation. Supabase handles auth, database, and file storage, while Claude Vision does the heavy lifting on receipt analysis. Serwist makes it a proper PWA, and it'll deploy on Netlify.

One interesting decision: Next.js 16 was what create-next-app@latest gave me, not 14. And Tailwind v4 uses this new CSS-based @theme config instead of the JS config file - pretty clean actually.

Building the Full App

Started by scaffolding the entire app structure - all 6 pages (Dashboard, Scan, Receipts, Detail, Export, Settings) plus the API route for receipt analysis. I went with a dark theme design system using #0a0f1a background and #14b8a6 teal as the primary color.

The core flow is: scan receipt → Claude Vision extracts data → save to Supabase → categorize and export. Simple but effective.

The Big Feature: Dynamic Categories

This was the meatiest part of the session. I completely ripped out the hardcoded 3-category system and built a proper flexible categories table with UUID foreign keys. Now users get 10 default categories seeded on first login, but they can add custom ones with their own colors.

The dashboard now groups totals by category type (expense/income/rebate), and there are dynamic filter tabs throughout the app. Way more flexible than what I started with.

I also stripped out all the Menards-specific logic (this started as a very niche use case) and made it generic. The AI prompt now detects store credits and rebates from any retailer.

Mobile-First PWA Polish

Fixed some mobile UX issues that would've been annoying:

  • Added proper safe-area padding for the bottom nav on newer phones
  • Fixed an infinite spinner on the home page for unauthenticated users
  • Made the category filter pills wrap instead of horizontal scroll

Technical Decisions

A few interesting choices I made:

  • Client-side Supabase calls with RLS instead of going through API routes for everything. Keeps it simple.
  • Serwist for the service worker since it has better Next.js integration than Workbox
  • Had to use --webpack flag for builds since Serwist doesn't play nice with Turbopack yet

What's Next

The code is done and pushed, but there's still some setup work:

  • Database migration SQL needs to run in Supabase
  • Need to swap out placeholder icons for proper branded ones
  • Connect to Netlify for deployment
  • Fill in the real API keys

Pretty satisfying to go from empty folder to feature-complete app in one session. The AI-powered receipt analysis is going to be the real game-changer here - no more manual data entry for expense tracking.

Share this post