The storefront
What the shop does for customers: its pages, cart and wishlist, checkout, accounts, order tracking, the fitting room, analytics tags and search engines.
For the Full Stack package
Pages
Every page exists in English under /en and in Arabic under /ar. A path without a language goes to /en.
| Path | What it shows |
|---|---|
/en | The home page: hero, categories, new drops, an offer banner, best sellers and editorial sections. |
/en/shop | Every product, with search, category, price and highlight filters, sorting and pages. The filters live in the address, so every view can be shared. |
/en/categories | The categories, with search and sorting. |
/en/products/<slug> | A product: gallery, variants, price, rating, reviews, related products, and the wishlist and fitting room buttons. |
/en/cart | The cart and its summary. |
/en/checkout | Shipping details and payment on one page, beside the order summary. Open to guests. |
/en/order-confirmation/<number> | The order number to keep for tracking, with links to keep shopping and to track the order. |
/en/track-order | Order tracking by order number and email, with no account. |
/en/about, /en/contact, /en/faq | Support pages. |
/en/auth/login, /en/auth/register, /en/auth/forgot-password, /en/auth/reset-password | Sign-in and account creation. A signed-in customer is sent away from them. |
/en/account | The signed-in area: an overview, orders and their detail, addresses, profile, order tracking and the wishlist. A visitor who is not signed in is sent to the sign-in page. |
/en/wishlist redirects to /en/account/wishlist.
Wire these before going live
The contact form and the footer's newsletter form confirm to the shopper but send nothing until you connect them, and the template has no terms or privacy pages, although the registration form asks shoppers to accept them. Connect both forms to your own mail or helpdesk and add those pages before you sell.
Cart and wishlist
- The cart and the wishlist are kept in the shopper's browser, for guests and signed-in customers alike, so they survive a reload and a return visit on the same device.
- Anyone can add to the wishlist from a product card or page. The wishlist page itself is in the account area, so viewing it needs sign-in.
- The cart shows the subtotal, the shipping (free from $75, otherwise $9.99) and the total. The API prices every order again from its own catalogue when it is placed, with the same shipping rule, and the cart never follows a shopper to another device.
Checkout
One page: first and last name, email, an optional phone number, address, city, postcode and country, then the payment method. Guests check out with their email.
- Cash on delivery is selected by default and confirms the order straight away.
- Card runs on Stripe, inside the page. It needs the publishable key in the storefront and the secret key and webhook in the API.
- The summary shows the shipping the API charges, free from $75 and otherwise $9.99, with no tax.
- There is no promo code field.
NEXT_PUBLIC_DEMO_CHECKOUT=trueprefills a generated buyer and adds a button beside the shipping heading that draws a new one. Keep itfalsefor a real shop.
Customer accounts
- Registration asks for a first and last name, an email and a password of at least 8 characters, and the terms checkbox.
- Sign-in works from its page and from a sign-in window that opens anywhere in the shop. Customers and staff are separate accounts: a customer cannot sign in to the admin dashboard.
- Profile has two tabs: the customer's details and a password change.
- Addresses can be added, edited, deleted and one set as the default.
- Orders lists the customer's orders, each with its status, tracking number, items, totals and addresses.
Email needs your mailer
The template sends no email: no order confirmation, no shipping notice and no password reset message. Outside production the API writes the reset token to its log, and the reset page opens at /en/auth/reset-password?token= followed by that token. With NODE_ENV=production the token goes nowhere until you connect a mail provider in forgotPassword, in back-end/src/modules/customer-auth/customer-auth.controller.ts.
Reviews
- Each product page shows its reviews and a rating summary. A review from a customer who bought the product carries a "Verified Purchase" badge.
- Shoppers cannot write a review: neither the storefront nor the admin dashboard has a form for it, so the seeded reviews are what the shop shows.
- The API accepts reviews from signed-in customers at
POST /api/reviews, one per customer per product: posting again updates the first.
Order tracking
/en/track-order asks for the order number and the email the order was placed with, so a guessed number reveals nothing. A link with ?order= fills the number in. Signed-in customers track from their account with the order number alone.
The lookup allows 10 tries a minute from one address.
The fitting room
When the API has the fitting room switched on, shoppers can see a product worn before they buy it. Without it, none of this appears.
- A "Try it on" hanger on each product card, a button in the product gallery, and a fitting room panel docked on every page.
- The look is drawn on a model, or on the shopper's own full-body photo (JPG, PNG or WebP, up to 12 MB) with "Use my photo".
- On the sample store it shows the product's own photo, with a note that the look was not drawn.
Analytics and tracking pixels
Six networks are built in. Paste an id into storefront/.env (with Docker Compose, the .env next to docker-compose.yml) and rebuild. An id left blank loads no script at all.
| Variable | Network |
|---|---|
NEXT_PUBLIC_GTM_ID | Google Tag Manager |
NEXT_PUBLIC_GA4_MEASUREMENT_ID | Google Analytics 4 |
NEXT_PUBLIC_META_PIXEL_ID | Facebook and Instagram |
NEXT_PUBLIC_TIKTOK_PIXEL_ID | TikTok |
NEXT_PUBLIC_SNAPCHAT_PIXEL_ID | Snapchat |
NEXT_PUBLIC_PINTEREST_TAG_ID |
NEXT_PUBLIC_ANALYTICS_CURRENCY (USD by default) is sent with every value, and NEXT_PUBLIC_ANALYTICS_DEBUG=true logs every event to the browser console. If you set only one id, set Tag Manager: it can load the others from its own interface. If GA4 runs inside your Tag Manager container, leave NEXT_PUBLIC_GA4_MEASUREMENT_ID blank, or every session is counted twice.
| Event | Raised when |
|---|---|
page_view | Every navigation, the first one included |
view_item | A product page finishes loading |
add_to_cart | Add to cart, Buy now, or a quantity increase in the cart |
remove_from_cart | A line is deleted, or its quantity decreased |
add_to_wishlist | A product is added to the wishlist |
view_cart | The cart page opens with something in it |
begin_checkout | The checkout page opens |
purchase | The order is created and the payment cleared |
search | A search term settles in the search panel |
sign_up | An account is created |
login | A shopper signs in |
Consent
The tags load as soon as the page does. If you sell into the EU or the UK, put a consent banner in front of them before going live: the tags are mounted by <AnalyticsScripts /> in src/app/layout.tsx.
Search engines and sharing
- Every public page has its own title and description, from
messages/seo/, with a canonical link and English, Arabic and default language alternates. /robots.txtkeeps the account, sign-in, cart, checkout and order confirmation pages out of search engines, and points to the sitemap./sitemap.xmllists the public pages in both languages, plus every product when the server can reach the API.- Every page carries the shop's organisation and website details for search engines, including the site search.
- All of these are built from
NEXT_PUBLIC_SITE_URL: set it to your real address before going live, and rebuild.
The sample store
Without NEXT_PUBLIC_API_BASE_URL, the storefront runs on a sample store in the browser and shows a "Sample data" notice that a visitor can dismiss until the next page load.
- Any email and password sign you in as the sample shopper. Browsing, filtering, the cart, the wishlist, addresses and order history all work, and changes are kept in the browser.
- Checkout charges shipping as the API does and completes without calling Stripe.
- Once your API is connected,
yarn remove:mockdeletes the sample store and its notice. It keepspublic/mock-media/, which a backend seeded without a bucket still points at.
storefrontyarn remove:mockWhere to change things
| What | Where, in storefront/ |
|---|---|
| Name, logo, contact details, social links, sharing images | src/config/brand.config.ts |
| Colours | src/styles/theme-variables.css |
| Every visible word | messages/<namespace>/en.json and ar.json |
| Page titles for search results | messages/seo/ |
| A page's layout | src/app/[locale]/ for the route, src/features/ for its parts |
| Marketing tags | src/config/analytics.config.ts, switched on from .env |
How the storefront's code fits together
Included with your purchase. Sign in to read, or open it in your download.
The code's structure and conventions, and how to add a tracking network.
What the API does for the shop
The storefront's catalogue, accounts, addresses, orders, tracking, reviews and fitting room are served by the API's public and customer routes.