Rebuilding the EV Reimbursement App from Scratch
4 min read
Rebuilding the EV Reimbursement App from Scratch
I wrote about the original version not long ago — a simple tool for Siemens employees to track home EV charging costs and generate reimbursement reports. It worked, people used it, and it solved the problem it was built for.
But the codebase was showing its age. One massive script.js file with 1,400+ lines, functions overwriting each other at runtime, and a dozen places where the same date-parsing logic was copy-pasted. It was the kind of code that worked fine until you tried to change anything.
So I rebuilt the whole thing.
The Rewrite (v2.0)
The original was three files — index.html, script.js, and styles.css. No build tools, no framework. That simplicity was intentional and I wanted to keep it. So instead of reaching for React or Vue, I split everything into ES modules.
The 1,400-line script became 16 focused modules: one for profiles, one for billing fields, one for charts, one for exports, and so on. Each module owns its own state and exports a clean API. The HTML loads a single app.js entry point with type="module", and the browser handles the rest.
No bundler. No transpiler. Open the folder, serve the files, and it runs.
The real wins from the rewrite:
- No more monkey-patching — the original had functions that overwrote themselves at runtime to inject side effects. That's gone.
- Centralized date parsing — twelve duplicate parsing calls became one utility function.
- Profile-scoped storage — data isolation between profiles is now built into the storage layer, not bolted on after the fact.
New Features (v2.1)
Once the foundation was solid, adding features became straightforward. Here's what shipped:
Billing History
You can now archive completed billing periods. Each archive captures the date range, total kWh, total cost, and rate used. You can browse past periods, restore one to edit it, or delete it. No more losing last month's data when you start a new cycle.
Saved Rate Presets
Most people use the same utility rate every month. Now you can save rate configurations — name, flat or tiered, the actual rates — and select them from a dropdown instead of re-entering them every time.
Receipt Generation
The app generates a formatted reimbursement receipt with a receipt number, itemized line items, and a signature line. It's styled to match what Siemens accounting expects, so employees can print and submit without reformatting anything.
Month-over-Month Trends
A new trend chart shows how your charging costs and usage change across archived billing periods. It makes it easy to spot patterns — seasonal changes in driving, rate increases, that kind of thing.
PWA Support
The app is now installable as a Progressive Web App. Add it to your home screen, and it works offline with a service worker caching all assets. For people who use this every day, it feels like a native app.
Still No Backend
Everything still runs client-side. All data stays in localStorage. No accounts, no servers, no tracking. That was a design principle from day one and it hasn't changed. The app is more capable now, but the privacy model is exactly the same.
What I Took Away
Rewrites get a bad reputation, and honestly, most of the time you should just refactor incrementally. But when the architecture actively fights new features — when every change requires understanding three layers of monkey-patching — sometimes a clean break is the right call.
The key was keeping what worked (zero-build simplicity, client-side only, Bootstrap for layout) and fixing what didn't (monolithic structure, duplicated logic, brittle state management). The result is an app that does more while being easier to maintain.
Check it out on GitHub.