Own product
Enderase: booking trusted local services, on web and mobile
A marketplace where customers book ID-verified providers or pick among bids, confirm with a deposit, message and review, in English or Amharic. In development: a Next.js web app, a Flutter app and a Fastify API on one Postgres backend; payments run in Chapa’s sandbox.
- Problem
- A web app, a mobile app and an API share one database, and the rules for customers, providers and admins have to hold whichever client sends the request.
- My part
- My own product: I own the product definition, architecture, data model, security model and verification, and AI coding agents (Claude Code and Codex) write the code under my direction.
- Result
- A marketplace where customers book ID-verified providers or pick among bids, confirm with a deposit, message and review, in English or Amharic; in development, with web flows re-verified end to end and payments in Chapa’s sandbox.
What it does
Enderase is a two-sided marketplace for home services in Ethiopia, set up for Addis Ababa’s sub-cities. A customer finds a provider whose identity has been verified, books an open time slot or posts a task and picks among bids, confirms with a 20% deposit, messages the provider, and reviews the job. Each step is an acceptance criterion. When a customer pays a deposit, for example, the payment is recorded as paid, the booking turns confirmed, the provider gets a “Deposit received” notification and a push, and each person’s “View booking” opens the confirmed booking.
Providers verify their identity with an ID document and a selfie, set weekly hours and bid on tasks. Admins verify providers and handle disputes, bug reports and a bilingual catalog of services and locations. Payments go through the Chapa gateway, in its sandbox for now: the balance is settled in cash or through Chapa, and when several providers share a job, the platform keeps a 10% fee and splits the rest. Jobs can be tracked live, and reviews are scored on several factors. Both apps are in English and Amharic.
How it works
A Next.js web app, a Flutter app and a Fastify API share one Supabase project: Postgres, authentication, file storage and real-time subscriptions. One question runs through every feature: where does each rule live? A rule kept in the apps has to be written twice and kept identical, so the line that matters runs between writes and everything else.
Apart from file uploads, both apps send their data writes to the API. It validates input with Zod and runs the business rules as SQL, inside transactions where requests can race. In Postgres, triggers keep related records in step.
Everything else goes straight to the database: the web app renders some pages from direct reads, and both apps subscribe to live updates and upload files directly. Messaging in the web app uses those live updates: a thread loads from the server, then listens for new messages, and a presence channel shows when the other person is typing.
Decisions
Decision
Send data writes through one API.
- Instead of
- Letting each app write to the database itself, as the web app did at first; moving it meant auditing each of its direct database calls.
- Why
- Both apps get the same rules: a booking rule, a validation message or a permission check lives in the API once instead of being copied into each app.
- Cost
- Both apps depend on the API to change anything, and where the API lists rows that clients can also read directly, the two paths have to agree on who sees what.
Decision
Build Amharic into the foundation, and check both languages by script.
- Why
- The Amharic foundation went in during the first week, before the mobile app existed: one set of translation files, later shared by both apps, with locale-aware formatting and prices in birr. Names that admins manage, like service categories and sub-cities, are data in both languages, not translation keys, so they change without a release.
- Cost
- Every string costs two entries and a translation. A script checks the pair: the same keys, the same placeholders, no empty Amharic strings and no English copied across unchanged.
How I verify it
Each major feature is written up in the repository, and the agents’ instructions require updating its document whenever the feature changes. But an agent’s report that something works is only a claim, so in late October 2026 I directed an agent-run campaign to test the claims, with one rule: nothing counts as done until someone other than whoever built or fixed it has seen it work at runtime.
- List the acceptance criteria. Agents independently listed what customers, providers and admins can do across web, mobile and API; deduplicated, those flows became the acceptance criteria.
- Run them. Web flows ran in Playwright with API and database assertions, mobile flows in Maestro on an iOS simulator and Android emulators.
- Audit the passes. A second agent checked that each passing test proved the screen, the stored data and the side effects, strengthening weak assertions and never weakening one.
- Confirm the failures. Failures were grouped by root cause, and a skeptical verifier tried to disprove each by another method, such as replaying API calls and querying the database instead of driving the browser.
- Verify each fix independently. Fixes ran in waves; within a wave each file belonged to exactly one fix package, so parallel agents couldn’t collide. An agent that hadn’t written a fix verified it at runtime.
The campaign confirmed failing flows, traced them to their defects and fixed them, and each fix was verified at runtime on a working branch. The web flows have since been re-verified end to end; the mobile flows still need their device runs.
What I’d change
Code ran ahead of verification: the flow-by-flow campaign came months after the first versions of all three parts. With coding agents, typing stops being the slow part. What remains is defining the product precisely enough to build and test against, so next time I’d write the flow list with the first feature and test each feature against it as it lands.
Outcome
Enderase is a web app and a Flutter app that share one API for their business rules, in English and Amharic. Its web flows have been re-verified end to end. It’s in development, so there’s no usage to report: payments run only in Chapa’s sandbox, the mobile app isn’t in the app stores, and its flows still need their device runs. What transfers: give each rule one owner, and have someone other than the author prove each result.