Shipping a legal marketplace solo
Stumble is a real two-sided marketplace for court coverage: ten packages, five services, Stripe payouts, offline mobile sync. Here is what one developer building all of that actually looks like.
09 Jun 2026 · 4 min
There is a particular kind of project that teaches you what "full stack" really means, and Stumble was mine. It is a production legal-coordination marketplace at stumblelegal.com: solicitors who cannot make a court appearance post the job, and barristers and associates pick it up to cover it. Two sides, real money, real deadlines, the kind where a missed notification means someone does not turn up to court. One developer. That last part is the whole story.
People hear "marketplace" and picture a CRUD app with a payment button. The button is the easy part. The hard part is everything that has to be true around the button before you can charge anyone.
What ten packages buys you
Stumble is a Yarn-workspaces monorepo of ten packages, and each one exists because something pushed back against putting it somewhere else. There is api, the Parse Server backend. There is the mobile app, Ionic plus Capacitor, because solicitors are not at a desk when their day falls apart. There is the Angular SSR website for the public side, a dashboard for admin, and a small constellation of background workers: livequery, update, scheduler, scraper. There is an mcp server so an agent can drive the platform. And there is shared, which is the only reason the other nine stay honest, the types and helpers that keep the mobile app and the API agreeing on what a job is.
The backend is Parse Server on MongoDB, with Redis behind it for LiveQuery and caching. I will defend Parse to anyone who has actually shipped on it. You get auth, an ACL model, a query language, and a real-time subscription layer out of the box, and you spend your time on the domain instead of reinventing sessions for the fourth time.
Offline-first, because courts do not have wifi
The mobile app cannot assume a connection. So it is offline-first: entries live in IndexedDB on the device, and a Parse LiveQuery WebSocket syncs them up and pulls everyone else's changes down when the signal comes back. A barrister can accept a job in a basement courtroom and the acceptance lands the moment they walk back into reception. The sync layer is the single most finicky thing in the whole platform, and it is also the feature nobody notices when it works, which is exactly how it should be.
Money is a state machine
Payments run on Stripe Connect with Express accounts. Associates onboard, get paid out, and the platform takes its fee in the middle. Refunds, partial captures, platform fees, payout timing: every one of those is a state, and the job is to never let two of them be true at once. Auth is Twilio OTP, because a phone number is the one credential a lawyer always has on them.
Then there are notifications, which sound trivial until you count them. Stumble has 31 notification types across 7 categories, delivered three ways: push to the device, in-app, and 32 branded HTML emails. When a job is posted, accepted, reassigned, cancelled, paid, or about to expire, the right people hear about it on the right channel. Getting that matrix right is more code than the marketplace logic itself.
The things that run while you sleep
A marketplace has to be correct when nobody is looking at it. A BullMQ scheduler auto-expires jobs that nobody picked up, and runs a nightly safety-net sweep that re-checks every assumption the live path is supposed to maintain. The sweep almost never finds anything. The one night it does is the night it pays for its entire existence.
The mobile app updates over the air through Capgo, so a fix ships to every phone without waiting on an app-store review. Five production services, each with its own Dockerfile and its own GitHub Actions deploy, push independently.
The part that surprised me
I did not set out to build a template. But once Stumble existed, the shape of it (Parse plus Mongo plus Redis, a workspace monorepo, independently deployed services, an offline mobile client, a notification matrix, Stripe Connect for the money) turned out to be the shape of the next marketplace, and the one after that. Every platform I have built since started as a fork of these decisions.
One developer cannot build a marketplace faster than a team. What one developer can do is hold the entire thing in their head, which means the seams line up, the types match end to end, and there is no meeting where the mobile team and the payments team discover they disagreed about what "complete" means. That coherence is the only advantage you get for going solo. It happens to be a large one.
- Parse Server beforeSave validation that holdsClient writes lie. This rejects bad data in a Parse Cloud Code beforeSave before it ever lands in the database.Snippet
- Why I still bet on Parse ServerThe backend everyone wrote off years ago is the one I keep reaching for, because boring infrastructure is the kind that ships products.Musing
- mcp-parseAn MCP server for Parse Server over its REST API.Tool
- One developer, ten platformsWhy I run everything as Dockerized TypeScript in one repo, and how that lets a single person ship more surface area than a small team.Musing
- Giving agents real handsA fleet of thirteen small servers that give agents real hands. What they wrap, the two house styles I build them in, and why they all start read-only.Musing