WaterDelivery
A Multiapp and multiplatform one-stop-shop for water delivery services in the Philippines
image
CONTEXT

Why three apps, not one.

Water delivery sounds simple until you map out the actual flow: a customer picks a supplier, places an order, a rider picks it up and delivers it, and the vendor tracks all of it. Each role needs a different screen, different data, different speed. Building one app that tries to serve all three is how you end up with a mess of toggles and hidden tabs. So we didn't — we built three.

The project started with a legacy CodeIgniter codebase and a dated UI. We were tasked to transition to Laravel, restructuring the backend for maintainability and performance. On the frontend, I led the rebuild using Vue.js and Ionic Capacitor, deploying the same Vue-based frontend as a native-like app on Android and iOS — reducing code duplication while retaining platform-specific features.

OVERVIEW

One backend, three products, zero fake separation.

WaterDelivery Philippines is a multi-platform application built to support water delivery services across the Philippines. The system includes web and mobile apps for suppliers, riders, and customers — all powered by a single Laravel 10 API.

My responsibilities spanned full-stack development, system architecture, and CI/CD setup. The result is a modular platform that continues to scale as more delivery partners come on board.

Stack
Laravel 10PHP 8.1Vue 3VitePiniaVue RouterCapacitor 7BackpackMySQLRedisAbly / PusherFirebaseXenditGoogle Maps
4codebases
3role-specific apps
112Laravel models
70backend services
166migrations
91frontend views
highlights End-to-end flows covering ordering, fulfillment, payments, messaging, and rewards. A super-admin panel for corporate clients, billing, invoicing, and analytics. Product manuals and a dedicated brand guide as supporting documentation.
ARCHITECTURE

One order, many surfaces, one source of truth.

Surface layer
wd-clientcustomer app
wd-riderrider app
wd-vendorsupplier app
Backpack admininternal ops UI
Super-admincorporate + finance
Vue 3 + Capacitor
wd-api · single source of truth
Backpack + Super-admin
wd-apiLaravel 10 · 71 services · 295 routes · 112 models
single ingest point
Auth + accessPassport · Sanctum · role flows
Orders + fulfillmentbusiness services
Messaging + notificationsjobs · events · broadcast
Payments + financebilling · receipts · payouts
integrations
MySQL Redis Ably / PusherXenditFirebaseGoogle Maps
Data + integrations
MySQL + Redisprimary store · cache · queues
Ably / Pusherrealtime channels · broadcast auth
Xendit · Firebase · Mapspayments · push · geolocation
Click any architecture box to see what that part of the platform does.
PIPELINE

How the platform actually moves.

Role split, not role overload.

The customer app creates demand. The supplier app shapes supply. The rider app executes the delivery. The backend holds the truth and pushes the state outward.

Customer appbrowse, checkout, track
wd-apivalidate + persist
Jobs + eventsnotify, sync, fan out
Rider + vendor appsfulfill + manage

What each surface was responsible for.

Three apps, three distinct jobs. Keeping them separate meant each one could go deeper on its own purpose without cluttering anyone else's flow.

01

Customer app (wd-client). Broad and service-oriented — fast ordering, transparent status, low friction throughout. Covers onboarding, address management, supplier selection, checkout, live order tracking, rewards and referrals, reviews, support, and in-app messaging.

02

Rider app (wd-rider). Lean and task-driven — execution speed over breadth, with maps and proofs front and center. Narrows the interface to delivery operations: customer list, map view, delivery schedules, proof-of-delivery flows, sold-product records, notifications, and chat.

03

Vendor app (wd-vendor). An operational control panel — customers, contacts, delivery schedules, product catalog, rewards configuration, user management, and a full view of the business. The supplier sees everything relevant to running their operation without touching the other two apps.

04

What made the backend non-trivial. This was not a thin CRUD API. It became the operational layer all three apps depended on: OTP and role switching for auth, delivery area rules and schedule management for fulfillment, queue-backed notifications and realtime broadcast auth for messaging, and the full billing cycle — invoices, official receipts, payouts, refunds — for finance.

Super-admin — where the whole operation is visible.

The three apps handle the day-to-day. The super-admin panel is where everything underneath gets managed: individual customers, corporate clients, the supplier billing cycle, and a full read on platform performance. Built on Backpack for Laravel with custom views and a fully custom analytics layer.

Order and customer management.

Orders across all suppliers — filterable by date, status, schedule, and payment method. Each order has a full preview: map, status history, product breakdown, proof of delivery, and payment receipt. Admins can change status or delete directly from the panel.

A full directory of individual customers across all suppliers — account details, address book, order history, reward points, and active subscriptions. Searchable and filterable by supplier without touching the vendor app.

Corporate clients. Onboarding for companies and embassies tied to a preferred supplier with recurring schedules. An employee benefit program where the corporate account covers delivery costs of enrolled employees — billing consolidated to the company. Current clients include foreign embassies and multinationals in the Philippines.

Billing + invoicing. Supplier billing statements, corporate billing, sales invoices, service fees, and potability reports. Paid/unpaid status, carry-over balances, penalties, and downloadable PDFs per entry.

Analytics dashboard. Two modes — quick summary and advanced with full chart breakdowns. Covers CLV, acquisition and retention, bottles sold by channel, supplier growth, delivery performance, voucher usage, and average driver time. All filterable by date range.

RESULTS

A platform that could get sharper without splitting apart.

What the three-app split actually bought us.

Keeping the apps separate meant each one could go deeper on its own job. A single backend made that possible — auth, orders, payments, and messaging were all consistent because they all hit the same API. There was no duplicated logic to keep in sync.

01

Role-focused UI with zero feature-flag debt. Three separate apps meant each role got a focused interface — no hidden tabs, no "this section isn't for you" moments. The customer app never had to expose supplier config it didn't need. The rider app cut down to just the screens that mattered during a run.

02

One fix lands everywhere. Auth, ordering, notifications, payments, and finance all lived in one backend. A bug fix or a feature shipped once and landed in all three apps simultaneously — no coordinating releases across separate API versions.

03

Payments needed a two-part fix. The original flow opened Xendit in an external browser, killing the WebSocket connection before payment confirmation could land back in the app. Switching to an in-app browser kept the session alive, and a backend WebSocket listener catches the Xendit webhook and pushes the success state via Ably. By the time the customer closes the payment screen, the order is already confirmed.

04

The backend became more than an API. Services, jobs, observers, reporting, admin tooling, and a full billing layer all lived in the same monolith. The migration from CodeIgniter to Laravel forced a full rethink of the data model — painful, but the reason the platform didn't buckle when the feature list grew to 295 routes and 112 models.

takeaway The hardest decisions on this project weren't technical — they were about scope. Knowing when to extend the monolith and when to push back on feature creep kept the codebase maintainable through a platform that covered ordering, fulfillment, payments, realtime messaging, billing, and analytics for three different user types.

This is the project I'd show someone if they asked what I actually know how to do. It covers the full stack end-to-end — backend architecture, mobile-ready frontend, realtime features, payments, and CI/CD. It's also where I learned that the hardest decisions aren't technical. They're about scope.