After finally making all the pages in the Freight Tracker frontend look more polished โ with a cleaner layout, better navigation, nicer styling, and a responsive design โ I thought I was done. But I wasn't. There was still a lot to improve under the hood.
Here's a breakdown of everything I worked on after the UI was "done," and what I learned along the way:
๐ Making the App Feel More Dynamic with Zustand and WebSockets
I had already integrated Zustand in Phase 2, but now I made it more useful. Instead of hitting the API every time, I could cache and reuse shipments in the Zustand store. That made the app snappier.
Then I added WebSocket support to make live updates possible โ so if a shipment gets updated in real-time (e.g., status changes to "DELIVERED"), it reflects instantly in the UI without the user refreshing the page. This gave the app a much more modern feel.
What I learned:
- Zustand is great for global state without the boilerplate of Redux
-
useShipmentStore.getState()
gives access outside components - WebSockets with STOMP and SockJS were already set up in the backend, so I just needed to connect and subscribe to the right topic
- Having WebSockets + Zustand together means my data stays fresh and fast
๐บ๏ธ Making the Map More Realistic
The Map Dashboard looked okay, but loading was slow. Why? Because I was calling the Google Geocode API for every city โ every time.
So I added a geocode cache using localStorage
. Now if a city was already looked up before, we reuse the coordinates. This made route rendering way faster.
I also:
- Gave each route a different color based on shipment status
- Added loading indicators while geocoding
- Made the map update live when new shipments are added via WebSocket
โ ๏ธ Fixing the Refresh Issue on Netlify
One of the most annoying bugs I ran into: when I refreshed a route like /shipments/2
, I got a "page not found" error. Turns out this is a common issue with React apps deployed on Netlify.
The fix? A simple _redirects
file in the public/
folder:
/* /index.html 200
That tells Netlify to send all routes to index.html
so React Router can do its thing.
๐ Preventing Backend Sleep with GitHub Actions
After deploying the backend to Render, I noticed that the free tier web service would go to sleep after a few minutes of inactivity. This meant that every time I revisited the app after a while, the backend had to "wake up," causing slow response times or even temporary unavailability.
To fix this, I added a lightweight GitHub Actions workflow in my backend repository that pings the backend url every 10 minutes โ just enough to keep it alive without overwhelming it.
Here's what the workflow looks like:
yaml # .github/workflows/keep-alive.yml name: Keep Render Backend Alive on: schedule: - cron: '*/10 * * * *' # runs every 10 minutes workflow_dispatch: # allows manual triggering jobs: ping: runs-on: ubuntu-latest steps: - name: Curl the backend run: curl --s https://freight-tracker.onrender.com/api/shipments Once pushed to the main branch, it showed up in the Actions tab on GitHub. Now I never have to worry about the backend sleeping on me. ๐ โ ๏ธ Note: GitHub Actions schedules are โbest-effortโ and may not always run exactly on time. If you want a more consistent keep-alive mechanism, consider using a free external ping service like UptimeRobot or cron-job.org ## ๐ Frontend + Backend Deployment The frontend was deployed on **Netlify** and the backend (Spring Boot) was containerized and deployed on **Render** using Docker. Key steps I learned: * Backend needs CORS configured correctly (e.g. allow frontend URL) * Set up a PostgreSQL DB on Render and connect via environment variables * Render's default `.mvnw` build failed, so I switched to Docker and wrote a `Dockerfile` instead * Frontend needed environment variable for backend API (`VITE_API_URL`) * I had to commit my real `application.properties`, not `application.properties.example`, with placeholders like `${DB_URL}` โ and set those secrets in Render Here's the live app: https://freighttracker.netlify.app/
Top comments (0)