Mobile AppsClient project

Shipping Princess Cosmetics in Ten Weeks with Shopify and Supabase

Princess Cosmetics already sold on Shopify. They needed riders, not a second product catalog. We delivered an Android dispatch app in ten weeks by letting Shopify own commerce and Supabase own auth, dispatch state, and realtime order updates.

FlutterSupabaseShopify APIFirebase FCM
Build-That Team3 min read
Shipping Princess Cosmetics in Ten Weeks with Shopify and Supabase

How we connected Shopify order webhooks to a Flutter delivery app without rebuilding commerce, and why Supabase RLS beat a custom auth server

Princess Cosmetics runs a successful Shopify storefront in Qatar. Orders were real; dispatch was not. Staff copied order details into WhatsApp, drivers called back for addresses, and nobody had a single view of what was out for delivery. The client did not need a new ecommerce platform. They needed operations software that respected what Shopify already did well.

We had ten weeks. Rebuilding catalog, checkout, or inventory inside Flutter would have burned half that timeline. The architecture we shipped keeps every product, price, and stock count in Shopify while Supabase holds dispatch rows, user accounts, and row-level access for staff versus drivers.


Splitting commerce from dispatch

  • Shopify: catalog, checkout, payments, inventory source of truth
  • Signed webhooks: orders/create and orders/updated normalized into dispatch rows
  • Supabase Postgres: operational state including assigned driver, pickup time, delivery proof
  • Supabase Auth and RLS: staff see all shop orders; drivers see only assigned rows
  • Flutter: two role-specific flows from one codebase (staff assign, driver confirm)
  • Firebase FCM: push when an order is assigned or status changes

Webhook verification (non-negotiable)

Every Shopify webhook hits a Supabase Edge Function that verifies HMAC before parsing JSON. Unsigned payloads are rejected immediately with no dispatch row and no side effects.

typescript
export async function handleShopifyOrder(req: Request) {
  const rawBody = await req.text();
  const hmac = req.headers.get('x-shopify-hmac-sha256');
  if (!verifyShopifyHmac(rawBody, hmac, SHOPIFY_SECRET)) {
    return new Response('Unauthorized', { status: 401 });
  }
  const order = JSON.parse(rawBody);
  await supabase.from('dispatch_orders').upsert(normalizeOrder(order));
  return new Response('OK', { status: 200 });
}

Row-level security instead of app-layer checks

Drivers must never see another driver's route because a Flutter conditional failed. Supabase RLS policies enforce access in Postgres on every select and update. Staff policies scope to shop_id. Driver policies require assigned_driver_id equals auth.uid(). A leaked API key still cannot exfiltrate another shop's orders.

  • Staff role: read and update all dispatch_orders where shop_id matches JWT claim
  • Driver role: read and update rows where assigned_driver_id equals auth.uid()
  • Anon: zero row access even with a session token missing role claims

Realtime without polling the order list

When staff assigns a driver, the driver's phone should alert immediately, not refresh on a timer. Flutter subscribes to Supabase Realtime postgres changes filtered by driver ID.

dart
supabase
    .channel('driver-orders')
    .onPostgresChanges(
      event: PostgresChangeEvent.all,
      schema: 'public',
      table: 'dispatch_orders',
      filter: PostgresChangeFilter(
        type: PostgresChangeFilterType.eq,
        column: 'assigned_driver_id',
        value: currentUser.id,
      ),
      callback: (_) => ref.invalidate(orderListProvider),
    )
    .subscribe();

What went live

  • Android app on Google Play with staff and driver flows
  • Shopify orders flowing into dispatch within seconds of checkout
  • Role-based access enforced at the database, not just hidden buttons
  • Push notifications on assignment and delivery confirmation
  • Ten-week timeline from kickoff to production riders

Shopify owns commerce. Supabase owns auth, dispatch state, and realtime. Flutter owns the mobile UX. That separation is how we delivered a production delivery stack without reinventing the storefront the client already trusted.

Production case study

Princess Cosmetics

Android delivery app for a Qatar cosmetics shop. Shopify orders in, riders out, with separate access for staff and drivers.

FlutterSupabaseFirebaseShopify API
View project
ShareLinkedIn
ShopifySupabaseFlutterDeliveryRLS

Project Inquiry

Let's do great
work together

Tell us about your project, whether it is a mobile app, web platform, or MVP, and we'll respond within 24 hours.

Ahmed Anwer, Founder of Build-That

Connect with Founder · Ahmed Anwer

Your name
Email address
Project details...