Headless Commerce
Bayt Alebaa
My first project as team lead across two separate deployments: Magento 2.4.7 Open Source as the commerce backend, and a Nuxt 2 / Vue Storefront 2 frontend that talks to Magento only over GraphQL. Saudi building-materials retailer—bilingual (ar/en), SAR—where I owned priorities, the GraphQL contract between frontend and backend, and shipping both sides together.
Problem
What was broken
Theme-bound Magento UX could not keep up with a modern storefront, KSA payments (Mada, Apple Pay, STC, Tamara), SMS OTP, showrooms, and a content-heavy homepage—while catalog, pricing, stock, and orders still had to stay in Magento (and sync to ERP). Two codebases meant every feature needed a paired backend schema and frontend module, not a Luma patch.
Solution
How we fixed it
Led frontend and backend as one product: Magento custom modules expose GraphQL for home CMS, branches, kitchen gallery, coupons, customer mobile/OTP, and catalog specs; the Nuxt frontend mirrors those as VSF modules (home settings, branches, OTP, kitchen, checkout…). Catalog/cart/account live on the frontend; payment-heavy finalize uses Vue Storefront CartSync so Hyperpay and Tamara stay on Magento. Coordinated frontend specialists while owning Magento modules, schema design, and release readiness across both.
Challenges
What made this hard
Keeping ~20+ custom Magento modules and matching Nuxt frontend modules in lockstep when either side ships. Hybrid checkout (Vue cart → Magento payment) needs reliable cart merge and redirect. Building-materials catalogs (min qty, tier price, tile specs, box coverage) stress layered nav and GraphQL payloads. Store-view and SAR cookies must stay aligned with Nuxt i18n on every request.
Architecture
How the system is shaped
API Structure
Frontend and backend: Magento CE 2.4.7 serves `/graphql` (core cart/catalog/customer plus custom schemas—home settings, branches, kitchen gallery, coupons, OTP, product specs). Nuxt 2 + Vue Storefront 2 middleware proxies browser calls to that endpoint (`useGETForQueries`, store cookie `ar`/`en`). Domain frontend modules map 1:1 to Magento modules. CartSync merges the Vue cart into a Magento session when checkout finalizes on Magento for Hyperpay/Tamara.
Data Flow
Shopper → Nuxt SSR/PWA → VSF middleware → Magento GraphQL → resolvers/plugins → MySQL (EAV catalog, quotes, orders). Home/CMS blocks load via `homeSettings`; showrooms via `branches`; auth via SMS OTP mutations. Place-order path can hand off to Magento checkout; ERP cron syncs stock and orders out-of-band. Redis caches Nuxt/middleware responses.
Backend Decisions
Upgrade-safe Magento modules for merchant GraphQL rather than core hacks. Hybrid checkout so payment complexity stays where Hyperpay/Tamara already work. Frontend never becomes a second order store—Magento remains commerce authority. Team-lead ownership meant every frontend feature shipped with a matching schema/resolver, not a theme override.
Decisions
Why this stack and shape
Headless CMS via GraphQL (`homeSettings`) instead of scraping Magento HTML. Keep Hyperpay/Tamara on Magento with VSF external checkout rather than re-implementing GCC payment edge cases in Nuxt. Saudi address model (`neighborhood`, national address) as extension attributes shared by Magento and Vue forms. SMS OTP GraphQL for mobile-first auth. ERP sync for stock/orders/customers stays server-side—never exposed to the storefront.