Draft: Shipping Ordina v1.6
Status: Draft 0.1
This is an early draft of an engineering journal documenting the work behind Ordina v1.6. It is intentionally incomplete, sections may move around, screenshots will be added throughout, and some technical details are still being refined.
For the past couple of weeks I've been preparing what eventually became Ordina v1.6.
At first, it didn't look like a particularly large release.
The original goal was relatively focused: redesign the delivery pricing engine to support more granular pricing rules.
That assumption didn't survive very long.
What began as changes to the delivery pricing engine gradually spread into many of the backend's critical paths. By the time the release was ready, the branch had grown to around 144 changed files and roughly 12k new lines, alongside infrastructure changes, database migrations, and features that are finished but intentionally not yet enabled.
Going back to code written in 2024
While working on Ordina v1.6, I kept running into files that hadn't been touched since November 2024. GitLens would quietly remind me when they were last modified, taking me back to a time when I was still finishing my engineering degree and building Ordina alongside a full-time job.
Back then I was still an engineering student.
I was balancing university, a full-time job, my graduation project, and Ordina after hours.
Some of the code I wrote during that period has quietly survived nearly a year in production.
Now I was back, rewriting parts of it with a completely different understanding of the system.
It's interesting how software becomes a timeline of your own growth.
The Scope Kept Growing
Ordina v1.6 started as a redesign of the delivery pricing engine. I expected a relatively contained change affecting only a few backend services.
As the implementation progressed, the changes spread into delivery boundaries, shop geofencing, assignment logic, and other production-critical code paths that depended on one another.
The branch gradually grew to around 144 changed files and roughly 12,000 insertions. Looking at the diff, it was clear this had become much more than a pricing update. Not exactly the kind of deployment you make without double-checking everything.
Around the same time, I noticed the main backend repository was approaching its 1,000th commit. Not a milestone in itself, but a quiet reminder of how much the system had evolved.
Redesigning the Delivery Pricing Engine
Until now, delivery fees were calculated using a single pricing model shared across the platform. It worked well in the early stages, but it gradually became restrictive as operational requirements became more varied.
One recurring challenge was merchant contracts. Some partners absorb part of the delivery cost, while others require higher delivery fees. Supporting these cases meant changing the pricing logic itself, which wasn't a sustainable approach.
The new system introduces delivery profiles. A profile defines how delivery fees are calculated and can be assigned to an individual shop or shared across a group of shops. This allows different pricing strategies without introducing custom logic for every merchant.
For example, one delivery profile may reduce the customer's delivery fee as part of a promotional agreement with a restaurant, while another may increase it to reflect a different commercial arrangement. The pricing engine simply evaluates the assigned profile and applies the corresponding rules.
Although the concept is relatively simple, introducing it required revisiting several parts of the backend. Delivery pricing is closely tied to shop eligibility, delivery boundaries, and distance calculations, so the redesign naturally extended beyond the pricing engine itself.
In short, a more flexible foundation that allows:
- More granular delivery pricing
- Better delivery zone computation
- Shop-specific delivery boundaries (geofencing)
- A cleaner path for future pricing models
Deployment day
The deployment happened on Friday morning, just before Jumu'ah.
As always, the process started with a backup.
Normally I expect migrations to finish within a few minutes.
This one didn't.
One of the data patches had to backfill newly introduced fields across existing records, and the migration ended up taking almost 40 minutes. There wasn't much to do except watch the terminal, keep an eye on the database, and hope it was still making progress rather than waiting on a lock.
Watching a production migration sit on Sending data for that long is an excellent exercise in patience.
Fortunately, everything completed successfully.
Monitoring production
I chose the timing carefully for when to deploy, low traffic period on a Friday.
While deploying, there was the expected spike in client errors while users background services restarted, but things quickly settled back down.
2:30PM I was on constant monitoring of critical clients' and server metrics.
At that point, I thought the release had gone smoothly.
I was wrong.
The regression that escaped testing
For a few days after the deployment, everything appeared to be working as expected. Orders were flowing normally, error rates remained low, and there were no obvious signs of trouble.
Drivers who were already delivering an order weren't receiving newly assigned deliveries until they completed their current task.
It wasn't obvious because it only happened under a very specific production workflow.
These are the kinds of bugs that remind you there's a difference between a comprehensive test suite and real users interacting with a live system.
The fix eventually went out around 3:00 AM.
Not the ending I was hoping for, but certainly not an uncommon one in software engineering.
More than pricing
Not everything developed for v1.6 is shipping with v1.6.
The backend implementation of the loyalty system is, for the most part, complete. Points, levels, rewards, and the supporting business logic are already in place, but the feature will remain disabled until the mobile applications and operational workflows are ready.
Development has also started on wallet transfers, allowing customers to transfer funds between their wallets. Like the loyalty system, it's progressing independently and won't be enabled until the entire feature is ready.
Keeping these features behind feature flags allows them to be developed, tested, and refined alongside production code without exposing incomplete functionality to users. It also keeps releases focused, allowing operational improvements to ship without being tied to features that still need more work.
Looking ahead
Looking back, v1.6 turned out to be much larger than I originally expected. Ordina v1.6 is another step in that journey. While this release is now in production, development hasn't slowed down. The loyalty system is waiting for its public release, wallet transfers are already underway
Crossing nearly 1,000 commits feels less like reaching a finish line and more like reaching another checkpoint.
There are still plenty of features on the roadmap.
There are certainly more bugs waiting to be discovered.
And there are still parts of the codebase that my future self will probably revisit and wonder:
"Why did I write it like that?"
Hopefully, with a smile.
Screenshots
I plan to include a few screenshots with this post:
Revisiting code last touched in November 2024. The 144-file diff behind v1.6. The migration that spent nearly 40 minutes updating production. Production monitoring during and after deployment.
Draft 0.1 — Written while waiting for the sun to rise and after the world has gone quiet.