Al-MadinaIttar
Four independently deployable projects sharing one backend: a customer storefront, a mobile app, an admin dashboard and a REST API that is the single source of truth.
The Challenge
One catalog, many surfaces
Web, mobile and admin all had to show the same products, orders and customers without drifting apart.
Discovery by scent
Shoppers browse perfume by fragrance family, not category, so the catalog needed scent-first navigation.
Friction at checkout
Customers needed to buy as a guest or with an account and still track their orders.
Running the business
The team needed to manage products, orders, customers and content from a single role-gated panel.
The Solution
MY TITLE
Full-stack developer
CLIENT
Al Madina Ittar
Web storefront
- Home, shop, product detail and collections
- Scent-family browsing and search
- Cart, wishlist and checkout with order confirmation
- Sitemap and robots for SEO
Mobile app
- iOS and Android from one Expo codebase
- Tokens kept in secure storage
- Mock-or-remote data seam: build the UI without a backend by flipping one env flag
The product in detail
What makes it different
Accounts and orders
Dashboard, profile, saved addresses, order history and notifications, with guest checkout as an alternative.
Secure auth
JWT access and refresh tokens with single-flight refresh, plus role-based access.
Commerce rules
AED integer pricing, free shipping over 250 AED, standard or express delivery, readable order references (AM-#####) and loyalty tiers: Member, Connoisseur and Maison Elite.
Admin dashboard
Manage the catalog, orders, customers and content behind role-gated endpoints.
Numbers after six months live
Apps connected
Web, mobile, admin, API
Flow covered
Browse, checkout, fulfilment
What it's built with
Web
State
Forms
Mobile
Admin
Backend
Services
Challenges & Learnings
Challenges
Keeping four apps consistent
A single API contract ({ data, message } for success, { status, message, code, details } for errors, standard pagination) with Zod validation returning 422 kept every client predictable.
Slow work on the request path
Emails and notifications go through Redis and BullMQ queues so responses stay fast.
Server and client state
Server state lives in TanStack Query; cart, session and wishlist live in Zustand.
Learnings
Layer + feature architecture pays off
Splitting by feature first, then by layer (routes, controller, service, repository, schema on the API; api, hooks, components, schema, types on the front ends) made all four repos easy to navigate.
Share schemas end to end
Typed TypeScript and shared Zod schemas for forms and API validation caught contract drift early.