Wahda Bank's digital platform started life as a well-behaved Laravel application. By the time it was carrying a meaningful share of the country's retail payments it was mature in the way that word really means: hundreds of endpoints, Eloquent models with real money in them, integrations with a core-banking system and instant payment rails — OnePay, LYPAY — a mobile app in the field that people would not update, and a business that could not tolerate a bad Tuesday.
Laravel backend engineer · Benghazi, Libya · EMEA · open to remote
Beyond the controller.
I'm Nabil. For ten years I've owned Laravel systems end to end — Eloquent, APIs, Redis, queues, workers, and the production paths that only matter when traffic spikes. Most recently: the digital platform that moves a country's money. This page is how I think about that work.
Scroll. Move your cursor through the stream — each particle is a session. Scroll. Each particle in the stream is a real session.
The last twelve months, on one Laravel platform I architected and built end to end — stats as of 15 Aug 2026
total transaction volume through Wahda Bank's digital platform.
~392K daily · ~11.9M monthly — Laravel, Redis queues, Go hot paths, Vue.
- 0 app users 561,555 individuals · 39,681 businesses
- 0 transactions across transfers, payments, and advances
- 0 transfers internal, OnePay, and LYPAY rails
- 0 digital payments MobiCash card & QR, card top-ups
- 0 merchants on the payment network
- 0 POS terminals live in the field
Numbers that size stop being impressive and start being a responsibility. Everything below is about carrying them without breaking what already works.
01 — Beyond the controller
A scalable change inside a mature Laravel codebase
Not a rewrite. Not a greenfield. The interesting work: peak load, Redis, workers, and a codebase that already had opinions — changed carefully so production stayed boring.
The problem arrived on salary days. Every transfer was processed inline in the request: validate, call core banking, write the ledger, notify, log. Under peak load the connection pool filled, lock waits on account rows cascaded, and a notification provider having a slow hour could make a payment feel slow.
The obvious answer — “rewrite the payments layer in something fast” — was also the most dangerous one. A rewrite is a promise to rediscover every edge case a mature system has already paid for.
So I didn't rewrite. I investigated the existing behaviour first, drew a line around the one thing that actually needed to be fast — the transfer hot path — and treated everything else as a scheduling problem.
- Everything that wasn't the money left the request. Notifications, statements, analytics and fraud scoring became Redis-backed queued jobs (Horizon) with explicit retry and idempotency semantics. Events carried the rest. The request that remained did one thing.
- The hot path moved into a small Go service behind the exact contract Laravel had always exposed. Laravel stayed the system of record and the orchestrator; Go became a worker that is very good at one narrow job. They speak through a versioned interface with contract tests, so the mobile app in the field never knew anything changed.
- Correctness first, speed second. Idempotency keys on every money-moving call; a reconciliation job comparing the new path against the old on shadow traffic before a single real transfer used it; per-cohort feature flags so rollout was a dial, not a switch.
Performance you can't afford to keep is technical debt with better PR. So each shortcut had an expiry: the parallel code path was written up in an ADR with a delete-by release; the dual-write comparison came out as soon as it had been quiet for two cycles; any query I touched left with an index and a test.
I let the old code stay ugly where it was safe, and made it clean only where it was hot — after I understood why it looked that way.
The next salary day was boring, which was the point. Peak-hour latency stopped tracking queue depth, a slow vendor stopped being able to slow a payment, and the mature codebase got a little smaller instead of a little scarier.
That platform now moves roughly 156 billion LYD a year across 143 million sessions, 77 million transactions, and 601 thousand users — and it still runs on Laravel where Laravel is right, and Go where Go is right.
02 — Domain over plumbing
I build when the problem is the domain — not the framework.
Laravel, Horizon, Redis, Guzzle
are solved. The domain isn't.
The plumbing is solved. Using Laravel well — Eloquent, jobs, events, Horizon, caching — is a skill; replacing it is a hobby. The one place I found that rule worth breaking was the integration layer under the bank.
Every Libyan payment rail — the core-banking system, OnePay, LYPAY — speaks a different dialect: different signing schemes, different ideas of what a “pending” transaction is, different reconciliation files arriving at different hours. Nothing on Packagist understood any of it. The first version wrapped each rail in its own ad-hoc client, which is a reliable way to get four copies of the same bug.
So I wrote a small PHP library for it: one ledger model every rail maps onto; a request pipeline where signing, idempotency, retries and timeouts are composable middleware; and a reconciliation engine that turns each provider's settlement file into the same stream of events. Adding a new rail became a few hundred lines of adapter instead of a new project.
Why build? Because when real money is moving, I can't afford magic behind my back. Every step has to be explicit — not hidden in a clever black box. Why keep it small? Because I've maintained other people's clever frameworks. It's better to know the codebase than to be surprised by it.
Same instinct at a smaller scale: a generator that builds Postman collections from route definitions, so API docs stop drifting from the code. And where the product needed it — Livewire, Filament, Inertia, Tailwind — I use the TALL / Laravel ecosystem instead of inventing another UI stack.
03 — Stack, honestly
What I bring to a Laravel backend seat.
Rated one to five. I'd rather you be pleasantly surprised on the technical test than the other way round.
04 — Off the clock
Watching Barça.
Ninety minutes where the only metric that matters is the scoreboard — and when someone goes airborne after a goal, the week gets lighter. FC Barcelona is my off-switch: the noise, the flip, the GOOOOOOOL. Craft under pressure, just a different pitch.
Visca el Barça →
Why CRAE
You build interconnected Laravel platforms — CRM, gaming, network, marketing — with real users, real transactions, high-frequency queues and Redis in the critical path. That is the shape of problem I've spent years inside.
Backend-first, TALL when it helps, ownership without corporate theatre. I've run a department; what I want now is deep craft on important systems, next to people who still ship.
You pay trial work and keep the hiring loop short. A company that respects an engineer's time is one I'd like to build for.
Benghazi, Libya · EMEA · Arabic (native), English (professional)
MSc & BSc Software Engineering, University of Benghazi · Open to remote