Apply Stores and Channels

Learn how advanced digital commerce requirements can be met with Stores and Channels.

  • After completing this page, you should be able to:

    • Implement solutions to ensure proper data management, product management, and customer experience.
  • Zen Electron’s multi-brand digital commerce requirements

    This document outlines the requirements for the digital commerce platforms of Zen Electron's two brands: Electronics High Tech and Zenith Living.

    CategoryElectronics High TechZenith Living
    Brands & Structure
    • Operates in Australia and New Zealand with separate online stores but shared product information
    • Operates solely in Australia with a single online store. Shares some products with Electronics High Tech.
    Website Requirements
    • Single domain: electronicstech.com.au
    • Locale Identifiers: Australia: /en-AU New Zealand: /en-NZ
    • Single domain: zenithliving.com.au
    • Locale: en-AU (implied)
    Pricing
    • Separate pricing structure
    • Currencies: Australia: AUD New Zealand: NZD
    • Separate pricing structure
    • Currency: AUD
    Locales
    • Supports localized EN and ZH for respective countries
    • Supports localized EN for Australia
    Data Management & Isolation
    • Customer data shared across AU and NZ but isolated from Zenith Living
    • Customer data isolated from Electronics High Tech
    Category Structure
    • Distinct category tree
    • Distinct category tree
    Product Management
    • Shared Products: Centrally managed for shared products between AU & NZ to ensure consistency
    • Unique Products: Some products are unique to Electronics High Tech
    • All products require tailored, premium-tone product descriptions
    • Shared Products: Centrally managed for shared products between brands
    • Unique Products: Some products are unique to Zenith Living with premium descriptions
    • All products require tailored, premium-tone product descriptions.
    Shipping & Fulfillment
    • Shipping Options: Click & Collect, Standard Shipping with regional free thresholds, Same Day Delivery (Australia only)
    • Shipping Options: Click & Collect, Standard Shipping with regional free thresholds, Same Day Delivery (Australia only)
    • Exclusive: Premium Platinum Delivery
    Customer Segmentation & Accounts
    • Shared customer accounts across AU & NZ regions; isolated from Zenith Living
    • Customer accounts isolated from Electronics High Tech
    Inventory Management
    • Each website maintains its own inventory pool for Standard Shipping; retail stores also function as warehouses
    • Each website maintains inventory for Standard Shipping; uses same pool for Premium Platinum Delivery
    Merchant Center Access
    • Staff have exclusive access to manage own customer data
    • Can manage product info and availability for Electronics High Tech
    • Staff have exclusive access to manage own customer data
    • Can manage product info and availability for Zenith Living
    Retail Store Locations
    • Australia: 200 stores (WA: 21, SA: 12, NT: 2, VIC: 52, NSW: 60, QLD: 40, ACT: 5)
    • New Zealand: 20 stores
    • Australia: 100 stores
    • New Zealand: 0 stores

    Let's now look at how we can solve Zen Electron's requirements, and how Stores and Channels can play be implemented.

    Project settings

    The following requirements can be solved using Project settings:

    CategoryElectronics High TechZenith Living
    Brands & Structure
    • Operates in Australia and New Zealand with separate online stores but shared product information
    • Operates solely in Australia with a single online store. Shares some products with Electronics High Tech.
    Website Requirements
    • Single domain: electronicstech.com.au
    • Locale Identifiers: Australia: en-AU New Zealand: en-NZ
    • Single domain: zenithliving.com.au
    • Locale: en-AU (implied)
    Pricing
    • Separate pricing structure
    • Currencies: Australia: AUD New Zealand: NZD
    • Separate pricing structure
    • Currency: AUD
    Locales
    • Supports localized EN and ZH for respective countries
    • Supports localized EN for Australia

    We will add the following settings to the Project, via the Project Settings:

    CountriesCurrenciesLanguages
    AU, NZAUD, NZDzh, en-AU, en-NZ

    Categories

    The following requirements can be solved using Categories:

    CategoryElectronics High TechZenith Living
    Category Structure
    • Distinct category tree
    • Distinct category tree

    Here are examples of what kind of Category tree each brand requires:

    Electronics High Tech

    • Computers & Tablets
      • Computers
      • Components
      • iPads, Surface & Tablets
      • Networking
      • Tech Services
      • Computer Accessories
    • Gaming

    Zenith Living

    • Computers
      • Shop by brand
      • Monitors
      • Software
      • Home internet & Wi-Fi
      • Printers & Ink
      • Hard drives & data storage
      • Office furniture
    • Cameras

    We can see some similarities in the taxonomy, but ultimately they are not the same and each brand is not willing to adopt the other brands taxonomy.

    To support the requirements, we will create two root-level Categories, one for each brand. The root-level Category for each brand will be the name of each respective brand, and then the Category tree will be created underneath it.

    The only limitation of this solution is that duplicate URL slugs per locale are illegal. Zen Electron can accept having slightly different URL slugs for duplicate names, whilst keeping the same category name, so we can continue with this option. For example, ‘computers’ is a duplicate and we will need to change one of its slugs to ‘‘computers’ or some other variation.

    The Categories will look like the example response below when querying Categories (we have only added en-AU localisation values for simplicity).

    When you are working with the Categories, you will be able to determine which root they belong to by looking at the top-level Category in the hierarchy; specifically, the parent of the brand's Category tree. When your application needs to understand this is best done by holding Category tree IDs.

    Category affiliation is determined by the root-level category. For efficient application logic, storing each branch of the Category with the IDs is recommended. This is because when querying for Products, the default response will return the Category ID without any hierarchy hints. Note that GraphQL will allow you to explictly request detailed Category information including the ancestors.

    If we want to be able to retrieve the Categories belonging to a specific brand, we would add a Custom Field to the Category and use this to determine which Category belongs to which brand. Then we can query the Categories and pass this field in the query parameter to ensure that the response only returns Categories related to the brand that we want, which will give us the information needed to build a hierarchical Category menu for each brand.

    When assigning Products to Categories, we will know which Category belongs to which brand by the Category path or the custom type of the Category.

    Recognizing which brand a Category belongs to by reading the Category path.

    Product management

    We have the following requirements concerning the product catalog to solve:

    CategoryElectronics High TechZenith Living
    Product Management
    • Shared Products: Centrally managed for shared products between AU & NZ to ensure consistency
    • Unique Products: Some products are unique to Electronics High Tech
    • All products require tailored, premium-tone product descriptions
    • Shared Products: Centrally managed for shared products between brands
    • Unique Products: Some products are unique to Zenith Living with premium descriptions
    • All products require tailored, premium-tone product descriptions.

    Product Types

    For all of the Product Types, the attributes that need to have localized values, we will set them to use LocalizedString on the attribute. The LocalizedString will use ZH, en-AU and en-NZ. This will allow us to have localized Product data for each local and each website facing attibute.

    Product Tailoring

    To support having different Product descriptions for Zenith Living, we will need to use Product Tailoring. This will require us to create a Store for Zenith Living and then we can specifically tailor the Products that belong to Zenith Living. The BFF will use Product Search with ProductSearchProjectionParams storeProjection to ensure that each brand is able to view the correct version of the Product data and only the expected locales.

    Product Search supports returning the tailored Product, but does not support querying on the tailored view, only the default value. The data integration with Product Projection parameters is still in beta.

    Product Selections

    We'll use Product Selections to customize product catalogs for each brand. First, we'll create a Product Selection containing all shared products. Then, we'll create individual Product Selections for each brand, containing their respective exclusive products. This will use Product Selection Type inclusion.

    Note: It’s important to give the Product Selections a good name, so that you know what they contain, just by reading the name.

    Three product selections created in Merchant Center.

    Next we will create a Store for each brand, with the following settings:

    • Assign the appropriate Product Selections to each brand
    • Assign the required languages for each store
      • Zenith Living: en-NZ
      • Electronics High Tech; ZH, en-AU, en-NZ
    • Countries
    • Set a Store key (this will be important for Store specific shipping rates)

    The Zen Electron Store should look similar to this:

    {
    "id": "fbb33836-d683-46b2-98aa-fe00c241ba8d",
    "version": 1,
    "versionModifiedAt": "2024-10-07T05:14:23.851Z",
    "lastMessageSequenceNumber": 1,
    "createdAt": "2024-10-07T05:14:23.851Z",
    "lastModifiedAt": "2024-10-07T05:14:23.851Z",
    "lastModifiedBy": {
    "isPlatformClient": true,
    "user": {
    "typeId": "user",
    "id": "c950c084-f5d0-4a42-8761-229d5c7a8598"
    }
    },
    "createdBy": {
    "isPlatformClient": true,
    "user": {
    "typeId": "user",
    "id": "c950c084-f5d0-4a42-8761-229d5c7a8598"
    }
    },
    "key": "zenith-living",
    "name": {
    "en-AU": "Zenith Living"
    },
    "languages": ["en-AU"],
    "distributionChannels": [],
    "supplyChannels": [],
    "productSelections": [
    {
    "productSelection": {
    "typeId": "product-selection",
    "id": "7665f708-aede-4718-bf22-9ca696752f9e"
    },
    "active": true
    },
    {
    "productSelection": {
    "typeId": "product-selection",
    "id": "0d3b40b0-e317-4f42-bcaa-8259adcb0100"
    },
    "active": true
    }
    ],
    "countries": [
    {
    "code": "AU"
    }
    ]
    }

    Now we have all the settings needed to allow us to have a different catalog for each brand.

    Lets see how this would look like as a diagram:

    Alternative Product Selection strategies

    The previous approach used inclusion-based Product Selections to define each brand's catalog. Alternatively, we can achieve the same result using exclusion-based Product Selections.

    Instead of defining what each brand sells, we define what each brand excludes. We create a Product Selection for each brand, populating it with the Products that the brand should not offer. These exclusion-based selections are then assigned to the corresponding brand's Store.

    For example, let's say we have a "shared products" selection and brand-specific products for "Zen Electron" and "Electronics High Tech".

    • Zenith Living (Exclusion): This Product Selection would contain all the products except those specific to Zen Electron and the shared products.
    • Electronics High Tech (Exclusion): This Product Selection would contain all products except those specific to Electronics High Tech and the shared products.

    This approach simplifies management when dealing with a large shared catalog and smaller brand-specific exclusions. Adding a new shared Product doesn't require updating every brand's selection. Only when a brand needs to exclude a specific Product would their selection need modification.

    Comparison of inclusion and exclusion approaches

    FeatureInclusion (Individual)Exclusion (IndividualExclusion)
    Use caseSuitable when dealing with smaller, curated assortments or when the list of desired products is easier to manage.Suitable for large catalogs where excluding a small subset of products is simpler than including a large number.
    Store availabilityA new published Product that does not belong to any Selections, will not be available to any Stores.A new published Product that does not belong to any Selections, will be available to any Stores.

    Choosing the right approach depends on the specific needs and characteristics of the product catalog and the number of brands involved. Consider the anticipated growth of the product catalog and the frequency of adding new products when making this decision. For catalogs with a large shared component and frequent additions, the exclusion method may be more efficient.

    This approach still requires careful naming conventions for Product Selections. For example, prefixes like "exclude-" or suffixes like "-not-sold" indicate the selection's purpose (for example, "exclude-zen-electron-products" or "electronics-high-tech-not-sold"). This improves readability and reduces confusion. The same Store configuration demonstrated earlier applies, with the only difference being the logic behind the assigned Product Selections.

    Shipping

    The following requirements can be solved using Shipping Methods:

    CategoryElectronics High TechZenith Living
    Shipping & Fulfillment
    • Shipping Options: Click & Collect, Standard Shipping with regional free thresholds, Same Day Delivery (Australia only)
    • Shipping Options: Click & Collect, Standard Shipping with regional free thresholds, Same Day Delivery (Australia only)
    • Exclusive: Premium Platinum Delivery

    The brands share some Shipping Methods in common, whilst each has the right to set their own shipping Rates.

    To support this, we will use different Shipping Methods for each brand and use predicates to specify which brand they belong to. The predicate Cart field identifier that we need to use here is store.key. We can use this field by itself or with other predicate fields. Below is an example of what the predicate should look like:

    "predicate": "store.key = \"zenith-living\""

    For this to work correctly, the Cart must have the store value set. This will happen under any of the following circumstances:

    Note that there is no update action to set the Store on an existing Cart. This means that you need to use one of the above options to set the Store on the Cart when the Cart is created.

    Below is an example of the whole Shipping Method with the store.key predicate.

    {
    "id": "1d738bad-aa92-4387-ae32-a9c781afb951",
    "version": 6,
    "versionModifiedAt": "2024-10-07T05:39:03.265Z",
    "createdAt": "2024-10-07T05:30:21.173Z",
    "lastModifiedAt": "2024-10-07T05:39:03.265Z",
    "lastModifiedBy": {
    "isPlatformClient": true,
    "user": {
    "typeId": "user",
    "id": "c950c084-f5d0-4a42-8761-229d5c7a8598"
    }
    },
    "createdBy": {
    "isPlatformClient": true,
    "user": {
    "typeId": "user",
    "id": "c950c084-f5d0-4a42-8761-229d5c7a8598"
    }
    },
    "name": "Premium Platinum Delivery",
    "localizedName": {
    "en-AU": "Premium Platinum Delivery"
    },
    "localizedDescription": {
    "en-AU": "Zen Electron"
    },
    "taxCategory": {
    "typeId": "tax-category",
    "id": "52dca5ab-959c-4ad6-a653-d187bbc989d9"
    },
    "zoneRates": [
    {
    "zone": {
    "typeId": "zone",
    "id": "92584e63-60a0-4182-b0dc-e866d375c835"
    },
    "shippingRates": [
    {
    "price": {
    "type": "centPrecision",
    "currencyCode": "AUD",
    "centAmount": 990100,
    "fractionDigits": 2
    },
    "tiers": []
    }
    ]
    }
    ],
    "active": true,
    "isDefault": true,
    "predicate": "store.key = \"zenith-living\"",
    "references": []
    }

    An additional challenge here is supporting “Same Day Delivery for metropolitan areas in Australia”. Metropolitan areas are densely populated urban centers, and they make up a subset of each state and territory in Australia. Zones will not support this case by themselves, as they only allow you to define country and state pairs and not anything more granular like we need to meet our requirement.

    These are the current postcodes that are classified as Metropolitan for delivery purposes (by Australia Post):

    • Postcode 1000 to 1935
    • Postcode 2000 to 2079, 2085 to 2107, 2109 to 2156, 2158, 2160 to 2172, 2174 to 2229, 2232 to 2249, 2557 to 2559, 2564 to 2567, 2740 to 2744, 2747 to 2751, 2759 to 2764, 2766 to 2774, 2776, 2777, 2890 to 2897.
    • Postcode 3000 to 3062, 3064 to 3098, 3101 to 3138, 3140 to 3210, 3800, 3801.
    • Postcode 4000 to 4018, 4029 to 4068, 4072 to 4123, 4127 to 4129, 4131, 4132, 4151 to 4164, 4169 to 4182, 4205, 4206.
    • Postcode 5000 to 5113, 5115 to 5117, 5125 to 5130, 5158 to 5169, 5800 to 5999.
    • Postcode 8000 to 8999
    • Postcode 9000 to 9275, 9999

    We have a few solutions for this case:

    1. Put all the address postcodes in the Shipping Predicate. For example, shippingAddress.postalCode in ("1000","1001","1002","1003")
    2. Use a Custom Field on Carts that indicates if the address is a metro area or not, and use this Custom Field on the Shipping Predicate. Write logic to update this value on the Cart based on the address. This might be done by your BFF or API Extensions.

    Customers

    The following requirements can be solved using Customers:

    CategoryElectronics High TechZenith Living
    Customer Segmentation & Accounts
    • Shared customer accounts across AU & NZ regions; isolated from Zenith Living
    • Customer accounts isolated from Electronics High Tech

    Since Customer data isn't shared between brands, each new customer account must be associated with a specific Store. This allows a single customer to use the same email address to create separate accounts for each brand.

    When creating a new Customer we should also specify their preferred locale, this will allow your front-end application to show the Customer the expected experience.

    Pricing

    The following requirements can be solved using Prices scoped to Channels:

    CategoryElectronics High TechZenith Living
    Pricing
    • Separate pricing structure
    • Currencies: Australia: AUD New Zealand: NZD
    • Separate pricing structure
    • Currency: AUD

    Each brand will have a dedicated Product Distribution Channel to manage their individual product pricing. All product Prices must be associated with the brand's corresponding channel within the Price. Without this Channel association, Prices cannot be filtered out by Store and so this Price will be available to all Stores. The required fields for our use case are value, currencyCode and channel. country, customerGroup, and validity period are optional and depend on project requirements.

    Example of the expected Price fields:

    {
    "value": {
    "type": "centPrecision",
    "currencyCode": "AUD",
    "centAmount": 15800,
    "fractionDigits": 2
    },
    "channel": {
    "typeId": "channel",
    "id": "ac2e77df-ff8c-44eb-8048-f9789123767a"
    }
    }

    Now we need to update each Store and add the matching Product Distribution Channel.

    Inventory

    The following requirements can be solved using Supply Channels:

    CategoryElectronics High TechZenith Living
    Inventory Management
    • Each website maintains its own inventory pool for Standard Shipping; retail stores also function as warehouses
    • Each website maintains inventory for Standard Shipping; uses same pool for Premium Platinum Delivery

    We will create Supply Channels for each inventory location and assign each of these Channels to a Store. When a Cart has a Store value set, then it can only use Supply Channels that belong to that Store, ensuring that the inventory is isolated per Store.

    Note: Inventory-to-shipping mapping strategies are outside the scope of this module.

    Merchant Center access

    The following requirements can be solved using Team permissions:

    CategoryElectronics High TechZenith Living
    Merchant Center Access
    • Staff have exclusive access to manage own customer data
    • Can manage product info and availability for Electronics High Tech
    • Staff have exclusive access to manage own customer data
    • Can manage product info and availability for Zenith Living

    To create different access controls for each Brand in the Merchant Center, open the Merchant Center navigate to the User Icon (top right) > Manage organizations & teams > Select your organization > Add team > give the team a name > Permissions.

    From here select the relevant Project and grant View and edit all: Customers, then select Add condition. Here we can define one or many Stores that the Team member can access, this will mean that they can only view and edit Customers belonging to those Stores. We will need to also do this for Orders and Cart discounts. View & Edit for Products, Product Selections and Categories will be enabled for both brand teams.

    Assigning Teams permissions to Stores.

    Test your knowledge