Case Study

IPD Buddy

A mobile-first invoicing PWA for a trades sub-contractor. Vue, Java Spring Boot, and PostgreSQL, with hard lessons in scope creep and security architecture.

Stack
Heroku
Vuetify
Git
PostgreSQL
Java
SpringBoot
TypeScript
Firebase
Vue.js
Netlify
Supabase
Year2025Started
Status
Frozen
Refactor Planned

The Problem

A sub-contractor friend was drowning in manual admin work between jobs: Manual invoicing, no tax tracking, no structure.

The goal: Build a mobile-first tool for job tracking, invoice generation, and basic financial calculations. Less admin, more living.

Constraints

  • Mobile only — the application had to function entirely from a phone, shaping every UI decision from the start
  • Tech aversion — the interface needed to be dead simple, with large tap targets and minimal cognitive overhead for someone who doesn’t enjoy using technology
  • Scope creep — change requests became increasingly specific to one person’s workflow rather than improvements that would benefit the application broadly, requiring pushback to keep the project viable
  • No budget — hosting and infrastructure had to be as close to zero cost as possible

The Approach

  • PWA to avoid the App Store.
  • Vue chosen over React to expand front end skill set.
  • Vuetify for the component library.
  • Spring Boot backend to deepen enterprise Java knowledge.
  • PostgreSQL via Supabase for relational integrity.
  • Stack split across free tiers: Netlify, Heroku, Supabase.

The Execution

AWS Cognito was the initial auth choice. It conflicted with Spring Security's session handling in a browser-based SPA, JWTs were lost on page reload, sessions were unreliable at best. The backend was scrapped and rebuilt from scratch with Firebase Authentication, security-first: test controller, confirmed auth, then everything else.

The billables enum was the wrong abstraction. A hardcoded list requiring a code change to update and the client's billables changed the moment the app launched.

The UI prioritised function over form:

  • Large tap targets
  • Bottom nav for one-handed use, fast data entry.
  • Colour palette drawn from trades and safety culture: black, gunmetal, orange.

The Outcome

The application shipped as a functioning full-stack PWA. A user could:

  • Log in securely with a persistent session
  • Enter a work site address, date, billable items with quantities, and additional notes
  • Submit the job to be persisted in the database
  • Generate two PDFs instantly, a clean client-facing invoice with GST calculated, and a personal copy with savings and tax recommendations based on their configured rates
  • View a dashboard showing year-to-date earnings, month-to-date earnings, and their highest paying job
  • Manage their tax and savings rates in a user settings section
  • Browse a job history tab displaying past work as cards (full drill-down into historical jobs was planned but not completed before the project was paused)
The friend ultimately abandoned the application. Unconfirmed requirements and constant scope creep made continued development unsustainable and over 100 hours invested, no compensation, project frozen.
The application remains intact. The path to revitalizing it is clear.

The Reflections

IPD Buddy was the most instructive project I've built.

Not because everything went well, but because of what went wrong and why.

Scope creep is a requirements problem first. The billables enum issue wasn't a technical mistake, it was the consequence of building against unconfirmed requirements. No amount of good engineering compensates for a spec that keeps moving.

Security architecture belongs at the start. The Cognito detour proved it for me. The rebuild started from a security-first foundation and that's now the default starting point for any new backend.

The application remains frozen, not abandoned. The path forward is clear:

  • Replacing the enum with user-owned templates (coined Jigs at the moment)
  • Migrating to Next.js, adding an interactive demo.

The foundation is solid enough to build on.