LahdaFood and grocery delivery app
Order restaurant meals and daily groceries through a mobile app connected to merchant preparation, driver delivery and administration.

The problem & workflow
Customer chooses an address and products → API calculates the order → merchant prepares → driver accepts an offer → delivery updates tracking → admin reconciles cash and ledger entries.
Key features
- Customer catalogue, favourites, addresses, cart and promotions
- Merchant order preparation and product management
- Driver offers, assignment, tracking and delivery status
- Admin settings, merchant ledgers, driver earnings, COD remittances and settlement receipts
- Firebase notification integration and location-aware delivery coverage
Architecture & decisions
- I kept the customer, merchant/driver, administration and API components in one repository so the order workflow stays connected.
- I use Prisma migrations for schema evolution, role guards for endpoints and ownership checks for individual records.
- Cash-on-delivery accounting connects merchant balances, driver earnings, remittances and settlement receipts.
Inside the source
Coordinating four roles in one delivery product
I built Lahda to connect food and grocery orders, merchant preparation, driver delivery and cash reconciliation.
The customer, merchant, driver and administrator see different parts of the same order. That creates two distinct authorization questions: may this role perform the action, and does this account own or handle this particular record? The API combines role guards with service-level ownership checks. The release demonstration exercises a complete delivery using synthetic accounts across the connected application roles.
Order progression also changes financial records. A delivered order can create merchant ledger entries and driver earnings, so repeating a delivery update must not create another payment record. The acceptance script checks sequential repetition and terminal-state regression. Concurrent writes remain a separate verification task.
A lesson from discounted cash collection
The discounted demonstration exposed a useful accounting distinction: a gross catalogue subtotal is not the cash collected from the customer. The remittance now uses the customer total minus the delivery fee, bounded at zero. The administrator can see the adjustment separately from the gross subtotal and application fee. This makes the price breakdown explainable instead of hiding the discount in an aggregate.
Previously publishing Lahda on Google Play demonstrates mobile delivery experience. The current release prepares reproducible API and administration demonstrations; maps, Firebase, fresh signing and device behavior need their own configuration and checks. The next engineering priorities are concurrent settlement scenarios and end-to-end notification delivery on devices.
Project status
I deployed and tested Lahda and published its customer app on Google Play.
Create an empty PostgreSQL database first. Copy api/.env.example to api/.env, set DATABASE_URL, a new JWT_SECRET of at least 32 characters, ADMIN_PASSWORD and DEMO_PASSWORD of at least 12 characters, and keep SEED_DEMO_DATA=1 only for your disposable demo. The seed provides synthetic driver/merchant accounts; bootstrap-customer adds customer@example.test and other@example.test. Configure admin/.env from its example and API URL port 2007. Configure customer and driver API URLs for emulator/LAN access; maps, Android Firebase files and signing material must be supplied separately.
Development checks & runtime notes
API and admin production builds passed. Fresh PostgreSQL initialization applied all 16 Prisma migrations. The synthetic acceptance script passed customer/merchant/driver/admin authentication, rejected admin self-registration and foreign-order access, verified a 10% discount, completed delivery, checked one driver earning and merchant entry, repeated delivery without additional entries, rejected terminal-state regression, and confirmed a remittance once. Fresh-database acceptance also verified discounted COD remittance: a 3,140 DZD customer total minus 1,000 DZD delivery equals 2,140 DZD remitted to administration. Repeating confirmation was rejected. The previous gross-subtotal formula incorrectly charged the driver for the customer discount and was corrected.
Android builds/device walkthroughs, fresh maps/Firebase integration, concurrent financial updates and multi-device notification delivery remain unverified. Repeated sequential updates passed; this is not proof of every concurrency scenario. Stop the API before Prisma generation/reset on Windows to avoid a locked query-engine DLL.
Technical details ↗A closer look


Interface walkthrough
An edited sequence of application captures using demo data.