01 / 04 · System overview
Client delivery · 2025 – Present
Multi-Location Restaurant Ordering Platform
- Problem
- A multi-location brand needed mobile and web ordering, provider sync and back-office tools to agree on one order lifecycle.
- My role
- Full-stack and mobile engineer within a Crave delivery team: Flutter app, Next.js web and admin, Express API, provider integrations.
- What changed
- Ordering contracts, POS catalog import and outbound orders, webhook status updates, and the fixes in the five stories below.
- What was verified
- Checkout double-charge, order history and Redis fixes confirmed in production; brand withheld, evidence sanitized.
Delivered through Crave for a multi-location restaurant brand: a Flutter ordering app, web ordering, an admin dashboard, and an Express API layer. The system connects store/menu discovery, basket and checkout flows, provider-backed order state, loyalty, notifications, support, and back-office operations. The brand is withheld; Crave publicly describes this work as the guest app for an 80-location restaurant brand.
01 Scope
The product context behind the work.
Problem
A multi-location restaurant brand needed customer ordering and internal operations to stay aligned. Customers needed a clean way to choose a location, browse menus, customize items, check out, and track orders. The operations team needed reliable menus, stores, customers, orders, exports, support, messaging, and analytics in one place instead of several disconnected surfaces.
My contribution
- Worked across a Turborepo monorepo with a Flutter ordering app, Next.js web surfaces, an operations dashboard, and an Express BFF on shared packages
- Built and connected ordering contracts for store selection, menu/category reads, modifiers, baskets, checkout context, payment handoff, order history, favorites, delivery addresses, and rewards
- Supported operations dashboard modules for orders, menus, ingredients, stores, customers, analytics, order exports, support, messaging, notifications, and internal jobs
- Connected provider APIs, webhooks, background queues, Redis, email/notification delivery, product analytics, error monitoring, support workflows, and Postgres/Prisma persistence so mobile history, order tracking, and admin views stay in sync
Selected production stories
Story 01 · Payments
Confirmed
Customers were charged, then told their order failed
- Problem
- On the new-card checkout path the payment and order went through, but the app's final confirmation call sometimes failed. Customers believed the order had failed, and some ordered again.
- My contribution
- I traced it to the managed Redis scripting engine silently dropping a null field from the saved checkout session, fixed the read to treat a missing value as empty, verified it by replaying the failed call on the test environment, and rebuilt each reported customer's session from server logs to separate our bug from a bank decline and a deliberate re-order.
- Verified result
- Roughly 3 in 100 new-card checkouts had hit the error while it was live. No recurrences in the first two days after release, and the store received a per-customer breakdown.
- Proof boundary
- The null field came from one of my own earlier changes about a month before. The fix does not reverse earlier double payments; refunds were a support decision.
Story 02 · Data integrity
Confirmed
Order history showed empty for thousands of customers
- Problem
- Signed-in customers who had ordered on the brand's website saw an empty order history in the app. The list required two account identifiers, and website orders carried only one.
- My contribution
- I proved the cause on production data and changed the history to include website orders linked to the account, view-only. Review caught two dangers I fixed first: a case-insensitive email match that treated underscore and percent as wildcards and could match other people's accounts, and orders stored twice after a cancellation.
- Verified result
- Thousands of customers went from an empty history to seeing their orders. Running the new code against production data showed zero duplicates and no regressions before release.
- Proof boundary
- A website guest order placed with a registered customer's email also appears in that customer's history. Twelve lower-priority review findings were deferred.
Story 03 · Reliability
Implementation confirmed
Every signed-in feature failed until the server was restarted
- Problem
- Twice in one afternoon, every signed-in request returned errors for a few minutes and the menu failed too. A manual restart fixed it instantly both times.
- My contribution
- I used the restart clue to rule out the managed Redis itself, found the server's single long-lived Redis connection had no keepalive or reconnect strategy and was left half-open when idle connections were dropped, and built the fix: reconnect with backoff, keepalive pings, readiness based on ready rather than open, and fail-fast reads.
- Verified result
- The self-healing client is in production.
- Proof boundary
- Say the connection was made self-healing, not that outages were eliminated; recurrence data after the fix was not recorded.
Story 04 · Integrations
Confirmed
Order updates never arrived from the ordering provider
- Problem
- In launch week, production orders stayed at received forever, and item-availability and menu-change events never arrived.
- My contribution
- I proved nothing was arriving at all: the handler rejects bad signatures before storing anything, so an empty event table plus zero signature failures meant zero deliveries. I confirmed our endpoint was ready, traced the gap to a webhook subscription never configured in the provider's dashboard, and wrote the exact setup: destination URL, shared secret and event list.
- Verified result
- Once the subscription was configured, production received order updates from every channel.
- Proof boundary
- The fix was provider-side configuration, not code.
Story 05 · Systems integration
Core integration confirmed
Connected an external POS catalog and ordering workflow
- Problem
- The platform needed to import categories, modifiers, products, prices, location context, and nutrition data, then forward customer orders and process provider status updates.
- My contribution
- I implemented the catalog import and outbound-order path, aligned the provider SDK and data contracts, added pricing, location, and nutrition handling, and built the webhook-to-internal-status update path.
- Verified result
- A test order reached the provider dashboard, import fixes were deployed and acknowledged, and relevant deployment checks passed for the core flow.
- Proof boundary
- The complete status-to-notification loop was not independently verified; image import and broader security hardening are not claimed, and scheduling UI was shared work.
02 Approach
Important engineering decisions.
The product is a multi-location restaurant ordering and operations platform. It spans a Flutter customer ordering app, web ordering and marketing surfaces, an internal operations dashboard, and an Express API layer that normalizes the ordering contracts between the frontend products and provider systems.
On the customer side, the ordering experience covers the full path from location selection to menu browsing, product customization, basket management, checkout, rewards, saved addresses, order history, and order tracking. The app and web surfaces do not talk directly to raw provider APIs; they rely on the BFF to expose stable, app-shaped contracts.
On the operations side, the dashboard gives the team control over the back office: orders, menus, ingredients, stores, customers, analytics, exports, notifications, support, messaging, and internal jobs. That matters because restaurant ordering is operational software, not just a cart flow - store availability, menu overlays, payment handoff, order imports, webhooks, email/notification delivery, product analytics, error monitoring, support tickets, and customer history all have to stay aligned.
The architecture is a Turborepo monorepo with shared packages for UI, database access, environment validation, utilities, logging, and config. The API server connects provider-backed ordering, loyalty, checkout, email delivery, push/device notifications, product analytics, error monitoring, and support workflows to Postgres/Prisma persistence, Redis-backed queues, webhooks, cron jobs, and admin-facing read models.
This platform was delivered through Crave, where I work as an engineer and now Director of Engineering. Crave publicly describes the engagement as building and launching the guest app for an 80-location restaurant brand; see craveup.com. The brand is withheld here, and the evidence above stays sanitized.
03 Evidence
How it works.
02 / 04 · Product journey
From choosing food to tracking it
03 / 04 · System boundary
One connection for web and mobile
04 / 04 · Delivery / verification
Keeping everyone up to date
04 Delivered & verified
What the public proof supports.
Delivered scope
Customer journey
Location -> menu -> basket -> checkout -> order tracking across mobile and web ordering surfaces
Operations
Orders, menus, stores, customers, analytics, exports, support, messaging, notifications, and internal jobs in one admin system
Architecture
Turborepo monorepo with Flutter, Next.js, Express, Prisma/Postgres, Redis queues, provider APIs, email/notifications, analytics, error monitoring, webhooks, and cron jobs
Stack
Reflections
- The product challenge was not a single checkout screen - it was keeping mobile, web, API, provider integrations, order state, and operations tooling aligned around one ordering lifecycle.
- The monorepo helped keep shared contracts, config, UI primitives, database access, and integration behavior consistent across a Flutter app, web surfaces, dashboard, and API.
Next step
Have a similar project?
If this looks close to the product work you need, book a short call and I will help scope the next step clearly.