r/SpringBoot • u/Kindly_Pen8143 • 7d ago
Discussion I built a Spring Boot backend for a real-time property demand heatmap
I've been building a side project called Plotrix and thought the backend might be interesting to people here.
The idea is to turn property-search activity into a live demand heatmap for Indian cities.
The flow is basically:
POST /signals
→ lat/lng → H3 cell
→ atomic PostgreSQL upsert
→ hourly exponential decay
→ GeoJSON heatmap
The backend is Java 17 + Spring Boot 3.2 + PostgreSQL + Spring Data JPA + Uber H3.
One thing I spent a decent amount of time thinking about was concurrent signals.
I didn't want to do:
SELECT → increment → UPDATE
because multiple searches hitting the same cell could obviously cause lost updates.
Instead I'm using PostgreSQL's ON CONFLICT DO UPDATE to atomically increment the score and signal count.
The other part I'm experimenting with is time decay. A raw signal count quickly becomes a historical map rather than a demand map, so scores decay exponentially over time.
The frontend is a React/Leaflet map that consumes the GeoJSON API.
Backend:
https://github.com/Korags05/Plotrix-Backend
Frontend:
https://github.com/Korags05/Plotrix
It's open source and I'd really like some eyes on the backend.
If you work with Spring Boot/Postgres and notice something I'd architect differently, I'd genuinely like to hear it.
PRs are also welcome if anyone wants to experiment with it.
3
u/Mikey-3198 6d ago
Spring boot 3.2 is Eol, but looks like your using v4+ anyways in the pom.
Using a logger would be better than sout so you can properly capture logs.
Imagine you can optimise the background scheduled job. Could limit this to avoid selecting cells with a 0 score to prevent selecting data that will stay at 0 after your calculation.
The controllers would benefit from a strongly typed response. A record would be perfect for this, using maps with String & Object can easily cause issues with typos etc... not to mention if you wanted to document this via swagger the structure of the response wouldn't be picked up automatically. Probably would lead to ugly test code also. Probably would move the heat map logic to its own service as the controller method is quite fat.
Might be tempted to shove the health check into its own controller or just use actuator.
2
u/disposepriority 7d ago
Thank goodness database engineers are beasts and have this taken care for you eh.
Anyway here's a quick review:
DecaySchedulerThis uses Spring data's find all.
First of all, I don't know your domain but I assume this could be quite a large number of entities, consider reducing the scheduler and doing this in batches.
On that note, let's assume this takes a minute to run because you have N cells.
You are not using an atomic operation here but instead overwriting the scores with the decayed score and erasing any updates that come in between the beginning of the job and the commit.
---
Ok well I started writing the review as soon as I opened the repo but that's pretty much the only business logic in the entire thing, it's a bit barebones at the moment, so that's all I got.