Why I changed the way I tracked infra cost
I built this because the previous approach was getting in the way of the page itself.
MasterMe tracks 6 projects on Neon plus one shared Vercel plan. Before, the page called the Neon API on every load, which meant the cost view depended on a live request every time someone opened it. That made the page more fragile than it needed to be, and it also created a counting problem: the total could double-count projects that already had a linked monthly cost.
I wanted a system that was simpler to read, easier to reason about, and less dependent on live API calls.
The shape of the solution
The core idea was to stop calculating everything on demand and instead store a daily snapshot.
I added a nightly cron that runs at 05:00. It writes one row per project per day into an InfraCostSnapshot table. The important part is that the row is upserted on projectId + day, so the same project for the same day always resolves to one record.
That gives me a stable daily record instead of a page that has to rebuild the whole cost picture every time it loads.
Why snapshots worked better than live API calls
The old version was doing too much at read time.
Every page load had to call the Neon API, gather the cost data, and then calculate a total that stayed correct even when some projects already had a linked monthly cost. That’s the kind of work I’d rather move out of the request path when I can.
With snapshots, the page reads stored data instead of rebuilding everything on demand. That makes the behavior easier to reason about and keeps the UI focused on showing data instead of coordinating it.
It also solved the double-counting problem more cleanly. Once I had one daily snapshot per project, it was simpler to base the totals on a single source of truth instead of mixing live API calls with monthly linked values.
The recalculate flow
I still wanted a way to refresh the data manually when needed, so I added a Recalculate button.
That button runs the same snapshot process on demand, but it’s limited to once a minute. I wanted it to be available for quick refreshes without turning into something that could be spammed.
This gave me a practical balance:
- the cron handles the normal daily update
- the button lets me recalculate when I need to
- the rate limit keeps the manual path controlled
How I think about the data model
The data model is deliberately narrow.
InfraCostSnapshot stores one row per project per day, and the uniqueness comes from projectId + day. That’s enough to support the reporting I need without spreading cost logic across the app.
I like this pattern because it keeps the data contract clear:
- one project
- one day
- one stored cost snapshot
That structure makes it easier to build around the data later, because the application no longer has to guess what a given cost value means or when it was last calculated.
What I’d keep in mind if I did this again
The main lesson here is that cost tracking is usually better as a stored workflow than a live one.
If the data changes on a schedule, I’d rather write it on a schedule than recalculate it on every request. That keeps the user-facing page simpler and avoids pulling external APIs into the critical path.
For this setup, the combination of a nightly cron, an upserted daily snapshot table, and a rate-limited manual recalculate action was enough to solve the problem without adding much complexity.
It’s a small system, but that’s the point. I wanted something that would be easy to operate and hard to break.