AlmajiriDev
All work

Lead engineer — delivery, backend, and payments

A task-running marketplace, across four surfaces

Problem

Getting a task run for you means finding somebody trustworthy, agreeing a price, and both sides being protected if it goes wrong. Doing that over calls and bank transfers does not scale past people you already know.

What I built

A platform connecting people who need a task run with people willing to run it: you post what you need, somebody takes it, and the money is held until the work is done.

The part people underestimate is that a marketplace is not one product. It is four. There is the API that holds the truth, the app a runner uses standing in the street on a bad connection, the console someone uses to resolve an argument between two users, and the site that explains the thing to people who have never heard of it. Each has a different user with a different tolerance for friction, and getting any one of them wrong undermines the others.

I led delivery across all four, and wrote most of the backend myself.

Holding money between two strangers is the hard part. Funds sit with the platform between the task being accepted and the work being accepted, which makes every payment edge case somebody's actual money. Providers retry webhooks, deliver them out of order, and sometimes deliver the same one twice — handled naively, that silently double-credits an account and the ledger stops balancing.

So the design assumes they will misbehave. Each incoming callback is keyed on the provider's own transaction reference and applied inside a transaction that can only succeed once; a duplicate is not an error to be investigated later but an expected event with a defined, boring outcome. State transitions are checked against what the record already says rather than what the callback assumes, so a "success" arriving after a "reversed" does not quietly resurrect a payment. And staging gets replayed duplicates, delayed callbacks and out-of-order sequences deliberately, because the first time you discover your reconciliation is wrong should not be when somebody is counting real money.

The disputes and support tooling exists for the same reason. Two people will eventually disagree about whether a task was completed, and when funds are sitting between them, "we will look into it" is not a feature — it needs a queue, a history, and a resolution path that moves the money correctly.

Realtime runs over Socket.IO with Redis behind it, because a task that has been accepted needs to stop being offered to everyone else immediately, not at the next poll. That is the kind of requirement that sounds small and quietly decides your whole architecture.

Result

Four surfaces in production over nineteen months — the API, a Flutter app, an admin console and the marketing site — with payments that reconcile correctly through retries and duplicate callbacks. Built for a client, who is not named here.