loading
← Back to Projects
Full-Stack Platform / Solo Build

Ordering & Delivery Platform

A complete ordering and delivery system, built solo end-to-end — database schema, API routes, customer front end, admin dashboard, staff portal, loyalty mechanics, push notifications, and PWA setup. Commissioned by a restaurant client; delivered and deployed, now running as a public demo.

My Role
Full-stack, solo
Team
Solo
Portals
3 (Customer, Admin, Staff)
Systems
10+
View live demo →
01

The Build

A restaurant client needed ordering, delivery dispatch, and back-office management as one system. I took it solo from an empty repository to a deployed product: schema, API, three separate front ends, and the infrastructure underneath.

The interesting problem was never the ordering form. It was that three different people — a customer, a kitchen, and an owner — act on the same order at the same time, and all three have to be looking at the truth.

Clients
Customer PWAmenu, cart, checkout, order tracking
Staff portalkitchen queue, delivery dispatch
Admin dashboardmenu CRUD, inventory, analytics
Application
Next.js route handlersauth middleware · server actions · validation
Data & infrastructure
Postgresrow-level security on 14 tables
Redismenu cache, invalidated on write
Web Pushorder status, cart recovery
02

Engineering Decisions

01

One source of truth for an order, three clients watching it

Constraint

A customer tracks an order while the kitchen advances it and the owner watches the queue. A stale status means food cooked twice, or not at all.

Decision

One orders table as the only source of truth, with Postgres change events pushed to every connected client. No client computes status locally, and none of them poll.

Trade-off

Every open client holds a live subscription, so reconnection and out-of-order events had to be handled deliberately rather than assumed away. That cost bought the disappearance of an entire class of “my screen says something different” bugs.

02

Authorization in the database, not in the route handler

Constraint

Three portals with sharply different permissions, built by one developer who cannot hand-audit every new endpoint before shipping it.

Decision

Row-level security across all 14 tables, so the policy travels with the data. A handler cannot leak a table by forgetting to guard it, because the guard is not in the handler.

Trade-off

Policies are meaningfully harder to debug than a conditional in a handler, and the first week went into paying that down. In return, every surface added afterwards cost almost nothing to review.

03

Caching a menu that has to be correct the moment it changes

Constraint

The menu is read on nearly every request and edited a few times a week — but when the owner changes a price, the next customer has to see it, not the next cache window.

Decision

Redis in front of Postgres for menu reads, with the admin write path explicitly invalidating the cache rather than waiting for a TTL to lapse.

Trade-off

Writes became slower and carry real risk: a missed invalidation shows a wrong price. A TTL alone would have been simpler, but it forces a choice between stale prices and no cache at all — and neither was acceptable here.

04

Checkout without touching card data

Constraint

The business ran on cash on delivery and WhatsApp confirmation. No card processor was in scope, and the country runs on two currencies at a rate that moves.

Decision

Money stays out of the application. Orders carry totals in both currencies against a rate the owner controls, and confirmation hands off to the channel customers already used.

Trade-off

No automated reconciliation — the owner does that by hand. In exchange there is no card data anywhere in the system, no gateway dependency, and a flow that matches how the business already worked instead of fighting it.

03

Stack

Framework
Next.js 16
UI
React 19
Language
TypeScript
Styling
Tailwind CSS 4
Animation
Framer Motion
Animation
GSAP
Database
Supabase
Auth
Supabase + OAuth
Email
Resend
Notifications
Web Push
Analytics
PostHog + GA
Messaging
WhatsApp API