
Case Studies: Successful Backend Projects by Sodio

A look at how Sodio has built backend systems across fintech, logistics, and healthcare — what worked, what didn't, and what you'd want to know before starting something similar.
What Does "Successful" Actually Mean in Backend Engineering?
Shipping is the baseline. The more useful question is whether the system held up when load doubled unexpectedly, whether the team that inherited it could reason about it six months later, and whether the architecture decisions made at week two didn't become the bottleneck at month eighteen.
That's the lens we apply internally when we call something successful. Not just that it went live, but that it kept working as the context around it changed.
The case studies below are drawn from categories of work Sodio has done since 2016. We're not naming clients or inventing metrics, but the architectural choices, the failure modes we encountered, and the trade-offs we made are real.
How Do You Build a High-Throughput Payment Processing Backend Without Losing Transactions?
Fintech backends punish ambiguity. A queue that loses a message in a consumer microservice doesn't just cause a bug report — it causes a missing transaction, a reconciliation failure, and eventually a regulator conversation.
The problem with at-most-once delivery
On one payment project, the initial architecture used a REST-based job queue with a cron-based worker. It was fast to build. It failed silently under load when the worker process crashed mid-execution. Transactions that had been deducted on one side were never credited on the other.
The fix was moving to Apache Kafka with idempotent producers and exactly-once semantics (EOS), introduced in Kafka 0.11. Combined with outbox pattern persistence on the PostgreSQL side, every state change was written to an outbox table within the same database transaction as the business operation. A separate Kafka Connect worker read from that table and published events. If the worker crashed, it resumed from the last committed offset. No message loss.
This is not a novel pattern. The value was recognising early enough that the simpler approach had an unacceptable failure mode.
Latency vs. consistency trade-offs
For the same project, payment status reads were served from a read replica with a replication lag of roughly 50ms under normal conditions. That was acceptable for a status page. It was not acceptable for the fraud scoring service, which needed the authoritative write state. Routing that single query back to the primary, rather than the replica, cost almost nothing in engineering effort and avoided a class of race conditions that would have been painful to debug in production.
The general principle: not every read in a fintech system needs to be consistent, but the ones that do need to be identified up front, not discovered after an incident.
What Does a Logistics Tracking Backend Actually Look Like Under the Hood?
Location data is deceptively simple to collect and genuinely difficult to store and query efficiently.
On a logistics tracking project, we received GPS pings from approximately 2,000 devices at 10-second intervals. That's 720,000 rows per hour, 17 million per day. A naive PostgreSQL schema with a standard B-tree index on device_id and timestamp degraded to multi-second query times within three months as the table grew past 100 million rows.
TimescaleDB and partitioning
We migrated the time-series data to TimescaleDB, which extends PostgreSQL with automatic time-based chunk partitioning. Queries that previously scanned the full table now touched only the relevant chunk. The 95th-percentile query time for "last known position of a device" dropped from 4.2 seconds to under 80ms without any application-level changes to query logic.
The trade-off is operational: TimescaleDB requires its own extension version management, and continuous aggregates need to be understood by whoever maintains the schema. For a team that only knows standard PostgreSQL, there's a learning curve. If the data volume doesn't justify it, standard partitioning in PostgreSQL 12+ achieves similar results with less operational overhead.
Geospatial queries with PostGIS
For "which vehicles are within 5km of this depot" queries, we used PostGIS with a GIST index on a geography column. The ST_DWithin function with a geography type correctly handles distance calculations on a sphere, which matters when vehicles operate across large geographic areas. Using a geometry type with flat-earth assumptions introduces errors that compound over longer distances.
/// Not sure where to start?
Get the architecture before you commit
Tell us what you're building and we'll map the technical approach, stack, and rough timeline. No cost, no obligation, no sales call required.
How Do You Design a Backend That a Team of Six Can Actually Maintain?
Architecture decisions aren't made in isolation from the team that has to live with them. A microservices architecture with 14 services might be the right call for a 40-person engineering team. For a six-person team, it usually isn't.
On a healthcare platform project, the initial instinct was to split the system into separate services for patient records, appointment scheduling, notifications, and billing. The argument was that each domain could scale independently. The counter-argument was that the team didn't have the operational maturity to manage 14 deployment units, 14 sets of logs to correlate, and the distributed tracing infrastructure needed to debug cross-service issues.
The decision was a modular monolith in Python with Django, with clear internal boundaries between modules enforced by code review convention rather than network calls. Each module had its own models, services, and API layer. Splitting any module into an independent service later would require extracting an already-clean boundary rather than unpicking a tangle.
This is the right architecture for that team size and that stage. It's the wrong architecture if you genuinely need independent scaling of components or if teams need to deploy independently of each other.
| Approach | Suits | Doesn't suit |
|---|---|---|
| Modular monolith | Small teams, single deployment unit, early-stage product | Independent team deployments, extreme per-service scaling |
| Microservices | Large teams, clear domain boundaries, mature observability | Teams without DevOps capacity, systems with heavy cross-service transactions |
| Serverless functions | Event-driven workloads, unpredictable traffic spikes | Long-running processes, stateful workloads, latency-sensitive paths |
What Breaks First When You Scale a Backend You Didn't Design for Scale?
Usually the database.
Application servers are stateless by design in most web frameworks, so horizontal scaling is straightforward. The database is stateful, and connection management becomes the first visible problem. At around 200 concurrent users on one project, a Django application running on Gunicorn was opening a new database connection per worker per request. With 8 Gunicorn workers across 5 instances, that's 40 potential simultaneous connections, each of which PostgreSQL treats as a process. At 500 users, connection exhaustion caused request queuing at the application layer.
PgBouncer in transaction pooling mode solved it. Connections to PostgreSQL were pooled at 20, with the bouncer handling multiplexing. Application-visible connection count dropped by 85%. The change took four hours to implement and test, including rollback planning.
The lesson isn't that connection pooling is a secret. It's that systems often don't need it until they suddenly do, and knowing the fix in advance makes the incident a four-hour engineering task rather than a two-day fire.
Conclusion
The patterns above — outbox for reliability, TimescaleDB for time-series, modular architecture for small teams, PgBouncer for connection management — aren't exotic. They're well-documented solutions to well-understood problems. The value Sodio brings is recognising which problem you're actually facing before you're facing it at 2am.
If you're scoping a backend project and want to talk through the architecture before any code is written, that's usually where we're most useful.
FAQ
Does Sodio only build backends in Python and Node.js? No. Python with Django or FastAPI and Node.js with Express or NestJS are the most common choices because they match the available talent pool and the project types we see most often. For performance-critical services, we've used Go. The language choice follows the requirements, not the other way around.
What's the minimum viable monitoring setup for a production backend? You need structured logs with a correlation ID per request, a basic metrics pipeline tracking error rate, request latency by endpoint, and database query time, and at least one on-call alerting rule that fires before your users notice. Prometheus and Grafana cover the metrics side with low operational overhead. That's a realistic starting point for a team of any size.
When should you not use a microservices architecture? When your team is smaller than about 10 engineers, when you don't have dedicated DevOps or platform engineering capability, or when your transactions regularly need to span multiple domains. Distributed transactions are hard to get right and the debugging overhead is real. A well-structured monolith deployed on Kubernetes is a reasonable production target for most early-stage products.
How does Sodio handle knowledge transfer at the end of an engagement? Documentation, code review sessions with the in-house team, and a structured handover period. We write code that the inheriting team can read without us in the room. That means opinionated style guides, inline comments on non-obvious decisions, and architecture decision records (ADRs) for significant choices made during the project.
Is cloud-native always the right deployment target? No. For some healthcare and government projects, data residency requirements or existing infrastructure contracts make an on-premises or private cloud deployment the only viable option. We've deployed on bare metal, on VMware, and on AWS, GCP, and Azure. The deployment target is a constraint to be planned around, not a default assumption.
Have a project in mind? Contact Sodio Technologies to discuss your requirements and explore the right technology solution for your business.
/// Work with us
Talk to the engineers who'd build it
You'll get a technical scope, timeline and cost estimate from the people doing the work, not an account manager. In-house team, no subcontracting, since 2016.
