Salesforce

Introduction To Salesforce

  1. Complete Salesforce Commerce Cloud (SFRA) Learning Roadmap
    1. Introduction to Salesforce Commerce Cloud and SFRA
      1. What is Salesforce Commerce Cloud?
      2. Types of Salesforce Commerce Cloud
      3. Why SFCC Matters
      4. Where and When SFCC is Used
      5. Prerequisites for Learning SFCC
    2. SFCC Architecture and Internal Working
      1. SFCC Architecture Overview
      2. Understanding Business Manager
      3. Introduction to SFRA (Storefront Reference Architecture)
      4. Execution Flow (Browser → Controller → Model → ISML → Response)
      5. Module System (Cartridges)
      6. Cartridge Path and Loading Order
      7. Project Folder Structure
      8. Internal Pipeline (Code → Output)
    3. Environment Setup and First Application
      1. Sandbox Setup and Access
      2. Prerequisites for Environment Setup
      3. Setup on Linux (Ubuntu) – Step by Step
      4. Setup on Windows – Step by Step
      5. Setup on macOS – Step by Step
      6. Installing Salesforce CLI and sfcc-ci
      7. Environment Setup (VS Code, Extensions)
    4. Your First Program – Hello World in SFRA (Complete Step-by-Step)
      1. Creating Custom Cartridge Folder Structure
      2. Creating package.json for Custom Cartridge
      3. Configuring Cartridge Path in Business Manager
      4. Creating Hello World Controller
      5. Creating Hello World ISML Template
      6. Deploying to Sandbox
      7. Accessing the Route
      8. Line-by-Line Code Explanation
      9. Troubleshooting Common Issues
    5. AI Integration with AI Tools
      1. ChatGPT for SFRA Development
      2. GitHub Copilot
      3. AI Controller Generation
      4. AI ISML Development
      5. AI Commerce Optimization
      6. AI Debugging
      7. AI Architecture Planning
    6. Commerce Cloud Fundamentals
      1. Business Manager
      2. Sandboxes
      3. Instances
      4. Code Deployment
      5. Data Replication
    7. JavaScript Foundations
      1. Variables
      2. Functions
      3. Objects
      4. Arrays
      5. ES6 Features
    8. SFRA Architecture
      1. Cartridges
      2. Cartridge Paths
      3. Controllers
      4. Middleware
      5. Models
      6. Scripts
    9. ISML Development
      1. ISML Fundamentals
      2. Templates
      3. Includes
      4. Components (Macros)
      5. Rendering Strategies
    10. Controllers and Routing
      1. Request Lifecycle
      2. Route Handling
      3. Middleware Chains
      4. Controller Design
    11. Catalog Management
      1. Products
      2. Categories
      3. Variants
      4. Product Sets
      5. Bundles
    12. Customer Management
      1. Registration
      2. Login
      3. Profiles
      4. Customer Groups
    13. Search and Merchandising
      1. Search Architecture
      2. Search Refinements
      3. Sorting
      4. Recommendations
    14. Cart and Checkout
      1. Basket Architecture
      2. Checkout Flow
      3. Shipping
      4. Taxation
      5. Payments
    15. Promotions and Campaigns
      1. Discounts
      2. Coupons
      3. Campaigns
      4. Personalized Promotions
    16. OCAPI and SCAPI
      1. API Fundamentals
      2. Shopper APIs
      3. Admin APIs
      4. Integrations
    17. Third-Party Integrations
      1. Payment Gateways
      2. ERP Systems
      3. CRM Systems
      4. Marketing Platforms
    18. Testing and Quality Assurance
      1. Unit Testing
      2. Integration Testing
      3. Performance Testing
      4. Automation
    19. Performance Optimization
      1. Caching
      2. CDN Optimization
      3. Page Performance
      4. Search Performance
    20. AI-Powered Commerce
      1. Salesforce Einstein
      2. AI Recommendations
      3. Personalized Commerce
      4. Conversational Commerce
    21. Production Architecture
      1. Logging
      2. Monitoring
      3. Security
      4. Scalability
      5. High Availability
    22. Real-World Projects
      1. Fashion Store
      2. Luxury Brand Platform
      3. Electronics Store
      4. Subscription Commerce Platform
      5. AI-Powered Retail Platform
    23. Career Readiness
      1. Portfolio Building
      2. SFCC Interviews
      3. Certification Preparation
      4. Enterprise Commerce Practices
    24. Conclusion and Final Skill Stack
    25. Final Advice

Complete Salesforce Commerce Cloud (SFRA) Learning Roadmap

Introduction to Salesforce Commerce Cloud and SFRA

What is Salesforce Commerce Cloud?

Salesforce Commerce Cloud (SFCC) is a cloud-based e-commerce platform enabling retailers to build scalable online stores with unified commerce capabilities. SFCC supports both B2C and B2B commerce, and its Storefront Reference Architecture (SFRA) is the modern framework for building highly modular, maintainable storefronts.

Why it matters: SFCC reduces time-to-market with pre-built features, handles high traffic, multi-site, multi-currency scenarios, and provides deep integrations with CRM, Marketing Cloud, and other Salesforce products.

A simple analogy: Imagine you are building a large department store. Without SFCC, you would need to build every shelf, every cash register, and every display case from scratch. SFCC is like a complete department store kit – shelves, cash registers, lighting, security systems, and inventory management all come pre-built. You just need to arrange them for your brand.

Code Example:

// This is a simple SFRA controller that handles a request
// URL: /Hello-Show

function show() {
    // res.render() renders an ISML template
    // 'hello' is the template name (hello.isml)
    // The second parameter passes data to the template
    res.render('hello', {
        message: 'Welcome to Salesforce Commerce Cloud!',
        timestamp: new Date().toISOString()
    });
}

// Export the show function – makes it available to the router
// URL pattern: /Hello-Show maps to Hello.js -> show() function
exports.Show = show;

SFRA controllers handle HTTP requests. The controller file name determines the URL path. When a user visits /Hello-Show, SFRA executes the show() function in Hello.js. The controller renders an ISML template with data, which generates the HTML response sent to the browser.

Types of Salesforce Commerce Cloud

TypeDescriptionExamples
B2C CommerceBusiness-to-consumer online storesRetail websites
B2B CommerceBusiness-to-business commerceWholesale portals
Order ManagementCross-channel order processingInventory management
Headless CommerceAPI-first commerceMobile apps, custom frontends

Code Example:

// SFRA supports both B2C and B2B commerce
// Example: B2B customer group check in a controller
function showB2B() {
    var CustomerMgr = require('dw/customer/CustomerMgr');
    var currentCustomer = CustomerMgr.getCurrentCustomer();
    var isB2B = currentCustomer && currentCustomer.isB2BCommerce();
    
    res.render('b2b/dashboard', {
        isB2B: isB2B,
        customerName: currentCustomer ? currentCustomer.getProfile().getFirstName() : 'Guest'
    });
}
exports.ShowB2B = showB2B;

SFRA controllers can check customer types and render different content. The dw/customer/CustomerMgr module provides customer information. B2B customers have additional capabilities like bulk ordering and account management.

Why SFCC Matters

BenefitExplanation
ScalabilityHandles Black Friday-level traffic
Multi-siteManage multiple brands from one instance
Multi-currencySupport global commerce
Integration readyCRM, Marketing Cloud, ERP connectors
Cloud-nativeNo server management
SecurityPCI compliant, enterprise-grade security

Code Example:

// Multi-site and multi-currency example
function showStorefront() {
    var Site = require('dw/system/Site');
    var currentSite = Site.getCurrent();
    var currencies = currentSite.getAllowedCurrencies();
    
    res.render('storefront/landing', {
        siteName: currentSite.getName(),
        currencies: currencies,
        defaultCurrency: currentSite.getDefaultCurrency()
    });
}
exports.ShowStorefront = showStorefront;

The dw/system/Site module provides site configuration. Each site can have multiple currencies. The controller retrieves this information and passes it to the template for rendering.

Where and When SFCC is Used

Industries using SFCC:

IndustryUse Case
RetailGlobal e-commerce stores
FashionMulti-brand fashion retailers
ElectronicsConsumer electronics stores
Luxury goodsHigh-end brand stores
B2BWholesale portals

Companies using SFCC: Adidas, Sephora, L’Oréal, Timberland, Crocs.

Code Example:

// Product catalog for retail
function showProduct() {
    var ProductMgr = require('dw/catalog/ProductMgr');
    var productId = request.httpParameterMap.pid.stringValue;
    var product = ProductMgr.getProduct(productId);
    
    if (!product) {
        res.redirect(URLUtils.url('Search-Show'));
        return;
    }
    
    res.render('product/detail', {
        product: product,
        images: product.getImages(),
        variations: product.getVariationModel()
    });
}
exports.ShowProduct = showProduct;

The controller retrieves a product by ID using ProductMgr.getProduct(). If the product doesn’t exist, it redirects to search. Otherwise, it renders the product detail page with images and variations.

Prerequisites for Learning SFCC

PrerequisiteLevel Needed
JavaScriptFunctions, objects, promises
HTML/CSSBasic web development
REST APIsUnderstanding HTTP methods
Git basicsVersion control

Code Example:

// Basic JavaScript required for SFCC
// 1. Functions
function calculateDiscount(price, discountPercentage) {
    return price - (price * discountPercentage / 100);
}

// 2. Objects
const product = {
    id: 'P001',
    name: 'Running Shoes',
    price: 89.99,
    getFormattedPrice: function() {
        return `$${this.price.toFixed(2)}`;
    }
};

// 3. Async operations
async function fetchProductData(productId) {
    try {
        const response = await fetch(`/api/products/${productId}`);
        const data = await response.json();
        return data;
    } catch (error) {
        console.error('Error fetching product:', error);
        return null;
    }
}

// 4. ES6 features
const { id, name } = product;
const updatedProduct = { ...product, price: 79.99 };
const message = `Product: ${name}, Price: $${updatedProduct.price}`;

SFCC uses JavaScript on the server side (similar to Node.js). Understanding these fundamentals is essential for developing SFRA controllers, scripts, and hooks.

SFCC Architecture and Internal Working

SFCC Architecture Overview

SFCC uses a cloud-based, multi-tenant architecture with Business Manager for administration, OCAPI for APIs, and SFRA for storefront development.

┌─────────────────────────────────────────────────────────────┐
│                   Salesforce Commerce Cloud                 │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────────────────────────────────────────────┐   │
│  │                   Business Manager                   │   │
│  │     (Admin interface for catalogs, pricing, orders)  │   │
│  └─────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                      SFRA                           │   │
│  │  (Storefront Reference Architecture – Controllers,  │   │
│  │   Models, ISML Templates, Cartridges)               │   │
│  └─────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                      OCAPI                          │   │
│  │   (Open Commerce API – REST and GraphQL APIs)      │   │
│  └─────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │               Salesforce Cloud Runtime               │   │
│  │      (Scaling, security, multi-tenancy)            │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

Code Example:

// Example showing interaction with multiple layers
// Controller uses OCAPI-like approach to fetch data
function showDashboard() {
    // Business Manager configuration
    var Site = require('dw/system/Site');
    var siteSettings = Site.getCurrent().getCustomPreferences();
    
    // SFRA controller logic
    var ProductMgr = require('dw/catalog/ProductMgr');
    var recentProducts = ProductMgr.getProducts(0, 10);
    
    // OCAPI-style response
    res.json({
        siteName: Site.getCurrent().getName(),
        settings: siteSettings,
        products: recentProducts
    });
}
exports.ShowDashboard = showDashboard;

The controller interacts with multiple layers: Business Manager settings via Site, SFRA logic via ProductMgr, and returns a response. This demonstrates the integrated nature of SFCC architecture.

Understanding Business Manager

Business Manager is the admin interface for managing catalogs, products, pricing, orders, promotions, and site configuration.

Key Sections:

SectionPurpose
CatalogsManage product catalogs and categories
ProductsAdd/edit products, variants, bundles
PricingSet price books and price adjustments
PromotionsCreate discounts and campaigns
OrdersView and manage customer orders
SitesConfigure multi-site settings
Merchant ToolsImport/export data, manage inventory

Code Example:

// Business Manager settings accessible in code
function showSiteSettings() {
    var Site = require('dw/system/Site');
    var currentSite = Site.getCurrent();
    
    // Retrieve custom preferences set in Business Manager
    var customPrefs = currentSite.getCustomPreferences();
    var sitePreferences = {
        siteName: currentSite.getName(),
        siteID: currentSite.getID(),
        defaultCurrency: currentSite.getDefaultCurrency(),
        allowedCurrencies: currentSite.getAllowedCurrencies().toArray(),
        customSettings: {
            enableGuestCheckout: customPrefs.get('enableGuestCheckout'),
            maxQuantity: customPrefs.get('maxQuantity'),
            defaultImage: customPrefs.get('defaultProductImage')
        }
    };
    
    res.render('admin/settings', {
        preferences: sitePreferences
    });
}
exports.ShowSiteSettings = showSiteSettings;

Business Manager settings are accessible through the dw/system/Site module. Custom preferences can be defined in Business Manager and retrieved in controllers. This allows configuration without code changes.

Introduction to SFRA (Storefront Reference Architecture)

SFRA is the modern, modular framework for building storefronts on SFCC. It replaces legacy pipelines with controller-based architecture.

SFRA Key Concepts:

ConceptDescription
ControllersHandle HTTP requests (like Express routes)
ModelsBusiness logic and data processing
ISML TemplatesHTML rendering (similar to JSX)
CartridgesModular code packages
HooksExtend functionality without modifying core

Code Example:

// SFRA architecture in action
// 1. Controller (handles request)
function showProduct() {
    var ProductMgr = require('dw/catalog/ProductMgr');
    var productId = request.httpParameterMap.pid.stringValue;
    var product = ProductMgr.getProduct(productId);
    
    // 2. Model (business logic)
    var productModel = new ProductModel(product);
    var productData = productModel.getProductData();
    
    // 3. ISML Template (rendering)
    res.render('product/detail', {
        product: productData
    });
}
exports.ShowProduct = showProduct;

// 4. Cartridge organization
// File: cartridges/app_storefront_base/cartridge/controllers/Product.js
// The controller is part of a cartridge, which is a modular package

SFRA organizes code into cartridges. Controllers handle requests and orchestrate models. Models contain business logic. ISML templates render the HTML output. Keeping different responsibilities separate makes the codebase easier to maintain, understand, and test.

Execution Flow (Browser → Controller → Model → ISML → Response)

Browser sends HTTP request
        │
        ▼
Controller handles the request (routes to specific action)
        │
        ▼
Model/Script processes business logic
        │
        ▼
ISML Template renders HTML output
        │
        ▼
Response sent back to browser

Code Example:

// Complete execution flow example
// 1. Browser request: /Product-Show?pid=001

// 2. Controller (Product.js)
function show() {
    // Get product ID from request
    var productId = request.httpParameterMap.pid.stringValue;
    
    // 3. Model logic
    var ProductMgr = require('dw/catalog/ProductMgr');
    var product = ProductMgr.getProduct(productId);
    
    // Process product data
    var productData = {
        id: product.getID(),
        name: product.getName(),
        price: product.getPriceModel().getPrice(),
        images: product.getImages(),
        description: product.getLongDescription()
    };
    
    // 4. ISML Template rendering
    res.render('product/detail', {
        product: productData,
        title: productData.name
    });
}
exports.Show = show;

// 5. ISML Template (product/detail.isml)
// <html>
//   <head><title>${title}</title></head>
//   <body>
//     <h1>${product.name}</h1>
//     <p>Price: ${product.price}</p>
//   </body>
// </html>

// 6. Response sent to browser
  1. Browser sends a request to /Product-Show?pid=001
  2. SFRA routes to Product.js controller, show() function
  3. Controller uses ProductMgr to fetch product data
  4. Data is processed and prepared for the template
  5. ISML template renders HTML with the product data
  6. HTML response is sent back to the browser

Module System (Cartridges)

Cartridges are modular code packages containing controllers, scripts, templates, and static assets.

Cartridge Loading Order (Highest to Lowest Priority):

  1. Custom cartridge (your code)
  2. Plugin cartridges (extensions)
  3. app_storefront_base (core SFRA)
  4. Modules (dependencies)

Rule: If the same file exists in multiple cartridges, the one in the highest priority cartridge wins.

Code Example:

// Cartridge structure
// cartridges/
// ├── app_storefront_base/           (Core SFRA)
// │   ├── controllers/
// │   ├── scripts/
// │   ├── templates/
// │   └── static/
// ├── plugin_paypal/                 (Plugin)
// │   ├── controllers/
// │   └── scripts/
// └── my_custom_cartridge/           (Your code - highest priority)
//     ├── controllers/
//     ├── scripts/
//     ├── templates/
//     └── static/

// Overriding a core controller
// In my_custom_cartridge/controllers/Product.js
function show() {
    // This overrides the core Product.js show() function
    // because my_custom_cartridge has higher priority
    var ProductMgr = require('dw/catalog/ProductMgr');
    var productId = request.httpParameterMap.pid.stringValue;
    var product = ProductMgr.getProduct(productId);
    
    // Add custom logic
    var customData = getCustomProductData(product);
    
    res.render('product/detail', {
        product: product,
        customData: customData
    });
}
exports.Show = show;

Cartridges are loaded in priority order. When a request comes in, SFRA searches for the controller in each cartridge in order. The first matching file is used. This allows customization without modifying core code.

Cartridge Path and Loading Order

The cartridge path determines which cartridges are loaded and in what order. This is configured in Business Manager.

To configure cartridge path:

  1. Log into Business Manager
  2. Go to Administration → Sites → Manage Sites
  3. Select your site
  4. Go to Settings → Developer Settings
  5. Update the Cartridge Path field

Example Cartridge Path:

my_custom_cartridge:plugin_paypal:app_storefront_base
  • Cartridges are loaded left to right
  • Leftmost has highest priority
  • If my_custom_cartridge has a controllers/Home.js, it overrides the one in app_storefront_base

Code Example:

// Understanding cartridge path resolution
// Given cartridge path: my_custom:plugin:app_storefront_base

// Request: /Home-Show
// 1. Check my_custom/controllers/Home.js → Found, use this
// 2. If not found, check plugin/controllers/Home.js
// 3. If not found, check app_storefront_base/controllers/Home.js

// Override example
// my_custom/controllers/Home.js
function show() {
    // This overrides the core Home.js
    res.render('home/custom', {
        message: 'Custom home page from my_custom cartridge'
    });
}
exports.Show = show;

SFRA resolves controller lookups based on the cartridge path order. This allows developers to customize functionality by placing their own files in a higher-priority cartridge without modifying the base cartridge.

Project Folder Structure

sfcc-project/
│
├── cartridges/                            # All cartridge code
│   ├── app_storefront_base/               # Core SFRA cartridge (provided)
│   │   ├── controllers/                   # Controllers for routes
│   │   │   ├── Home.js
│   │   │   ├── Product.js
│   │   │   └── Search.js
│   │   ├── scripts/                       # Business logic scripts
│   │   │   ├── helpers/
│   │   │   └── models/
│   │   ├── templates/                     # ISML templates
│   │   │   └── default/
│   │   │       ├── home/
│   │   │       ├── product/
│   │   │       └── search/
│   │   └── static/                        # CSS, JS, images
│   │       ├── css/
│   │       ├── js/
│   │       └── images/
│   └── my_custom_cartridge/               # YOUR custom code
│       ├── controllers/
│       │   └── Hello.js
│       ├── scripts/
│       ├── templates/
│       │   └── default/
│       │       └── hello.isml
│       ├── static/
│       └── package.json
│
├── .gitignore
├── package.json
└── README.md

Code Example:

// Adding a new custom cartridge
// Step 1: Create folder structure
// cartridges/my_custom_cartridge/controllers/Hello.js
// cartridges/my_custom_cartridge/templates/default/hello.isml
// cartridges/my_custom_cartridge/package.json

// Step 2: Create package.json
{
    "name": "my_custom_cartridge",
    "version": "1.0.0",
    "description": "My custom SFRA cartridge",
    "main": "index.js",
    "author": "Your Name"
}

// Step 3: Add to cartridge path in Business Manager
// my_custom_cartridge:app_storefront_base

// Step 4: Deploy
// sfcc-ci code:upload --sandbox my-sandbox --code-version custom

The project structure organizes code into cartridges. Each cartridge contains controllers, scripts, templates, and static assets. Custom cartridges are placed alongside the core SFRA cartridge. The cartridge path determines which code is used.

Internal Pipeline (Code → Output)

Write code in cartridges
        │
        ▼
Deploy to sandbox via Business Manager or sfcc-ci
        │
        ▼
SFCC runtime loads cartridges in order (cartridge path)
        │
        ▼
Browser request hits controller (e.g., /Hello-Show)
        │
        ▼
Controller calls scripts/models
        │
        ▼
ISML template renders output
        │
        ▼
HTML sent to browser
        │
        ▼
Logs and monitoring provide runtime insights

Code Example:

// Complete pipeline example

// 1. Write code in cartridge
// cartridges/my_custom/controllers/Hello.js
function show() {
    res.render('hello', {
        message: 'Hello from SFRA!'
    });
}
exports.Show = show;

// 2. Deploy
// sfcc-ci code:upload --sandbox dev-sandbox --code-version v1

// 3. Runtime loads cartridges
// my_custom:app_storefront_base

// 4. Browser request
// https://dev-sandbox.demandware.net/on/demandware.store/Sites-Site/default/Hello-Show

// 5. Controller executes
// -> show() function runs
// -> res.render('hello', {...})

// 6. ISML renders
// templates/default/hello.isml -> HTML

// 7. Response
// HTML sent to browser

// 8. Logging
// Logs appear in Business Manager > Administration > Logs

The development pipeline involves writing code, deploying it, and testing it in a sandbox. The runtime loads cartridges in priority order. Requests are routed to controllers. Controllers execute logic and render templates. Responses are sent back to browsers. Logs provide visibility into runtime behavior.

Environment Setup and First Application

Sandbox Setup and Access

A sandbox is a development environment for building and testing SFCC code. Sandboxes allow development without affecting production.

Sandbox Access Steps:

  1. Request sandbox access from Salesforce
  2. Receive credentials for Business Manager
  3. Business Manager URL: https://your-sandbox.demandware.net
  4. Example: https://dev01-sandbox.demandware.net

Code Example:

# Request sandbox access from Salesforce
# You will receive an email with credentials

# Example Business Manager URL:
# https://dev01-sandbox.demandware.net/on/demandware.store/Sites-Site/default/ViewApplication-Start

# Credentials example:
# Username: developer@company.com
# Password: TemporaryPassword123!

Sandboxes are isolated environments. Each sandbox has its own URL, database, and code version. Developers can make changes without affecting other environments. Sandboxes are ideal for development and testing.

Prerequisites for Environment Setup

System Requirements:

ComponentRequirement
OSWindows 10/11, macOS 11+, Ubuntu 22.04+
RAMMinimum 16 GB (strongly recommended)
StorageAt least 30 GB free space
InternetRequired for downloads
Node.jsv16.x or higher
GitLatest version
SFCC SandboxRequired (provided by Salesforce)
BrowserChrome, Firefox, or Edge
Text EditorVS Code (recommended)

Code Example:

# Check system requirements
# Node.js version
node -v

# npm version
npm -v

# Git version
git --version

# Check memory
# Linux: free -h
# macOS: system_profiler SPHardwareDataType | grep Memory
# Windows: wmic memorychip get capacity

SFCC development requires Node.js for CLI tools, Git for version control, and sufficient RAM for running sandboxes and development tools. VS Code provides the best development experience with SFCC extensions.

Setup on Linux (Ubuntu) – Step by Step

Path 1: Command‑Line Environment

Step 1: Open Terminal

Press Ctrl + Alt + T.

Step 2: Update package list

sudo apt update
sudo apt upgrade -y

Step 3: Install Node.js and npm

sudo apt install nodejs npm -y

Step 4: Verify Node.js

node -v
npm -v

Step 5: Install Git

sudo apt install git -y

Step 6: Install Salesforce CLI

npm install -g @salesforce/cli

Step 7: Verify Salesforce CLI

sf --version

Step 8: Install sfcc-ci (SFCC deployment tool)

npm install -g sfcc-ci

Step 9: Verify sfcc-ci

sfcc-ci --version

Step 10: Create project folder

mkdir sfcc-project
cd sfcc-project
mkdir cartridges

Step 11: Clone SFRA (optional – for reference)

git clone https://github.com/SalesforceCommerceCloud/storefront-reference-architecture.git

Step 12: Authenticate to sandbox

sfcc-ci auth:login --username YOUR_USERNAME --password YOUR_PASSWORD

Step 13: List available sandboxes

sfcc-ci sandbox:list

Code Example:

// Testing the setup
// Create a test cartridge
mkdir -p cartridges/test_cartridge/controllers
cd cartridges/test_cartridge

// Create package.json
echo '{"name":"test_cartridge","version":"1.0.0"}' > package.json

// Create test controller
cat > controllers/Test.js << 'EOF'
function show() {
    res.render('test', { message: 'Setup successful!' });
}
exports.Show = show;
EOF

// Create test template
mkdir -p templates/default
cat > templates/default/test.isml << 'EOF'
<iscontent type="text/html"/>
<html>
<body>
    <h1>${message}</h1>
    <p>Your SFCC setup is working!</p>
</body>
</html>
EOF

// Deploy and test
sfcc-ci code:upload --sandbox YOUR_SANDBOX --code-version test

The setup installs all necessary tools. The test cartridge validates that the environment is correctly configured. The deployment uploads the code to the sandbox, and the template renders the success message.

Path 2: Professional IDE Environment

Step 1: Install Visual Studio Code

Download from code.visualstudio.com and install the .deb package.

Step 2: Install SFCC VS Code extension

code --install-extension salesforce.salesforcedx-vscode-commerce

Step 3: Open project folder

code ~/sfcc-project

Step 4: Configure VS Code settings

Create .vscode/settings.json:

{
    "files.associations": {
        "*.isml": "html",
        "*.ds": "javascript"
    },
    "editor.formatOnSave": true,
    "files.exclude": {
        "**/node_modules": true,
        "**/.git": true
    }
}

Step 5: Open integrated terminal (Ctrl+``) and run sfcc-ci auth:login`.

Code Example:

// .vscode/settings.json for SFCC development
{
    "files.associations": {
        "*.isml": "html",
        "*.ds": "javascript"
    },
    "editor.formatOnSave": true,
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "files.exclude": {
        "**/node_modules": true,
        "**/.git": true
    },
    "workbench.colorTheme": "Dracula",
    "editor.fontSize": 14,
    "terminal.integrated.shell.linux": "/bin/bash"
}

VS Code extensions provide syntax highlighting and formatting for SFCC files. Settings optimize the editor for SFCC development. The integrated terminal allows running commands without leaving the editor.

Path 3: Full AI‑Integrated Development Workflow

Step 1: Install GitHub Copilot in VS Code.

Step 2: Generate a controller with Copilot

In a new file cartridges/my_custom_cartridge/controllers/Hello.js, type // SFRA controller for Hello World and let Copilot suggest the code.

Step 3: Use ChatGPT for explanations

Ask “How does SFRA cartridge path override work?”

Step 4: Debug with AI

When you see a deployment error, copy it and ask “Why does my SFCC code upload fail?”

Step 5: Generate ISML template

Prompt: “Create an SFRA ISML template for a product card.”

Code Example:

// AI-generated controller with Copilot
// Prompt: "SFRA controller for Hello World"
// Copilot generated:
function show() {
    // This function renders a hello world page
    res.render('hello', {
        message: 'Hello World from Copilot!',
        timestamp: new Date().toISOString(),
        developer: 'AI-Assisted'
    });
}
exports.Show = show;

// AI-generated ISML template
// Prompt: "Create an SFRA ISML template for a product card"
// ChatGPT generated:
/*
<iscontent type="text/html" charset="utf-8"/>
<div class="product-card">
    <div class="product-image">
        <img src="${product.image}" alt="${product.name}"/>
    </div>
    <h3 class="product-name">${product.name}</h3>
    <div class="product-price">${product.price}</div>
    <button class="add-to-cart" data-pid="${product.id}">Add to Cart</button>
</div>
*/

AI tools can generate complete SFRA controllers and ISML templates. GitHub Copilot autocompletes code based on patterns and comments. ChatGPT can explain concepts, debug errors, and generate templates.

Setup on Windows – Step by Step

Path 1: Command‑Line Environment

Step 1: Install Node.js

Download LTS version from nodejs.org, run installer. Ensure “Add to PATH” is checked.

Step 2: Verify Node.js

node -v
npm -v

Step 3: Install Git from git-scm.com.

Step 4: Install Salesforce CLI

npm install -g @salesforce/cli

Step 5: Install sfcc-ci

npm install -g sfcc-ci

Step 6: Create project folder

mkdir %USERPROFILE%\Desktop\sfcc-project
cd %USERPROFILE%\Desktop\sfcc-project
mkdir cartridges

Step 7: Authenticate to sandbox

sfcc-ci auth:login --username YOUR_USERNAME --password YOUR_PASSWORD

Code Example:

// Windows-specific path handling
// In SFCC, paths use forward slashes regardless of OS
// Example: controllers/Home.js works on all platforms

// Windows environment variables
// USERPROFILE = C:\Users\YourName
// PATH includes Node.js and npm

Node.js and npm are installed via the Windows installer. Git provides version control. PowerShell is used for commands. SFCC code uses forward slashes, which work on all platforms.

Path 2: Professional IDE Environment

Step 1: Install VS Code from code.visualstudio.com, check “Add to PATH”.

Step 2: Install SFCC extension

code --install-extension salesforce.salesforcedx-vscode-commerce

Step 3: Open project

code %USERPROFILE%\Desktop\sfcc-project

Code Example:

// .vscode/settings.json for Windows
{
    "files.associations": {
        "*.isml": "html",
        "*.ds": "javascript"
    },
    "editor.formatOnSave": true,
    "terminal.integrated.defaultProfile.windows": "PowerShell",
    "files.eol": "\n",
    "files.exclude": {
        "**/node_modules": true,
        "**/.git": true
    }
}

VS Code on Windows uses PowerShell as the default terminal. The settings optimize the editor for SFCC development. The files.eol setting ensures consistent line endings.

Path 3: Full AI‑Integrated Development Workflow

Same as Linux: install GitHub Copilot, use AI for code generation, debugging, and learning.

Code Example:

// AI-generated controller with error handling
// Prompt: "Create an SFRA controller with error handling"
// AI generated:
function show() {
    try {
        var ProductMgr = require('dw/catalog/ProductMgr');
        var productId = request.httpParameterMap.pid.stringValue;
        
        if (!productId) {
            res.redirect(URLUtils.url('Search-Show'));
            return;
        }
        
        var product = ProductMgr.getProduct(productId);
        
        if (!product) {
            res.render('error/notFound', {
                message: 'Product not found'
            });
            return;
        }
        
        res.render('product/detail', {
            product: product
        });
    } catch (error) {
        // Log error
        var Logger = require('dw/system/Logger');
        Logger.error('Product controller error: ' + error.message);
        
        res.render('error/generic', {
            message: 'An error occurred'
        });
    }
}
exports.Show = show;

AI can generate robust controllers with error handling, validation, and logging. The generated code follows SFRA patterns and includes best practices.

Setup on macOS – Step by Step

Path 1: Command‑Line Environment

Step 1: Install Homebrew

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Step 2: Install Node.js

brew install node

Step 3: Install Git

brew install git

Step 4: Install Salesforce CLI

npm install -g @salesforce/cli

Step 5: Install sfcc-ci

npm install -g sfcc-ci

Step 6: Create project folder

mkdir ~/Desktop/sfcc-project
cd ~/Desktop/sfcc-project
mkdir cartridges

Step 7: Authenticate

sfcc-ci auth:login --username YOUR_USERNAME --password YOUR_PASSWORD

Code Example:

# macOS setup verification
# Check Node.js
node -v
# Should show v16.x or higher

# Check npm
npm -v
# Should show 8.x or higher

# Check sfcc-ci
sfcc-ci --version

# Check Salesforce CLI
sf --version

# Create and test a simple cartridge
cd ~/Desktop/sfcc-project/cartridges
mkdir test_cartridge
cd test_cartridge
mkdir controllers templates templates/default

# Create test controller
cat > controllers/Test.js << 'EOF'
function show() {
    res.render('test', { message: 'macOS setup working!' });
}
exports.Show = show;
EOF

# Create test template
cat > templates/default/test.isml << 'EOF'
<iscontent type="text/html"/>
<html><body><h1>${message}</h1></body></html>
EOF

Homebrew installs packages on macOS. Node.js and Git are installed via Homebrew. The SFCC CLI tools are installed via npm. The test cartridge validates the setup.

Path 2: Professional IDE Environment

Step 1: Install VS Code

brew install --cask visual-studio-code

Step 2: Install SFCC extension

code --install-extension salesforce.salesforcedx-vscode-commerce

Step 3: Open project

code ~/Desktop/sfcc-project

Code Example:

// .vscode/settings.json for macOS
{
    "files.associations": {
        "*.isml": "html",
        "*.ds": "javascript"
    },
    "editor.formatOnSave": true,
    "terminal.integrated.defaultProfile.osx": "zsh",
    "editor.fontSize": 14,
    "workbench.colorTheme": "Dracula",
    "files.exclude": {
        "**/node_modules": true,
        "**/.git": true
    }
}

VS Code on macOS uses zsh as the default shell. The settings optimize the editor for SFCC development. The brew install --cask command installs macOS applications.

Path 3: Full AI‑Integrated Development Workflow

Same as Linux/macOS.

Code Example:

// AI-assisted SFCC development
// Ask ChatGPT: "How do I create a custom SFRA cartridge?"

// ChatGPT response:
/*
1. Create folder structure:
cartridges/my_custom/
├── controllers/
├── scripts/
├── templates/default/
└── static/

2. Create package.json:
{
    "name": "my_custom",
    "version": "1.0.0"
}

3. Create a controller:
// controllers/Hello.js
function show() {
    res.render('hello', { message: 'Hello from custom cartridge!' });
}
exports.Show = show;

4. Create template:
// templates/default/hello.isml
<iscontent type="text/html"/>
<html><body><h1>${message}</h1></body></html>

5. Add to cartridge path in Business Manager:
my_custom:app_storefront_base

6. Deploy:
sfcc-ci code:upload --sandbox your-sandbox --code-version custom
*/

// GitHub Copilot can generate this code
// Just start typing the controller and it will autocomplete

AI can provide step-by-step guidance for SFCC development. ChatGPT explains concepts and provides code examples. GitHub Copilot generates code based on patterns and comments.

Installing Salesforce CLI and sfcc-ci

These tools are essential for interacting with Salesforce Commerce Cloud sandboxes.

Code Example:

# Install Salesforce CLI (used for general Salesforce development)
npm install -g @salesforce/cli

# Install sfcc-ci (specifically for Commerce Cloud code deployment)
npm install -g sfcc-ci

# Verify both
sf --version
sfcc-ci --version

# Common sfcc-ci commands
# Login to sandbox
sfcc-ci auth:login --username YOUR_USERNAME --password YOUR_PASSWORD

# List sandboxes
sfcc-ci sandbox:list

# Upload code
sfcc-ci code:upload --sandbox YOUR_SANDBOX --code-version VERSION_NAME

# Start sandbox
sfcc-ci sandbox:start --sandbox YOUR_SANDBOX

# Stop sandbox
sfcc-ci sandbox:stop --sandbox YOUR_SANDBOX

# Check status
sfcc-ci sandbox:status --sandbox YOUR_SANDBOX

sfcc-ci is the primary tool for interacting with SFCC sandboxes. It handles authentication, code deployment, and sandbox management. The auth:login command authenticates you to your sandbox. code:upload deploys your cartridges.

Environment Setup (VS Code, Extensions)

VS Code Extensions for SFCC:

code --install-extension salesforce.salesforcedx-vscode-commerce

VS Code Settings:

{
    "files.associations": {
        "*.isml": "html",
        "*.ds": "javascript"
    },
    "editor.formatOnSave": true,
    "files.exclude": {
        "**/node_modules": true,
        "**/.git": true
    }
}

The SFCC extension provides syntax highlighting, IntelliSense, and debugging support for SFRA development. File associations help VS Code recognize ISML and DS files. Format on save ensures consistent code style.

Your First Program – Hello World in SFRA (Complete Step-by-Step)

Creating Custom Cartridge Folder Structure

A custom cartridge is where you put your own code. It overrides core SFRA functionality. Never modify app_storefront_base directly – always use a custom cartridge.

Code Example:

# Navigate to cartridges folder
cd sfcc-project/cartridges

# Create your custom cartridge folder
mkdir my_custom_cartridge

# Create subfolders
cd my_custom_cartridge
mkdir controllers
mkdir scripts
mkdir templates
mkdir templates/default
mkdir static

Final structure:

cartridges/
└── my_custom_cartridge/
    ├── controllers/
    ├── scripts/
    ├── templates/default/
    └── static/

The custom cartridge structure mirrors the core SFRA structure. Controllers go in the controllers/ folder. Templates go in templates/default/. Static assets go in static/. This organization keeps code maintainable.

Creating package.json for Custom Cartridge

Every cartridge needs a package.json file for metadata.

Code Example:

{
    "name": "my_custom_cartridge",
    "version": "1.0.0",
    "description": "My custom SFRA cartridge for Hello World",
    "main": "index.js",
    "scripts": {},
    "author": "Your Name",
    "license": "ISC"
}

The package.json file identifies the cartridge. The name must match the cartridge folder name. The version helps track changes. The description explains the cartridge’s purpose.

Configuring Cartridge Path in Business Manager

The cartridge path determines which cartridges are loaded and in what order. Your custom cartridge must be in the path before app_storefront_base to override core files.

Step-by-step instructions:

  1. Log into your Business Manager
  2. URL: https://your-sandbox.demandware.net/on/demandware.store/Sites-Site/default/ViewApplication-Start
  3. Go to Administration → Sites → Manage Sites to access the site management settings.
  4. Click on your site name (e.g., “RefArch”)
  5. Go to Settings → Developer Settings tab
  6. Find “Cartridge Path” field
  7. Update the cartridge path to: my_custom_cartridge:app_storefront_base
  8. Click “Apply” and then “Save”

What this does:

  • my_custom_cartridge is loaded first (highest priority)
  • app_storefront_base is loaded second (fallback)
  • Your custom code will override core code

Code Example:

// Understanding cartridge path
// Given path: my_custom:app_storefront_base

// Request: /Hello-Show
// 1. Check my_custom/controllers/Hello.js → Found, use this
// 2. If not found, check app_storefront_base/controllers/Hello.js

// This allows you to override core files
// my_custom/controllers/Home.js will override app_storefront_base/controllers/Home.js

The cartridge path is evaluated left to right. The first cartridge containing the requested file is used. This allows developers to customize functionality without modifying core code.

Creating Hello World Controller

A controller handles HTTP requests. The file name determines the URL path.

Code Example:

// File: cartridges/my_custom_cartridge/controllers/Hello.js

// Introduction: This controller handles requests to /Hello-Show
// It renders an ISML template called 'hello' and passes data to it.

// This function runs when you access /Hello-Show
function show() {
    // res.render() renders an ISML template
    // 'hello' is the template name (hello.isml)
    // The second parameter passes data to the template
    res.render('hello', {
        message: 'Hello from SFRA Controller!',
        timestamp: new Date().toISOString(),
        developer: 'Your Name'
    });
}

// Export the show function – makes it available to the router
// URL pattern: /Hello-Show maps to Hello.js -> show() function
exports.Show = show;
CodeWhat it does
function show()Defines the controller action function
res.render('hello', {...})Renders the ISML template named ‘hello’
message: 'Hello...'Creates a variable named ‘message’ with string value
timestamp: new Date().toISOString()Creates a variable with current date/time
exports.Show = showExports function to router (maps to /Hello-Show)

URL pattern explained:

ComponentExampleSource
Controller nameHelloFile name (Hello.js)
Action nameShowExported function name (Show)
Full URL/Hello-ShowCombined

Creating Hello World ISML Template

ISML (Internet Store Markup Language) is the templating language used by Salesforce Commerce Cloud (SFCC) to generate and structure dynamic web pages.

Code Example:

<!-- File: cartridges/my_custom_cartridge/templates/default/hello.isml -->

<!-- Introduction: This ISML template receives data from the controller
     and renders HTML. Variables are output using ${variableName}. -->

<iscontent type="text/html" charset="utf-8" />

<!DOCTYPE html>
<html>
<head>
    <title>Hello SFRA</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            margin-top: 50px;
            background-color: #f5f5f5;
        }
        .message {
            color: #0070d2;
            font-size: 24px;
            margin-bottom: 20px;
        }
        .timestamp {
            color: #666;
            font-size: 14px;
            margin-bottom: 10px;
        }
        .developer {
            color: #999;
            font-size: 12px;
        }
    </style>
</head>
<body>
    <div class="message">
        <!-- ${message} outputs the 'message' variable from the controller -->
        ${message}
    </div>
    <div class="timestamp">
        <!-- ${timestamp} outputs the timestamp from controller -->
        Rendered at: ${timestamp}
    </div>
    <div class="developer">
        Developed by: ${developer}
    </div>
</body>
</html>
CodeWhat it does
<iscontent type="text/html" charset="utf-8" />Declares content type
${message}Outputs the ‘message’ variable from controller
${timestamp}Outputs the ‘timestamp’ variable from controller
${developer}Outputs the ‘developer’ variable from controller

Deploying to Sandbox

Deployment uploads your local code to the SFCC sandbox.

Code Example:

# From your project root (sfcc-project folder)
cd /path/to/sfcc-project

# Upload all cartridges to sandbox
sfcc-ci code:upload --sandbox YOUR_SANDBOX_NAME --code-version hello-world

# Start the sandbox (if not already running)
sfcc-ci sandbox:start --sandbox YOUR_SANDBOX_NAME

# Check deployment status
sfcc-ci sandbox:status --sandbox YOUR_SANDBOX_NAME

What these commands do:

CommandPurpose
code:uploadUploads your cartridges to the sandbox
code-versionA version label for your code (use any name)
sandbox:startStarts the sandbox runtime
sandbox:statusChecks sandbox status

The sfcc-ci code:upload command packages your cartridges and uploads them to the sandbox. The --code-version parameter creates a version label. The sandbox must be running for the code to be accessible.

Accessing the Route

Get your sandbox URL:

  • Business Manager URL: https://your-sandbox.demandware.net

Construct your storefront URL:

https://your-sandbox.demandware.net/on/demandware.store/Sites-Site/default/Hello-Show

Open in browser

Expected output:

Hello from SFRA Controller!
Rendered at: 2024-01-15T10:30:00.000Z
Developed by: Your Name

The URL follows the pattern: /{sandbox}/on/demandware.store/Sites-{site}/default/{Controller}-{Action}. The controller name comes from the file name (Hello.js). The action comes from the exported function (Show).

Line-by-Line Code Explanation

Controller (Hello.js) – Detailed explanation:

CodeWhat it does
function show()Defines the controller action function
res.render('hello', {...})Renders the ISML template named ‘hello’
message: 'Hello...'Creates a variable named ‘message’ with string value
timestamp: new Date().toISOString()Creates a variable with current date/time
exports.Show = showExports function to router (maps to /Hello-Show)

URL pattern explained:

ComponentExampleSource
Controller nameHelloFile name (Hello.js)
Action nameShowExported function name (Show)
Full URL/Hello-ShowCombined

ISML Template (hello.isml) – Detailed explanation:

CodeWhat it does
<iscontent type="text/html" charset="utf-8" />Declares content type
${message}Outputs the ‘message’ variable from controller
${timestamp}Outputs the ‘timestamp’ variable from controller
${developer}Outputs the ‘developer’ variable from controller

Troubleshooting Common Issues

ProblemLikely CauseSolution
404 Not FoundCartridge path not configuredCheck cartridge path in Business Manager
Template not foundISML file in wrong folderEnsure file is in templates/default/
Controller not foundController not exportedCheck exports.Show = show line
Changes not visibleCode not deployedRun sfcc-ci code:upload again
Sandbox not runningSandbox stoppedRun sfcc-ci sandbox:start

Debugging checklist:

✅ Is custom cartridge in cartridge path?
✅ Is controller file named correctly (Hello.js)?
✅ Is function exported (exports.Show = show)?
✅ Is template in templates/default/ folder?
✅ Did you deploy after changes?
✅ Is sandbox running?

Code Example:

// Common debugging techniques

// 1. Add logging
var Logger = require('dw/system/Logger');
function show() {
    Logger.info('Hello controller called');
    // ... rest of code
}

// 2. Check if template exists
function show() {
    var Template = require('dw/util/Template');
    var templateExists = Template.hasTemplate('hello');
    Logger.info('Template exists: ' + templateExists);
    // ... rest of code
}

// 3. Check cartridge path
function show() {
    var Site = require('dw/system/Site');
    var path = Site.getCurrent().getCartridgePath();
    Logger.info('Cartridge path: ' + path);
    // ... rest of code
}

Logging provides runtime visibility. The Template module checks if templates exist. The Site module provides cartridge path information. These techniques help identify and resolve issues.

AI Integration with AI Tools

ChatGPT for SFRA Development

Example prompts:

  • “Create an SFRA controller for product search with pagination.”
  • “Explain how cartridge path override works in Salesforce Commerce Cloud.”
  • “Generate an ISML template for a product grid with lazy loading.”

Code Example:

// ChatGPT-generated SFRA controller for product search
// Prompt: "Create an SFRA controller for product search with pagination"

function show() {
    var ProductSearchModel = require('dw/catalog/ProductSearchModel');
    var searchQuery = request.httpParameterMap.q.stringValue;
    var page = request.httpParameterMap.page.intValue || 1;
    var pageSize = 12;
    
    var search = new ProductSearchModel();
    search.setSearchPhrase(searchQuery);
    search.search();
    
    var products = search.getProductSearchHits().asList();
    var total = search.getProductSearchHits().getTotalCount();
    
    res.render('search/results', {
        products: products,
        total: total,
        page: page,
        pageSize: pageSize,
        query: searchQuery
    });
}
exports.Show = show;

ChatGPT generates complete SFRA controllers based on natural language prompts. The generated code follows SFRA patterns and includes proper error handling.

GitHub Copilot

Install GitHub Copilot in VS Code. Use it to:

  • Autocomplete controller functions
  • Generate ISML template structures
  • Suggest script helper functions

Code Example:

// Type: "SFRA controller for product detail"
// GitHub Copilot autocompletes:
function show() {
    var ProductMgr = require('dw/catalog/ProductMgr');
    var productId = request.httpParameterMap.pid.stringValue;
    var product = ProductMgr.getProduct(productId);
    
    if (!product) {
        res.redirect(URLUtils.url('Search-Show'));
        return;
    }
    
    res.render('product/detail', {
        product: product,
        categories: product.getCategories().asList()
    });
}
exports.Show = show;

Copilot analyzes the code context and suggests completions. It understands SFRA patterns and generates idiomatic code.

AI Controller Generation

Create an SFRA controller for user registration that validates the submitted data, handles validation errors, and securely creates the user account when the input is valid.

Code Example:

// AI-generated user registration controller
function show() {
    res.render('account/register');
}
exports.Show = show;

function submit() {
    var form = request.httpParameterMap;
    var firstName = form.firstName.stringValue;
    var lastName = form.lastName.stringValue;
    var email = form.email.stringValue;
    var password = form.password.stringValue;
    var confirmPassword = form.confirmPassword.stringValue;
    
    // Validation
    var errors = {};
    if (!firstName || firstName.length < 2) {
        errors.firstName = 'First name is required';
    }
    if (!lastName || lastName.length < 2) {
        errors.lastName = 'Last name is required';
    }
    if (!email || !email.contains('@')) {
        errors.email = 'Valid email is required';
    }
    if (!password || password.length < 8) {
        errors.password = 'Password must be at least 8 characters';
    }
    if (password !== confirmPassword) {
        errors.confirmPassword = 'Passwords do not match';
    }
    
    // Check if email already exists
    var CustomerMgr = require('dw/customer/CustomerMgr');
    var existingCustomer = CustomerMgr.getCustomerByEmail(email);
    if (existingCustomer) {
        errors.email = 'Email already registered';
    }
    
    if (Object.keys(errors).length > 0) {
        res.render('account/register', {
            errors: errors,
            form: form
        });
        return;
    }
    
    // Create customer
    var customer = CustomerMgr.createCustomer(email, password);
    customer.getProfile().setFirstName(firstName);
    customer.getProfile().setLastName(lastName);
    
    // Login
    session.privacy.userAuthenticated = true;
    session.privacy.customer = customer;
    
    res.redirect(URLUtils.url('Account-Show'));
}
exports.Submit = submit;

AI generates complete controllers with validation, error handling, and business logic. The code follows SFRA patterns and uses standard SFCC modules.

AI ISML Development

Prompt: “Write an ISML macro for a product card with image, name, price, and add-to-cart button.”

Code Example:

<!-- AI-generated ISML macro -->
<ismacro name="productCard" product="${product}" showAddToCart="${true}">
    <div class="product-card" data-pid="${product.id}">
        <div class="product-card__image">
            <isinclude template="product/components/primaryImage" product="${product}"/>
        </div>
        <div class="product-card__details">
            <h3 class="product-card__name">
                <a href="${URLUtils.url('Product-Show', 'pid', product.id)}">
                    ${product.name}
                </a>
            </h3>
            <div class="product-card__price">
                ${product.priceModel?.price?.formatted}
            </div>
            <div class="product-card__rating">
                <isinclude template="product/components/rating" rating="${product.averageRating}"/>
            </div>
            <isif condition="${showAddToCart && product.availabilityModel.isInStock()}">
                <button class="product-card__add-to-cart btn btn-primary" 
                        data-pid="${product.id}">
                    Add to Cart
                </button>
            </isif>
        </div>
    </div>
</ismacro>

AI generates reusable ISML macros with proper structure, styling, and functionality. The macro includes conditional rendering and links to other templates.

AI Commerce Optimization

Prompt: “Optimize my SFRA cartridges for better performance and cache efficiency.”

Code Example:

// AI-optimized controller with caching
function show() {
    var CacheMgr = require('dw/system/CacheMgr');
    var cacheKey = 'product_' + request.httpParameterMap.pid.stringValue;
    
    // Check cache first
    var cachedData = CacheMgr.get(cacheKey);
    if (cachedData) {
        res.render('product/detail', cachedData);
        return;
    }
    
    // Fetch data
    var ProductMgr = require('dw/catalog/ProductMgr');
    var product = ProductMgr.getProduct(request.httpParameterMap.pid.stringValue);
    
    // Prepare data
    var productData = {
        product: product,
        categories: product.getCategories().asList(),
        variations: product.getVariationModel(),
        images: product.getImages()
    };
    
    // Cache for 1 hour
    CacheMgr.put(cacheKey, productData, 3600);
    
    res.render('product/detail', productData);
}
exports.Show = show;

AI identifies performance bottlenecks and suggests optimizations. Caching reduces database load and improves response times. The optimized code uses SFCC’s built-in caching.

AI Debugging

When you encounter an error, copy the stack trace and ask: “Why is my SFRA controller returning a 500 error?”

Code Example:

// Error: "Cannot read property 'getProduct' of undefined"
// AI debugging response:
// "The ProductMgr module is not imported. Add: 
// var ProductMgr = require('dw/catalog/ProductMgr');"

// Error: "Template not found: hello"
// AI debugging response:
// "Check that hello.isml is in templates/default/ folder and
//  that the cartridge containing it is in the cartridge path."

// Error: "Controller not found: Hello"
// AI debugging response:
// "Check that Hello.js is in controllers/ folder and
//  that the show function is exported: exports.Show = show;"

AI analyzes error messages and stack traces to identify root causes. It provides specific solutions and references relevant documentation.

AI Architecture Planning

Prompt: “Design a multi‑site SFRA architecture for three global brands sharing 70% of code.”

Code Example:

// AI-architected multi-site structure
/*
Cartridge Structure:
├── core_shared/                    # 70% shared code
│   ├── controllers/
│   ├── scripts/
│   └── templates/default/
├── brand_a/                        # Brand A customization
│   └── controllers/
├── brand_b/                        # Brand B customization
│   └── controllers/
└── brand_c/                        # Brand C customization
    └── controllers/

Cartridge Path:
brand_a:brand_b:brand_c:core_shared:app_storefront_base

Shared components:
- Product catalog
- Search functionality
- Cart and checkout
- User accounts
- Promotions

Brand-specific components:
- Brand A: Luxury UI, custom payment
- Brand B: Discount-focused UI
- Brand C: Subscription-based commerce

Implementation:
var Site = require('dw/system/Site');
var currentSite = Site.getCurrent();
var brand = currentSite.getCustomPreferenceValue('brandName');
res.render('brand/' + brand + '/header');
*/

AI designs scalable architectures that maximize code reuse while allowing brand-specific customization. The structure uses cartridge priority for selective overrides.

Commerce Cloud Fundamentals

Business Manager

Business Manager is the admin interface for managing all commerce operations.

Key sections:

SectionPurpose
CatalogsProduct and category management
ProductsAdd/edit products, variants, bundles
PricingPrice books and adjustments
PromotionsDiscounts, coupons, campaigns
OrdersView and manage customer orders
SitesMulti-site configuration
Merchant ToolsImport/export, inventory

Code Example:

// Accessing Business Manager settings in code
var Site = require('dw/system/Site');
var currentSite = Site.getCurrent();

// Get custom preferences set in Business Manager
var customPreferences = currentSite.getCustomPreferences();
var enableGuestCheckout = customPreferences.get('enableGuestCheckout');
var maxQuantity = customPreferences.get('maxQuantity');

// Get site configuration
var siteConfig = {
    id: currentSite.getID(),
    name: currentSite.getName(),
    defaultCurrency: currentSite.getDefaultCurrency(),
    allowedCurrencies: currentSite.getAllowedCurrencies().toArray()
};

res.render('admin/config', {
    config: siteConfig,
    preferences: {
        enableGuestCheckout: enableGuestCheckout,
        maxQuantity: maxQuantity
    }
});

Business Manager configuration is accessible through the Site module. Custom preferences can be defined in Business Manager and retrieved in controllers. This allows configuration without code changes.

Sandboxes

Sandboxes are isolated development environments.

Types:

TypePurpose
Development SandboxCode development and testing
Staging SandboxPre-production testing
Production SandboxLive store

Code Example:

# List sandboxes
sfcc-ci sandbox:list

# Check sandbox status
sfcc-ci sandbox:status --sandbox my-sandbox

# Start sandbox
sfcc-ci sandbox:start --sandbox my-sandbox

# Stop sandbox
sfcc-ci sandbox:stop --sandbox my-sandbox

# Upload code to sandbox
sfcc-ci code:upload --sandbox my-sandbox --code-version v1.0.0

Sandboxes are isolated environments. Each sandbox has its own URL, database, and code version. Developers can make changes without affecting other environments.

Instances

An instance is a running environment of Commerce Cloud. Each sandbox has its own instance.

Code Example:

// Check instance information
var Instance = require('dw/system/Instance');
var instanceInfo = {
    type: Instance.getType(),
    isDevelopment: Instance.isDevelopment(),
    isStaging: Instance.isStaging(),
    isProduction: Instance.isProduction()
};

Logger.info('Instance type: ' + instanceInfo.type);

if (instanceInfo.isProduction) {
    // Production-specific logic
} else {
    // Development-specific logic
}

The Instance module provides information about the current runtime environment. This allows code to behave differently in development, staging, and production.

Code Deployment

Code is deployed using sfcc-ci or Business Manager.

Code Example:

# Deploy code using sfcc-ci
sfcc-ci code:upload --sandbox my-sandbox --code-version v1.0.0

# Deploy specific cartridge
sfcc-ci code:upload --sandbox my-sandbox --code-version custom --cartridge my_custom

# Deploy with activation (auto-start sandbox)
sfcc-ci code:upload --sandbox my-sandbox --code-version v1.0.0 --activate

The code:upload command packages cartridges and uploads them to the sandbox. The --code-version parameter creates a version label. The --activate flag starts the sandbox after deployment.

Data Replication

Data can be replicated between sandboxes for testing.

Code Example:

# Replicate data from one sandbox to another
sfcc-ci data:replicate --source source-sandbox --target target-sandbox

# Replicate specific data types
sfcc-ci data:replicate --source source-sandbox --target target-sandbox --types products,prices

# Check data replication status
sfcc-ci data:status --sandbox target-sandbox

Data replication copies catalogs, products, pricing, and other data between sandboxes. This allows testing with realistic data without affecting production.

JavaScript Foundations

Variables

Code Example:

// JavaScript variables in SFCC context
var productId = 'P001';      // function-scoped, hoisted
let price = 29.99;           // block-scoped, can reassign
const TAX_RATE = 0.08;       // block-scoped, constant

// In SFCC, var is commonly used in controllers
var ProductMgr = require('dw/catalog/ProductMgr');
var product = ProductMgr.getProduct(productId);

// let and const are also supported (SFCC uses modern JavaScript)
let quantity = 1;
const maxQuantity = 10;

Variables store data. var is function-scoped and hoisted. let is block-scoped and can be reassigned. const is block-scoped and cannot be reassigned. SFCC supports all three.

Functions

Code Example:

// Function declaration (hoisted)
function calculateTotal(price, quantity) {
    return price * quantity;
}

// Function expression
const applyDiscount = function(total, discount) {
    return total - (total * discount);
};

// Arrow function (modern)
const getFormattedPrice = (price) => {
    return '$' + price.toFixed(2);
};

// In SFCC controllers
function show() {
    var product = getProduct();
    var total = calculateTotal(product.price, 1);
    res.render('product/detail', {
        total: total
    });
}
exports.Show = show;

Functions encapsulate reusable logic. Arrow functions provide concise syntax. In SFCC, controllers export functions that handle HTTP requests.

Objects

Code Example:

// Object literal
const product = {
    id: 'P001',
    name: 'Running Shoes',
    price: 89.99,
    getFormattedPrice: function() {
        return '$' + this.price.toFixed(2);
    }
};

// Accessing properties
console.log(product.name);      // "Running Shoes"
console.log(product['price']);  // 89.99
console.log(product.getFormattedPrice()); // "$89.99"

// In SFCC, objects often come from data models
var productModel = {
    id: product.getID(),
    name: product.getName(),
    price: product.getPriceModel().getPrice().getValue()
};

Objects group related data and behavior. In SFCC, objects represent products, customers, orders, and other business entities.

Arrays

Code Example:

// Array declaration
const products = ['Shoe', 'Shirt', 'Hat'];
const productIds = ['P001', 'P002', 'P003'];

// Array methods
products.push('Socks');                    // Add to end
const first = products.shift();            // Remove from start
const filtered = products.filter(p => p.startsWith('S'));
const mapped = products.map(p => p.toUpperCase());

// In SFCC, arrays are used for collections
var categories = product.getCategories().asList();
var categoryNames = categories.map(function(cat) {
    return cat.getDisplayName();
});

Arrays store ordered collections. Common methods include push, pop, shift, unshift, filter, map, and reduce. In SFCC, many data models return arrays.

ES6 Features

Code Example:

// Destructuring
const product = { id: 'P001', name: 'Shoe', price: 89.99 };
const { id, name, price } = product;
console.log(id, name); // "P001 Shoe"

// Spread operator
const updatedProduct = { ...product, price: 79.99 };

// Template literals
console.log(`Product: ${name}, Price: $${price}`);

// Arrow functions (lexical this)
const product = {
    name: 'Shoe',
    getInfo: () => {
        // this is lexical (from outer scope)
        return this.name;
    }
};

// Default parameters
function calculateTotal(price, quantity = 1) {
    return price * quantity;
}

// Rest parameters
function sum(...numbers) {
    return numbers.reduce((a, b) => a + b, 0);
}

ES6 features are supported in modern SFCC. Destructuring extracts values. Spread copies objects. Template literals format strings. Arrow functions provide concise syntax.

SFRA Architecture

Cartridges

Cartridges are the fundamental unit of code organization in SFRA. Each cartridge is a self-contained module.

Code Example:

// Cartridge structure example
// cartridges/my_custom/
// ├── controllers/      # Route handlers
// ├── scripts/          # Business logic
// ├── templates/        # ISML templates
// ├── static/           # CSS, JS, images
// └── package.json      # Metadata

// Accessing resources from a cartridge
var MyHelper = require('*/cartridge/scripts/helpers/myHelper');
var myTemplate = 'product/detail';
var myStatic = '/static/css/main.css';

Cartridges organize code into logical units. Each cartridge has its own controllers, scripts, templates, and static assets. The require function loads scripts from cartridges.

Cartridge Paths

The cartridge path determines load order. Configured in Business Manager under Developer Settings.

Code Example:

// Cartridge path configuration
// In Business Manager: my_custom:app_storefront_base

// How resolution works:
// Request: /Home-Show
// 1. Check my_custom/controllers/Home.js → Found, use this
// 2. If not found, check app_storefront_base/controllers/Home.js

// Override example
// my_custom/controllers/Home.js
function show() {
    // This overrides the core Home.js
    res.render('home/custom', {
        message: 'Custom home page'
    });
}
exports.Show = show;

The cartridge path is evaluated left to right. The first cartridge containing the requested file is used. This allows customization without modifying core code.

Controllers

Controllers handle HTTP requests. File name = route prefix, exported function = action.

Code Example:

// File: controllers/Product.js

// Show product detail
function show() {
    var ProductMgr = require('dw/catalog/ProductMgr');
    var productId = request.httpParameterMap.pid.stringValue;
    var product = ProductMgr.getProduct(productId);
    
    res.render('product/detail', {
        product: product
    });
}

// Add product to cart
function addToCart() {
    var BasketMgr = require('dw/order/BasketMgr');
    var productId = request.httpParameterMap.pid.stringValue;
    var quantity = request.httpParameterMap.quantity.intValue || 1;
    
    var basket = BasketMgr.getCurrentBasket();
    basket.addProduct(productId, quantity);
    
    res.redirect(URLUtils.url('Cart-Show'));
}

// Export actions
exports.Show = show;
exports.AddToCart = addToCart;

URL mapping:

URLControllerAction
/Product-ShowProduct.jsShow
/Product-AddToCartProduct.jsAddToCart

Controllers define actions that handle requests. The file name provides the controller name. Exported functions provide actions. URLs follow the pattern /{Controller}-{Action}.

Middleware

Middleware runs before or after controller actions.

Code Example:

// Middleware functions
function authenticationMiddleware(req, res, next) {
    if (!session.privacy.userAuthenticated) {
        res.redirect(URLUtils.url('Login-Show'));
        return;
    }
    next();
}

function loggingMiddleware(req, res, next) {
    var Logger = require('dw/system/Logger');
    Logger.info('Request: ' + req.requestURI);
    next();
}

// Applying middleware
server.append('Show', function(req, res, next) {
    // This runs before the core Show action
    Logger.info('Before Show action');
    next();
});

server.prepend('Show', function(req, res, next) {
    // This runs after the core Show action
    Logger.info('After Show action');
    next();
});

Middleware functions intercept requests before or after controller actions. They can perform logging, authentication, validation, and other cross-cutting concerns.

Models

Models contain business logic, often using SFCC built-in modules.

Code Example:

// File: scripts/models/productModel.js
var ProductMgr = require('dw/catalog/ProductMgr');

function getProductData(productId) {
    var product = ProductMgr.getProduct(productId);
    if (!product) {
        return null;
    }
    
    return {
        id: product.getID(),
        name: product.getName(),
        price: product.getPriceModel().getPrice(),
        description: product.getLongDescription(),
        images: product.getImages().asList(),
        categories: product.getCategories().asList(),
        availability: product.getAvailabilityModel().getAvailability()
    };
}

function getProductRecommendations(productId) {
    // Business logic for recommendations
    var ProductMgr = require('dw/catalog/ProductMgr');
    var product = ProductMgr.getProduct(productId);
    var category = product.getCategories().asList()[0];
    return category.getProducts().asList().slice(0, 4);
}

module.exports = {
    getProductData: getProductData,
    getProductRecommendations: getProductRecommendations
};

Models encapsulate business logic. They use SFCC modules for data access. They return formatted data for controllers and templates.

Scripts

Reusable JavaScript modules stored in the scripts/ folder.

Code Example:

// File: scripts/helpers/cartHelper.js
var BasketMgr = require('dw/order/BasketMgr');
var ProductMgr = require('dw/catalog/ProductMgr');

function addToCart(productId, quantity) {
    var basket = BasketMgr.getCurrentBasket();
    if (!basket) {
        basket = BasketMgr.createBasket();
    }
    
    var product = ProductMgr.getProduct(productId);
    if (!product) {
        return { success: false, error: 'Product not found' };
    }
    
    basket.addProduct(productId, quantity);
    return { success: true, product: product };
}

function getCartTotal() {
    var basket = BasketMgr.getCurrentBasket();
    if (!basket) {
        return 0;
    }
    return basket.getTotalGrossPrice().getValue();
}

function getCartItems() {
    var basket = BasketMgr.getCurrentBasket();
    if (!basket) {
        return [];
    }
    return basket.getProductLineItems().asList();
}

module.exports = {
    addToCart: addToCart,
    getCartTotal: getCartTotal,
    getCartItems: getCartItems
};

Scripts contain reusable functions. They are loaded with require. They can be used in controllers, middleware, and other scripts.

ISML Development

ISML Fundamentals

ISML is a templating language similar to HTML with special tags.

Code Example:

<!-- Basic ISML template -->
<iscontent type="text/html" charset="utf-8" />

<!DOCTYPE html>
<html>
<head>
    <title>${pageTitle}</title>
</head>
<body>
    <isinclude template="components/header" />
    
    <main>
        <h1>${heading}</h1>
        <p>${message}</p>
        
        <isif condition="${isLoggedIn}">
            <p>Welcome back, ${userName}!</p>
        </isif>
        
        <isloop items="${products}" var="product">
            <div class="product">
                <h3>${product.name}</h3>
                <p>${product.price}</p>
            </div>
        </isloop>
    </main>
    
    <isinclude template="components/footer" />
</body>
</html>
TagPurpose
<iscontent>Declares content type
${variable}Outputs variable value
<isinclude>Includes another template
<isif>Conditional rendering
<isloop>Iterates over collections

Templates

Basic ISML template structure.

Code Example:

<!-- File: templates/default/product/detail.isml -->

<iscontent type="text/html" charset="utf-8" />

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>${product.name}</title>
    <link rel="stylesheet" href="${URLUtils.staticURL('/css/main.css')}">
</head>
<body>
    <isinclude template="components/header" />
    
    <main class="product-detail">
        <div class="product-images">
            <isloop items="${product.images}" var="image">
                <img src="${image.getAbsURL()}" alt="${product.name}">
            </isloop>
        </div>
        
        <div class="product-info">
            <h1>${product.name}</h1>
            <div class="product-price">${product.price}</div>
            <div class="product-description">${product.description}</div>
            
            <isif condition="${product.availability.inStock}">
                <form action="${URLUtils.url('Product-AddToCart')}" method="POST">
                    <input type="hidden" name="pid" value="${product.id}">
                    <input type="number" name="quantity" value="1" min="1" max="${product.availability.maxOrderQuantity}">
                    <button type="submit">Add to Cart</button>
                </form>
            </isif>
        </div>
    </main>
    
    <isinclude template="components/footer" />
</body>
</html>

Templates define the structure and content of pages. They include logic for conditional rendering and loops. They can include other templates.

Includes

Include other templates for reuse.

Code Example:

<!-- File: templates/default/components/header.isml -->
<header class="header">
    <div class="header-logo">
        <a href="${URLUtils.url('Home-Show')}">
            <img src="${URLUtils.staticURL('/images/logo.png')}" alt="Store Logo">
        </a>
    </div>
    <nav class="header-nav">
        <ul>
            <li><a href="${URLUtils.url('Search-Show')}">Search</a></li>
            <li><a href="${URLUtils.url('Cart-Show')}">Cart</a></li>
            <isif condition="${session.privacy.userAuthenticated}">
                <li><a href="${URLUtils.url('Account-Show')}">My Account</a></li>
                <li><a href="${URLUtils.url('Logout-Show')}">Logout</a></li>
            </isif>
            <isif condition="${!session.privacy.userAuthenticated}">
                <li><a href="${URLUtils.url('Login-Show')}">Login</a></li>
            </isif>
        </ul>
    </nav>
</header>

<!-- File: templates/default/product/detail.isml -->
<isinclude template="components/header" />
<!-- Rest of product detail -->
<isinclude template="components/footer" />

Includes allow template reuse. Header and footer are included on every page. This reduces duplication and improves maintainability.

Components (Macros)

Reusable components with parameters.

Code Example:

<!-- File: templates/default/components/productCard.isml -->
<ismacro name="productCard" product="${product}" showActions="${true}">
    <div class="product-card" data-pid="${product.id}">
        <div class="product-card__image">
            <isinclude template="product/components/primaryImage" product="${product}"/>
        </div>
        <div class="product-card__details">
            <h3 class="product-card__name">
                <a href="${URLUtils.url('Product-Show', 'pid', product.id)}">
                    ${product.name}
                </a>
            </h3>
            <div class="product-card__price">
                ${product.price}
            </div>
            <isif condition="${showActions && product.availability.inStock}">
                <button class="product-card__add-to-cart" 
                        data-pid="${product.id}">
                    Add to Cart
                </button>
            </isif>
        </div>
    </div>
</ismacro>

<!-- Usage -->
<isinclude template="components/productCard" product="${product}" showActions="${true}" />

Macros are reusable components that accept parameters. They encapsulate complex UI patterns. They can be used multiple times with different data.

Rendering Strategies

Server-side rendering (default), conditional rendering, and loops.

Code Example:

<!-- Conditional rendering -->
<isif condition="${product.availability.inStock}">
    <p class="in-stock">In Stock</p>
<iselseif condition="${product.availability.preOrderable}">
    <p class="pre-order">Pre-Order Now</p>
<iselse>
    <p class="out-of-stock">Out of Stock</p>
</isif>

<!-- Loops -->
<isloop items="${products}" var="product" status="loopStatus">
    <div class="product-item ${loopStatus.first ? 'first' : ''} ${loopStatus.last ? 'last' : ''}">
        <h3>${product.name}</h3>
        <p>${product.price}</p>
    </div>
    <isif condition="${loopStatus.last}">
        <p>Total products: ${loopStatus.count}</p>
    </isif>
</isloop>

<!-- Formatting -->
${product.price.formatted}
${product.createdAt.format('MMMM d, yyyy')}
${product.description.replace(/\n/g, '<br>')}

Conditional rendering with <isif> and <iselseif>. Loops with <isloop> provide iteration. Status variables provide loop context. Formatting functions transform data.

Controllers and Routing

Request Lifecycle

Request lifecycle steps:

  1. Browser request
  2. Route resolution (file + function)
  3. Pre‑middleware
  4. Controller execution
  5. Post‑middleware
  6. ISML rendering
  7. Response

Code Example:

// Complete request lifecycle example
// 1. Browser request: /Product-Show?pid=001

// 2. Route resolution
// Product.js controller, Show action

// 3. Pre‑middleware
server.append('Show', function(req, res, next) {
    Logger.info('Before Product-Show');
    next();
});

// 4. Controller execution
function show() {
    var productId = request.httpParameterMap.pid.stringValue;
    var product = ProductMgr.getProduct(productId);
    res.render('product/detail', { product: product });
}
exports.Show = show;

// 5. Post‑middleware
server.prepend('Show', function(req, res, next) {
    Logger.info('After Product-Show');
    next();
});

// 6. ISML rendering
// product/detail.isml generates HTML

// 7. Response
// HTML sent to browser

The request lifecycle is a sequence of events. Controllers handle the core logic. Middleware extends functionality. Templates render the response.

Route Handling

URL pattern: /{Controller}-{Action}

Examples:

URLControllerAction
/Home-ShowHome.jsShow
/Product-Show?pid=123Product.jsShow
/Search-Show?q=shoeSearch.jsShow
/Cart-AddProductCart.jsAddProduct

Code Example:

// Multiple actions in one controller
// File: controllers/Product.js

function show() {
    // /Product-Show
    var productId = request.httpParameterMap.pid.stringValue;
    var product = ProductMgr.getProduct(productId);
    res.render('product/detail', { product: product });
}

function addToCart() {
    // /Product-AddToCart
    var productId = request.httpParameterMap.pid.stringValue;
    var quantity = request.httpParameterMap.quantity.intValue || 1;
    BasketMgr.getCurrentBasket().addProduct(productId, quantity);
    res.redirect(URLUtils.url('Cart-Show'));
}

function getReviews() {
    // /Product-GetReviews?pid=123
    var productId = request.httpParameterMap.pid.stringValue;
    var reviews = getProductReviews(productId);
    res.json(reviews);
}

exports.Show = show;
exports.AddToCart = addToCart;
exports.GetReviews = getReviews;

Controllers can have multiple actions. Each action handles a different URL pattern. Query parameters provide additional data.

Middleware Chains

Middleware runs before or after controller actions.

Code Example:

// Authentication middleware
function authenticationMiddleware(req, res, next) {
    if (!session.privacy.userAuthenticated) {
        res.redirect(URLUtils.url('Login-Show'));
        return;
    }
    next();
}

// Cache middleware
function cacheMiddleware(req, res, next) {
    res.setCacheControl('max-age=3600');
    next();
}

// Logger middleware
function loggerMiddleware(req, res, next) {
    var Logger = require('dw/system/Logger');
    Logger.info('Request: ' + req.requestURI);
    next();
}

// Applying middleware to specific actions
server.append('Show', authenticationMiddleware);
server.append('Show', cacheMiddleware);
server.append('Show', loggerMiddleware);

// Global middleware (runs for all actions)
server.use(function(req, res, next) {
    Logger.info('Global middleware');
    next();
});

Middleware functions intercept requests. They can be applied globally or to specific actions. They can modify request/response objects. They call next() to continue the chain.

Controller Design

Best practices for controller design.

Code Example:

// File: controllers/Product.js

// Good: Single responsibility
function show() {
    var productId = request.httpParameterMap.pid.stringValue;
    var product = ProductMgr.getProduct(productId);
    
    if (!product) {
        res.redirect(URLUtils.url('Search-Show'));
        return;
    }
    
    var viewData = prepareProductViewData(product);
    res.render('product/detail', viewData);
}
exports.Show = show;

// Helper function for preparation
function prepareProductViewData(product) {
    return {
        product: product,
        categories: product.getCategories().asList(),
        images: product.getImages().asList(),
        variations: product.getVariationModel(),
        reviews: getProductReviews(product.getID()),
        recommendations: getRecommendations(product)
    };
}

// Validation
function addToCart() {
    var productId = request.httpParameterMap.pid.stringValue;
    var quantity = request.httpParameterMap.quantity.intValue || 1;
    
    if (!productId) {
        res.redirect(URLUtils.url('Search-Show'));
        return;
    }
    
    if (quantity < 1 || quantity > 10) {
        res.json({ error: 'Invalid quantity' });
        return;
    }
    
    var product = ProductMgr.getProduct(productId);
    if (!product) {
        res.json({ error: 'Product not found' });
        return;
    }
    
    BasketMgr.getCurrentBasket().addProduct(productId, quantity);
    res.json({ success: true });
}
exports.AddToCart = addToCart;

Good controllers are thin and delegate logic to models. They handle request/response concerns. They validate input. They render templates or return JSON.

Catalog Management

Products

Products are the core of any commerce system.

Code Example:

// Getting product data
var ProductMgr = require('dw/catalog/ProductMgr');

// Get product by ID
var product = ProductMgr.getProduct('P001');

// Product attributes
var productData = {
    id: product.getID(),
    name: product.getName(),
    description: product.getLongDescription(),
    price: product.getPriceModel().getPrice(),
    images: product.getImages(),
    categories: product.getCategories().asList()
};

// Check availability
var availability = product.getAvailabilityModel();
var inStock = availability.isInStock();
var quantity = availability.getInventoryRecord().getInStockQuantity();

// Get product variants
var variationModel = product.getVariationModel();
var variants = variationModel.getVariants();

Products are managed through ProductMgr. Each product has attributes, pricing, images, and availability. Products can have variants for size, color, etc.

Categories

Categories organize products.

Code Example:

// Getting category data
var CatalogMgr = require('dw/catalog/CatalogMgr');
var catalog = CatalogMgr.getSiteCatalog();

// Get category by ID
var category = catalog.getCategory('electronics');

// Category attributes
var categoryData = {
    id: category.getID(),
    name: category.getDisplayName(),
    description: category.getDescription(),
    products: category.getProducts().asList(),
    subcategories: category.getSubcategories().asList()
};

// Get product count
var productCount = category.getProductCount();

// Get root categories
var rootCategories = catalog.getRootCategory().getSubcategories();

Categories organize products hierarchically. Each category has subcategories and products. Categories can be used for navigation and filtering.

Variants

Products with variations (size, color, etc.).

Code Example:

// Working with product variants
var ProductMgr = require('dw/catalog/ProductMgr');
var product = ProductMgr.getProduct('P001');

// Get variation model
var variationModel = product.getVariationModel();

// Get all variants
var variants = variationModel.getVariants();

// Get variation attributes
var attributes = variationModel.getVariationAttributes();

// Get product option models
var optionModel = product.getOptionModel();

// Get selected variant by attribute values
var selectedVariant = variationModel.getVariantByAttributeValues({
    'color': 'red',
    'size': 'M'
});

Variants are products with different attributes. The variation model provides access to variants. Variants share common attributes like price and description.

Product Sets

Product sets are groups of products sold together.

Code Example:

// Working with product sets
var ProductMgr = require('dw/catalog/ProductMgr');
var productSet = ProductMgr.getProduct('PS001');

// Get product set components
var productSetComponents = productSet.getProductSetComponents();

// Get products in set
var productsInSet = productSetComponents.map(function(component) {
    return ProductMgr.getProduct(component.getProductID());
});

// Get default product set
var defaultProduct = productSet.getDefaultProduct();

// Render product set with components
res.render('product/productSet', {
    product: productSet,
    components: productsInSet,
    defaultProduct: defaultProduct
});

Product sets group multiple products. They can be used for bundles or kits. Components are individual products in the set.

Bundles

Bundles are discounted product combinations.

Code Example:

// Working with bundles
var ProductMgr = require('dw/catalog/ProductMgr');
var bundle = ProductMgr.getProduct('B001');

// Get bundle components
var bundleComponents = bundle.getBundleComponents();

// Get products in bundle
var productsInBundle = bundleComponents.map(function(component) {
    return {
        product: ProductMgr.getProduct(component.getProductID()),
        quantity: component.getQuantity(),
        fixed: component.isFixed()
    };
});

// Get bundle price
var bundlePrice = bundle.getPriceModel().getPrice();

// Add bundle to cart
var basket = BasketMgr.getCurrentBasket();
basket.addBundle(bundle, {
    'component1': 'product1',
    'component2': 'product2'
});

Bundles combine products at a discount. Components can be optional or fixed. The bundle price is typically less than the sum of components.

Customer Management

Registration

Customer registration creates new accounts.

Code Example:

// Registration controller
function register() {
    var CustomerMgr = require('dw/customer/CustomerMgr');
    var form = request.httpParameterMap;
    
    var email = form.email.stringValue;
    var password = form.password.stringValue;
    var firstName = form.firstName.stringValue;
    var lastName = form.lastName.stringValue;
    
    // Validate
    if (!email || !password) {
        res.render('account/register', {
            error: 'Email and password are required'
        });
        return;
    }
    
    // Check if email exists
    var existing = CustomerMgr.getCustomerByEmail(email);
    if (existing) {
        res.render('account/register', {
            error: 'Email already registered'
        });
        return;
    }
    
    // Create customer
    var customer = CustomerMgr.createCustomer(email, password);
    var profile = customer.getProfile();
    profile.setFirstName(firstName);
    profile.setLastName(lastName);
    
    // Login
    session.privacy.userAuthenticated = true;
    session.privacy.customer = customer;
    
    res.redirect(URLUtils.url('Account-Show'));
}
exports.Register = register;

Registration creates a new customer account. Validation ensures data quality. The account is created and the user is logged in.

Login

Login authenticates existing customers.

Code Example:

// Login controller
function show() {
    res.render('account/login');
}
exports.Show = show;

function authenticate() {
    var CustomerMgr = require('dw/customer/CustomerMgr');
    var form = request.httpParameterMap;
    
    var email = form.email.stringValue;
    var password = form.password.stringValue;
    
    // Login
    var login = CustomerMgr.loginCustomer(email, password);
    if (!login || !login.isAuthenticated()) {
        res.render('account/login', {
            error: 'Invalid email or password'
        });
        return;
    }
    
    // Set session
    var customer = login.getCustomer();
    session.privacy.userAuthenticated = true;
    session.privacy.customer = customer;
    
    res.redirect(URLUtils.url('Account-Show'));
}
exports.Authenticate = authenticate;

function logout() {
    session.privacy.userAuthenticated = false;
    session.privacy.customer = null;
    res.redirect(URLUtils.url('Home-Show'));
}
exports.Logout = logout;

Login authenticates the customer. The session is updated with customer information. Logout clears the session.

Profiles

Customer profiles store personal information.

Code Example:

// Profile management
function show() {
    var customer = session.privacy.customer;
    if (!customer) {
        res.redirect(URLUtils.url('Login-Show'));
        return;
    }
    
    var profile = customer.getProfile();
    var addressBook = customer.getAddressBook();
    
    res.render('account/profile', {
        profile: profile,
        addressBook: addressBook
    });
}
exports.Show = show;

function update() {
    var customer = session.privacy.customer;
    if (!customer) {
        res.redirect(URLUtils.url('Login-Show'));
        return;
    }
    
    var form = request.httpParameterMap;
    var profile = customer.getProfile();
    
    profile.setFirstName(form.firstName.stringValue);
    profile.setLastName(form.lastName.stringValue);
    profile.setPhone(form.phone.stringValue);
    
    res.redirect(URLUtils.url('Profile-Show'));
}
exports.Update = update;

Profiles store customer information. Users can view and update their profiles. Address books store shipping addresses.

Customer Groups

Customer groups enable segmentation and personalization.

Code Example:

// Working with customer groups
var CustomerMgr = require('dw/customer/CustomerMgr');
var customer = session.privacy.customer;

// Check customer groups
var isPremium = CustomerMgr.isMemberOfGroup(customer, 'premium');
var isWholesale = CustomerMgr.isMemberOfGroup(customer, 'wholesale');

// Get customer groups
var groups = CustomerMgr.getCustomerGroups(customer);

// Apply group-specific pricing
var priceModel = product.getPriceModel();
var price = priceModel.getPrice();
if (isPremium) {
    price = price.multiply(0.9); // 10% discount for premium
}

// Group-based personalization
res.render('product/detail', {
    product: product,
    isPremium: isPremium,
    isWholesale: isWholesale
});

Customer groups enable segmentation. Groups can be used for pricing, personalization, and access control. Customers can belong to multiple groups.

Search and Merchandising

Search Architecture

SFCC uses a powerful search engine for product discovery.

Code Example:

// Basic search
var ProductSearchModel = require('dw/catalog/ProductSearchModel');
var search = new ProductSearchModel();

// Set search phrase
search.setSearchPhrase('running shoes');

// Set search parameters
search.setSortingOption('price-asc');
search.setRefinementValues('color', ['red', 'blue']);

// Execute search
search.search();

// Get results
var results = search.getProductSearchHits();
var total = results.getTotalCount();
var products = results.asList();

// Display results
res.render('search/results', {
    products: products,
    total: total,
    searchTerm: 'running shoes'
});

ProductSearchModel handles search queries. Results can be filtered and sorted. Search returns product hits with relevance scoring.

Search Refinements

Refinements filter search results.

Code Example:

// Working with refinements
var ProductSearchModel = require('dw/catalog/ProductSearchModel');
var search = new ProductSearchModel();

// Set search phrase
search.setSearchPhrase('shoes');

// Add refinements
search.setRefinementValues('color', ['red', 'blue']);
search.setRefinementValues('size', ['M', 'L']);
search.setRefinementValues('price', { min: 50, max: 200 });
search.setRefinementValues('brand', ['nike', 'adidas']);

// Clear refinements
search.clearRefinements();

// Get available refinements
var refinements = search.getRefinements();
var colorRefinements = refinements.get('color');
var priceRefinements = refinements.get('price');

// Render refinements
res.render('search/refinements', {
    refinements: refinements
});

Refinements filter search results. They can be added and cleared. Available refinements are displayed to users.

Sorting

Sort search results by various criteria.

Code Example:

// Sort options
var ProductSearchModel = require('dw/catalog/ProductSearchModel');
var search = new ProductSearchModel();

// Set search phrase
search.setSearchPhrase('shoes');

// Sort by price
search.setSortingOption('price-asc');    // Low to high
search.setSortingOption('price-desc');   // High to low

// Sort by relevance
search.setSortingOption('relevance');

// Sort by rating
search.setSortingOption('rating-desc');

// Custom sort
search.setSortingOption('custom:popularity');

// Get current sort
var currentSort = search.getSortingOption();

// Render sort options
res.render('search/sort', {
    currentSort: currentSort,
    sortOptions: [
        { id: 'relevance', label: 'Relevance' },
        { id: 'price-asc', label: 'Price: Low to High' },
        { id: 'price-desc', label: 'Price: High to Low' },
        { id: 'rating-desc', label: 'Highest Rated' }
    ]
});

Sorting orders search results. Options include price, relevance, and rating. Users can select their preferred sort order.

Recommendations

Recommendations suggest products to customers.

Code Example:

// Product recommendations
var ProductMgr = require('dw/catalog/ProductMgr');

// Get products from same category
function getRelatedProducts(productId) {
    var product = ProductMgr.getProduct(productId);
    var category = product.getCategories().asList()[0];
    if (!category) {
        return [];
    }
    var allProducts = category.getProducts().asList();
    return allProducts.filter(function(p) {
        return p.getID() !== productId;
    }).slice(0, 4);
}

// Get frequently bought together
function getBoughtTogether(productId) {
    // Business logic for recommendations
    // Could be based on order history
    var recommendations = [
        'P001', 'P002', 'P003'
    ];
    return recommendations.map(function(id) {
        return ProductMgr.getProduct(id);
    });
}

// Get personal recommendations (based on browsing history)
function getPersonalRecommendations() {
    var customer = session.privacy.customer;
    if (!customer) {
        return [];
    }
    // Custom logic based on customer data
    return getRecentProducts(customer);
}

Recommendations suggest products based on categories, purchase history, or personalization. Business logic determines which products are recommended.

Cart and Checkout

Basket Architecture

The basket (cart) stores items before checkout.

Code Example:

// Working with basket
var BasketMgr = require('dw/order/BasketMgr');

// Get current basket
var basket = BasketMgr.getCurrentBasket();
if (!basket) {
    basket = BasketMgr.createBasket();
}

// Add product
basket.addProduct('P001', 2);

// Get product line items
var lineItems = basket.getProductLineItems();

// Update quantity
var lineItem = basket.getProductLineItem('P001');
lineItem.setQuantityValue(3);

// Remove product
basket.removeProductLineItem('P001');

// Get totals
var subtotal = basket.getSubtotalPrice();
var shipping = basket.getShippingTotalPrice();
var tax = basket.getTaxTotalPrice();
var total = basket.getTotalGrossPrice();

// Clear basket
basket.clear();

The basket stores products, quantities, and pricing. It calculates subtotals, shipping, tax, and total. Basket methods manage items and totals.

Checkout Flow

Checkout processes the order.

Code Example:

// Checkout flow
function start() {
    var basket = BasketMgr.getCurrentBasket();
    if (!basket || basket.getProductLineItems().size() === 0) {
        res.redirect(URLUtils.url('Cart-Show'));
        return;
    }
    
    res.render('checkout/start', {
        basket: basket,
        shippingAddresses: getCustomerAddresses()
    });
}
exports.Start = start;

function shipping() {
    var basket = BasketMgr.getCurrentBasket();
    var form = request.httpParameterMap;
    var shippingAddress = form.shippingAddress.stringValue;
    
    // Set shipping address
    var address = getAddress(shippingAddress);
    basket.setShippingAddress(address);
    
    // Calculate shipping
    var shippingMethods = getShippingMethods(address);
    
    res.render('checkout/shipping', {
        basket: basket,
        shippingMethods: shippingMethods
    });
}
exports.Shipping = shipping;

function payment() {
    var basket = BasketMgr.getCurrentBasket();
    var form = request.httpParameterMap;
    var shippingMethod = form.shippingMethod.stringValue;
    
    // Set shipping method
    basket.setShippingMethod(shippingMethod);
    
    // Calculate total
    var total = basket.getTotalGrossPrice();
    
    res.render('checkout/payment', {
        basket: basket,
        total: total
    });
}
exports.Payment = payment;

function placeOrder() {
    var basket = BasketMgr.getCurrentBasket();
    var form = request.httpParameterMap;
    var paymentMethod = form.paymentMethod.stringValue;
    
    // Set payment method
    basket.setPaymentMethod(paymentMethod);
    
    // Create order
    var order = basket.createOrder();
    
    // Clear basket
    BasketMgr.createBasket();
    
    res.render('checkout/confirmation', {
        order: order
    });
}
exports.PlaceOrder = placeOrder;

Checkout is a multi-step process. Steps include shipping address, shipping method, payment, and order placement. Each step saves data and progresses to the next.

Shipping

Shipping calculates delivery costs and methods.

Code Example:

// Shipping methods
var ShippingMgr = require('dw/order/ShippingMgr');

function getShippingMethods(address) {
    var basket = BasketMgr.getCurrentBasket();
    var shippingMethods = ShippingMgr.getShippingMethods();
    var applicableMethods = [];
    
    var shippingAddress = address || basket.getShippingAddress();
    if (!shippingAddress) {
        return shippingMethods;
    }
    
    shippingMethods.forEach(function(method) {
        var cost = method.getCost();
        var isEligible = method.isEligible(shippingAddress);
        if (isEligible) {
            applicableMethods.push({
                id: method.getID(),
                name: method.getDisplayName(),
                cost: cost,
                estimatedDays: method.getEstimatedDays()
            });
        }
    });
    
    return applicableMethods;
}

function calculateShipping(address) {
    var basket = BasketMgr.getCurrentBasket();
    var shippingMethods = ShippingMgr.getShippingMethods();
    var bestMethod = null;
    var bestCost = null;
    
    shippingMethods.forEach(function(method) {
        if (method.isEligible(address)) {
            var cost = method.getCost();
            if (bestCost === null || cost < bestCost) {
                bestCost = cost;
                bestMethod = method;
            }
        }
    });
    
    return {
        method: bestMethod,
        cost: bestCost
    };
}

Shipping methods are determined by address. Each method has eligibility rules and costs. The best method is selected based on cost and availability.

Taxation

Taxation calculates taxes based on location and product.

Code Example:

// Tax calculation
var TaxMgr = require('dw/order/TaxMgr');

function calculateTax(basket, shippingAddress) {
    var items = basket.getProductLineItems();
    var totalTax = 0;
    
    items.forEach(function(item) {
        var price = item.getPrice();
        var quantity = item.getQuantityValue();
        var taxRate = TaxMgr.getTaxRate(item.getProduct(), shippingAddress);
        var tax = price * quantity * taxRate;
        totalTax += tax;
    });
    
    return totalTax;
}

function getTaxRate(product, address) {
    var taxClass = product.getTaxClass();
    var taxRate = TaxMgr.getTaxRate(taxClass, address);
    return taxRate;
}

// Display tax info
res.render('checkout/tax', {
    taxRate: getTaxRate(product, address),
    taxAmount: calculateTax(basket, address),
    totalWithTax: subtotal + calculateTax(basket, address)
});

Taxation uses tax classes and rates. Tax is calculated based on product tax class and shipping address. Total tax is the sum of tax on all items.

Payments

Payment processing handles transactions.

Code Example:

// Payment processing
var PaymentMgr = require('dw/order/PaymentMgr');

function processPayment(order, paymentMethod) {
    // Get payment processor
    var processor = PaymentMgr.getPaymentProcessor(paymentMethod);
    if (!processor) {
        return { success: false, error: 'Payment method not supported' };
    }
    
    // Create payment transaction
    var transaction = processor.createTransaction();
    transaction.setAmount(order.getTotalGrossPrice());
    transaction.setCurrencyCode(order.getCurrencyCode());
    
    // Process payment
    var result = processor.processPayment(transaction);
    if (!result.isSuccessful()) {
        return { success: false, error: result.getErrorMessage() };
    }
    
    // Add payment to order
    order.addPayment(transaction);
    
    return { success: true, transaction: transaction };
}

// Payment method validation
function validatePaymentMethod(paymentMethod) {
    var PaymentMgr = require('dw/order/PaymentMgr');
    var processor = PaymentMgr.getPaymentProcessor(paymentMethod);
    if (!processor) {
        return false;
    }
    return processor.isAvailable();
}

Payment processing uses payment processors. Each processor handles specific payment methods. Transactions are created and processed. Successful payments are added to orders.

Promotions and Campaigns

Discounts

Discounts reduce the price of products or orders.

Code Example:

// Applying discounts
var PromotionMgr = require('dw/campaign/PromotionMgr');

function applyDiscounts(basket) {
    // Get applicable promotions
    var promotions = PromotionMgr.getPromotions();
    var applicablePromotions = [];
    
    promotions.forEach(function(promo) {
        if (promo.isEligible(basket)) {
            applicablePromotions.push(promo);
        }
    });
    
    // Apply promotions
    applicablePromotions.forEach(function(promo) {
        promo.apply(basket);
    });
    
    // Calculate discount totals
    var discountTotal = basket.getDiscountTotal();
    
    return {
        appliedPromotions: applicablePromotions,
        discountTotal: discountTotal,
        totalAfterDiscount: basket.getTotalGrossPrice()
    };
}

// Check discount eligibility
function isEligibleForDiscount(productId, customer) {
    var product = ProductMgr.getProduct(productId);
    var promotions = PromotionMgr.getPromotions();
    
    for (var i = 0; i < promotions.length; i++) {
        var promo = promotions[i];
        if (promo.isEligibleForProduct(product) &&
            promo.isEligibleForCustomer(customer)) {
            return true;
        }
    }
    return false;
}

Promotions apply discounts to products or orders. Eligibility is based on customer, product, and order criteria. Discount totals are calculated and applied.

Coupons

Coupons are codes that unlock discounts.

Code Example:

// Coupon handling
function applyCoupon(couponCode) {
    var PromotionMgr = require('dw/campaign/PromotionMgr');
    var coupon = PromotionMgr.getCoupon(couponCode);
    var basket = BasketMgr.getCurrentBasket();
    
    if (!coupon) {
        return { success: false, error: 'Invalid coupon code' };
    }
    
    if (!coupon.isValid()) {
        return { success: false, error: 'Coupon has expired' };
    }
    
    if (coupon.hasBeenUsed()) {
        return { success: false, error: 'Coupon has already been used' };
    }
    
    // Apply coupon
    basket.addCoupon(couponCode);
    var discount = coupon.getDiscount();
    
    return {
        success: true,
        discount: discount,
        newTotal: basket.getTotalGrossPrice()
    };
}

function removeCoupon(couponCode) {
    var basket = BasketMgr.getCurrentBasket();
    basket.removeCoupon(couponCode);
    
    return {
        success: true,
        newTotal: basket.getTotalGrossPrice()
    };
}

Coupons are codes that apply discounts. They have validity periods and usage limits. Coupons can be applied and removed from baskets.

Campaigns

Campaigns group promotions for specific events or seasons.

Code Example:

// Campaign management
function getActiveCampaigns() {
    var CampaignMgr = require('dw/campaign/CampaignMgr');
    var campaigns = CampaignMgr.getCampaigns();
    var activeCampaigns = [];
    var now = new Date();
    
    campaigns.forEach(function(campaign) {
        if (campaign.isActive() &&
            campaign.getStartDate() <= now &&
            campaign.getEndDate() >= now) {
            activeCampaigns.push(campaign);
        }
    });
    
    return activeCampaigns;
}

function getCampaignPromotions(campaignId) {
    var CampaignMgr = require('dw/campaign/CampaignMgr');
    var campaign = CampaignMgr.getCampaign(campaignId);
    if (!campaign) {
        return [];
    }
    return campaign.getPromotions().asList();
}

function showCampaignBanner(campaignId) {
    var CampaignMgr = require('dw/campaign/CampaignMgr');
    var campaign = CampaignMgr.getCampaign(campaignId);
    
    if (!campaign || !campaign.isActive()) {
        return null;
    }
    
    return {
        id: campaign.getID(),
        name: campaign.getDisplayName(),
        description: campaign.getDescription(),
        image: campaign.getImage(),
        promotion: campaign.getPromotions().asList()[0]
    };
}

Campaigns organize promotions by time period. They have start and end dates. Campaigns can be seasonal or event-based. Active campaigns are displayed to customers.

Personalized Promotions

Personalized promotions target specific customers.

Code Example:

// Personalized promotions
function getPersonalizedPromotions(customer) {
    var PromotionMgr = require('dw/campaign/PromotionMgr');
    var promotions = PromotionMgr.getPromotions();
    var personalized = [];
    
    promotions.forEach(function(promo) {
        // Check if promotion is personalized
        if (promo.isPersonalized()) {
            var targetSegments = promo.getTargetSegments();
            if (targetSegments.contains(customer.getSegment())) {
                personalized.push(promo);
            }
        }
    });
    
    return personalized;
}

function getCustomerSegment(customer) {
    // Determine customer segment based on behavior
    if (!customer) {
        return 'guest';
    }
    
    // Check purchase history
    var orderHistory = getOrderHistory(customer);
    var totalSpent = getTotalSpent(orderHistory);
    
    if (totalSpent > 1000) {
        return 'premium';
    } else if (totalSpent > 500) {
        return 'regular';
    } else if (customer.isNew()) {
        return 'new';
    }
    return 'standard';
}

function showPersonalizedOffers() {
    var customer = session.privacy.customer;
    var segment = getCustomerSegment(customer);
    var offers = getPersonalizedPromotions(customer);
    
    res.render('promotions/personalized', {
        offers: offers,
        segment: segment
    });
}

Personalized promotions target customer segments. Segments are based on behavior and purchase history. Personalized offers improve conversion rates.

OCAPI and SCAPI

API Fundamentals

OCAPI (Open Commerce API) provides RESTful access to commerce data.

Code Example:

// OCAPI basics
// API endpoints follow REST conventions

// GET /products/{id}
// GET /products?category=123
// POST /baskets
// PUT /baskets/{id}/items

// Example: Product API call
var ProductMgr = require('dw/catalog/ProductMgr');
var product = ProductMgr.getProduct('P001');

var productResponse = {
    id: product.getID(),
    name: product.getName(),
    description: product.getLongDescription(),
    price: product.getPriceModel().getPrice().getValue(),
    currency: product.getPriceModel().getPrice().getCurrencyCode(),
    images: product.getImages().asList().map(function(img) {
        return {
            url: img.getAbsURL(),
            alt: img.getAltText()
        };
    }),
    categories: product.getCategories().asList().map(function(cat) {
        return cat.getID();
    }),
    availability: {
        inStock: product.getAvailabilityModel().isInStock(),
        quantity: product.getAvailabilityModel().getInventoryRecord().getInStockQuantity()
    }
};

res.json(productResponse);

OCAPI provides RESTful endpoints for commerce data. API responses are JSON formatted. Data includes products, categories, and availability.

Shopper APIs

Shopper APIs handle customer-facing operations.

Code Example:

// Shopper APIs
// GET /shopper/baskets
// GET /shopper/baskets/{id}
// POST /shopper/baskets/{id}/items
// DELETE /shopper/baskets/{id}/items/{itemId}

function getShopperBasket() {
    var basket = BasketMgr.getCurrentBasket();
    if (!basket) {
        res.json({ items: [], total: 0 });
        return;
    }
    
    var response = {
        id: basket.getID(),
        items: basket.getProductLineItems().asList().map(function(item) {
            return {
                id: item.getID(),
                productId: item.getProductID(),
                quantity: item.getQuantityValue(),
                price: item.getPrice().getValue(),
                subtotal: item.getPrice() * item.getQuantityValue()
            };
        }),
        totals: {
            subtotal: basket.getSubtotalPrice().getValue(),
            shipping: basket.getShippingTotalPrice().getValue(),
            tax: basket.getTaxTotalPrice().getValue(),
            total: basket.getTotalGrossPrice().getValue()
        }
    };
    
    res.json(response);
}
exports.GetShopperBasket = getShopperBasket;

Shopper APIs are customer-facing. They handle baskets, checkout, and customer data. Responses include basket details and totals.

Admin APIs

Admin APIs handle administration and management.

Code Example:

// Admin APIs
// GET /admin/products
// POST /admin/products
// PUT /admin/products/{id}
// DELETE /admin/products/{id}

function adminGetProducts() {
    var ProductMgr = require('dw/catalog/ProductMgr');
    var products = ProductMgr.getAllProducts().asList();
    
    var response = products.map(function(product) {
        return {
            id: product.getID(),
            name: product.getName(),
            price: product.getPriceModel().getPrice().getValue(),
            category: product.getCategories().asList()[0]?.getID()
        };
    });
    
    res.json(response);
}
exports.AdminGetProducts = adminGetProducts;

function adminCreateProduct() {
    var form = request.httpParameterMap;
    var ProductMgr = require('dw/catalog/ProductMgr');
    
    var product = ProductMgr.createProduct(
        form.id.stringValue,
        form.name.stringValue
    );
    
    product.setLongDescription(form.description.stringValue);
    product.setPrice(form.price.doubleValue);
    
    res.json({
        success: true,
        product: {
            id: product.getID(),
            name: product.getName()
        }
    });
}
exports.AdminCreateProduct = adminCreateProduct;

Admin APIs manage products, orders, and site configuration. They require administrator access. Responses include success status and created data.

Integrations

Integrations connect SFCC with external systems.

Code Example:

// External integration example
function syncWithERP() {
    var Logger = require('dw/system/Logger');
    var ServiceMgr = require('dw/svc/ServiceMgr');
    
    // Create service request
    var service = ServiceMgr.getService('erpIntegration');
    var request = {
        action: 'syncProducts',
        timestamp: new Date().toISOString(),
        products: getProductData()
    };
    
    // Send request
    var response = service.call(request);
    if (response.getStatus() !== 200) {
        Logger.error('ERP sync failed: ' + response.getErrorMessage());
        return { success: false, error: response.getErrorMessage() };
    }
    
    Logger.info('ERP sync completed successfully');
    return { success: true };
}

function getProductData() {
    var ProductMgr = require('dw/catalog/ProductMgr');
    var products = ProductMgr.getAllProducts().asList();
    return products.map(function(product) {
        return {
            id: product.getID(),
            name: product.getName(),
            price: product.getPriceModel().getPrice().getValue(),
            stock: product.getAvailabilityModel().getInventoryRecord().getInStockQuantity()
        };
    });
}

Integrations connect SFCC with external systems. Services handle API calls. Data is transformed between formats. Error handling manages failures.

Third-Party Integrations

Payment Gateways

Payment gateways process transactions.

Code Example:

// Payment gateway integration
var PaymentMgr = require('dw/order/PaymentMgr');

function processPaymentWithGateway(order, paymentData) {
    // Get payment processor
    var processor = PaymentMgr.getPaymentProcessor('stripe');
    if (!processor) {
        return { success: false, error: 'Payment processor not found' };
    }
    
    // Create payment transaction
    var transaction = processor.createTransaction();
    transaction.setAmount(order.getTotalGrossPrice());
    transaction.setCurrencyCode(order.getCurrencyCode());
    transaction.setCardNumber(paymentData.cardNumber);
    transaction.setExpirationMonth(paymentData.expirationMonth);
    transaction.setExpirationYear(paymentData.expirationYear);
    transaction.setCvv(paymentData.cvv);
    
    // Process payment
    var result = processor.processPayment(transaction);
    if (!result.isSuccessful()) {
        return {
            success: false,
            error: result.getErrorMessage()
        };
    }
    
    // Add payment to order
    order.addPayment(transaction);
    
    return {
        success: true,
        transactionId: transaction.getTransactionID(),
        authorizationCode: transaction.getAuthorizationCode()
    };
}

Payment gateways process credit card transactions. They handle authorization and settlement. Errors are returned for failed transactions.

ERP Systems

ERP systems manage inventory and operations.

Code Example:

// ERP integration
function syncInventory() {
    var ServiceMgr = require('dw/svc/ServiceMgr');
    var Logger = require('dw/system/Logger');
    
    // Get service
    var service = ServiceMgr.getService('erpInventory');
    
    // Get current inventory
    var ProductMgr = require('dw/catalog/ProductMgr');
    var products = ProductMgr.getAllProducts().asList();
    var inventoryData = products.map(function(product) {
        return {
            productId: product.getID(),
            quantity: product.getAvailabilityModel().getInventoryRecord().getInStockQuantity()
        };
    });
    
    // Send to ERP
    var request = {
        action: 'updateInventory',
        data: inventoryData
    };
    
    var response = service.call(request);
    if (response.getStatus() !== 200) {
        Logger.error('ERP inventory sync failed');
        return false;
    }
    
    Logger.info('ERP inventory sync completed');
    return true;
}

ERP systems manage inventory, orders, and fulfillment. Synchronization keeps data consistent. Services handle API communication.

CRM Systems

CRM systems manage customer relationships.

Code Example:

// CRM integration
function syncCustomerData(customer) {
    var ServiceMgr = require('dw/svc/ServiceMgr');
    var Logger = require('dw/system/Logger');
    
    var service = ServiceMgr.getService('crmIntegration');
    
    var customerData = {
        id: customer.getID(),
        email: customer.getProfile().getEmail(),
        firstName: customer.getProfile().getFirstName(),
        lastName: customer.getProfile().getLastName(),
        phone: customer.getProfile().getPhone(),
        orderCount: getOrderCount(customer),
        totalSpent: getTotalSpent(customer),
        lastOrder: getLastOrderDate(customer)
    };
    
    var response = service.call(customerData);
    if (response.getStatus() !== 200) {
        Logger.error('CRM sync failed: ' + response.getErrorMessage());
        return false;
    }
    
    Logger.info('CRM sync completed for customer ' + customer.getID());
    return true;
}

CRM systems store customer data and interactions. Synchronization updates customer profiles. Data includes purchase history and preferences.

Marketing Platforms

Marketing platforms handle campaigns and analytics.

Code Example:

// Marketing platform integration
function sendAnalyticsEvent(eventType, eventData) {
    var ServiceMgr = require('dw/svc/ServiceMgr');
    
    var service = ServiceMgr.getService('analytics');
    var payload = {
        event: eventType,
        timestamp: new Date().toISOString(),
        data: eventData,
        customerId: session.privacy.customer?.getID(),
        sessionId: request.session.getID()
    };
    
    service.call(payload);
    
    return { success: true };
}

// Track product view
function trackProductView(productId) {
    var product = ProductMgr.getProduct(productId);
    sendAnalyticsEvent('productView', {
        productId: productId,
        productName: product.getName(),
        price: product.getPriceModel().getPrice().getValue()
    });
}

// Track add to cart
function trackAddToCart(productId, quantity) {
    sendAnalyticsEvent('addToCart', {
        productId: productId,
        quantity: quantity
    });
}

Marketing platforms track user behavior. Events include page views, product views, and transactions. Data is used for analytics and personalization.

Testing and Quality Assurance

Unit Testing

Unit tests verify individual components.

Code Example:

// Unit test example
// File: test/unit/productHelper.test.js
var ProductMgr = require('dw/catalog/ProductMgr');
var productHelper = require('*/cartridge/scripts/helpers/productHelper');

describe('Product Helper Tests', function() {
    it('should format product price', function() {
        var product = ProductMgr.getProduct('P001');
        var formattedPrice = productHelper.formatPrice(product);
        expect(formattedPrice).toBe('$89.99');
    });
    
    it('should check product availability', function() {
        var product = ProductMgr.getProduct('P001');
        var availability = productHelper.checkAvailability(product);
        expect(availability.inStock).toBe(true);
    });
});

Unit tests verify individual functions. They use assertions to check expected results. Tests run in isolation from other components.

Integration Testing

Integration tests verify component interactions.

Code Example:

// Integration test example
// File: test/integration/productController.test.js
var productController = require('*/cartridge/controllers/Product');

describe('Product Controller Integration Tests', function() {
    it('should show product detail', function() {
        var request = {
            httpParameterMap: {
                pid: {
                    stringValue: 'P001'
                }
            }
        };
        
        var response = {
            render: function(template, data) {
                expect(template).toBe('product/detail');
                expect(data.product.getID()).toBe('P001');
            }
        };
        
        productController.Show(request, response);
    });
});

Integration tests verify that components work together. They test the full request/response cycle. Mocks may be used for external dependencies.

Performance Testing

Performance tests measure response times.

Code Example:

// Performance test example
function testPagePerformance() {
    var startTime = new Date().getTime();
    
    // Execute page logic
    var ProductMgr = require('dw/catalog/ProductMgr');
    var products = ProductMgr.getProducts(0, 100);
    
    var endTime = new Date().getTime();
    var duration = endTime - startTime;
    
    if (duration > 500) {
        Logger.warn('Product page took ' + duration + 'ms');
        // Consider optimization
    }
    
    return duration;
}

// Measure API performance
function measureAPIPerformance() {
    var times = [];
    for (var i = 0; i < 10; i++) {
        var start = new Date().getTime();
        var product = ProductMgr.getProduct('P001');
        var end = new Date().getTime();
        times.push(end - start);
    }
    
    var average = times.reduce(function(a, b) {
        return a + b;
    }) / times.length;
    
    return {
        average: average,
        min: Math.min.apply(null, times),
        max: Math.max.apply(null, times)
    };
}

Performance tests measure response times. They identify slow operations. Results guide optimization efforts.

Automation

Automated testing reduces manual effort.

Code Example:

// Automated test suite
// File: test/suites/all.test.js
var productTests = require('./product.test');
var cartTests = require('./cart.test');
var checkoutTests = require('./checkout.test');

function runAllTests() {
    var results = {
        total: 0,
        passed: 0,
        failed: 0
    };
    
    // Run all test suites
    var testSuites = [productTests, cartTests, checkoutTests];
    testSuites.forEach(function(suite) {
        var result = suite.run();
        results.total += result.total;
        results.passed += result.passed;
        results.failed += result.failed;
    });
    
    return results;
}

function runContinuousTests() {
    // Run tests on file change
    var watch = require('watch');
    watch.createMonitor('./cartridges', function(monitor) {
        monitor.on('changed', function(file) {
            console.log('File changed: ' + file);
            var results = runAllTests();
            console.log('Tests: ' + results.passed + '/' + results.total + ' passed');
        });
    });
}

Automated tests run without manual intervention. They can be triggered by file changes or scheduled. Results are reported automatically.

Performance Optimization

Caching

Caching improves response times.

Code Example:

// Caching implementation
var CacheMgr = require('dw/system/CacheMgr');

function getProductWithCache(productId) {
    var cacheKey = 'product_' + productId;
    var cached = CacheMgr.get(cacheKey);
    
    if (cached) {
        return cached;
    }
    
    var product = ProductMgr.getProduct(productId);
    var productData = {
        id: product.getID(),
        name: product.getName(),
        price: product.getPriceModel().getPrice().getValue()
    };
    
    // Cache for 1 hour
    CacheMgr.put(cacheKey, productData, 3600);
    return productData;
}

function clearProductCache(productId) {
    var cacheKey = 'product_' + productId;
    CacheMgr.remove(cacheKey);
}

Caching stores frequently accessed data. Cache hits reduce database load. Cache expiration ensures data freshness.

CDN Optimization

CDN optimization improves static asset delivery.

Code Example:

// CDN configuration
var URLUtils = require('dw/web/URLUtils');

function getStaticAssetURL(path) {
    // Use CDN for static assets
    var cdnDomain = site.getCustomPreferenceValue('cdnDomain');
    if (cdnDomain) {
        return 'https://' + cdnDomain + '/static/' + path;
    }
    return URLUtils.staticURL(path);
}

function getImageURL(product) {
    var image = product.getImages()[0];
    var url = image.getAbsURL();
    
    // Add CDN parameters for optimization
    var cdnParams = '?width=400&height=400&fit=cover';
    return url + cdnParams;
}

CDNs deliver static assets from edge locations. This reduces latency and server load. CDN parameters optimize image delivery.

Page Performance

Page performance affects user experience.

Code Example:

// Page performance optimization
function optimizePageRendering() {
    // Minimize database queries
    var ProductMgr = require('dw/catalog/ProductMgr');
    var products = ProductMgr.getProducts(0, 12); // Limit results
    
    // Lazy load images
    var imageData = products.map(function(product) {
        return {
            id: product.getID(),
            name: product.getName(),
            image: product.getImages()[0]?.getAbsURL(),
            placeholder: getPlaceholderImage()
        };
    });
    
    // Render with lazy loading
    res.render('product/list', {
        products: imageData,
        enableLazyLoading: true
    });
}

function getPlaceholderImage() {
    return 'data:image/svg+xml;base64,...';
}

Page performance optimization includes limiting data, lazy loading, and efficient rendering. These techniques improve perceived and actual performance.

Search Performance

Search performance affects product discovery.

Code Example:

// Search performance optimization
function optimizedSearch(query) {
    var ProductSearchModel = require('dw/catalog/ProductSearchModel');
    var search = new ProductSearchModel();
    
    // Use indexed fields for sorting
    search.setSearchPhrase(query);
    search.setSortingOption('relevance'); // Indexed
    
    // Limit results
    search.setRecordCount(20);
    
    // Use caching for frequent searches
    var cacheKey = 'search_' + query + '_' + search.getSortingOption();
    var cached = CacheMgr.get(cacheKey);
    if (cached) {
        return cached;
    }
    
    search.search();
    var results = search.getProductSearchHits().asList();
    
    // Cache for 10 minutes
    CacheMgr.put(cacheKey, results, 600);
    return results;
}

Search performance uses indexes, caching, and result limits. Frequent searches are cached. Indexed fields improve sorting speed.

AI-Powered Commerce

Salesforce Einstein

Salesforce Einstein provides AI capabilities.

Code Example:

// Einstein integration
function getEinsteinRecommendations(productId) {
    var EinsteinMgr = require('sfai/experience');
    var product = ProductMgr.getProduct(productId);
    
    var recommendations = EinsteinMgr.getRecommendations({
        productId: productId,
        customerId: session.privacy.customer?.getID(),
        count: 4
    });
    
    return recommendations.map(function(rec) {
        return ProductMgr.getProduct(rec.productId);
    });
}

function getPersonalizedProducts() {
    var customer = session.privacy.customer;
    if (!customer) {
        return getDefaultProducts();
    }
    
    var EinsteinMgr = require('sfai/experience');
    var personalized = EinsteinMgr.getPersonalizedProducts({
        customerId: customer.getID(),
        count: 10,
        categories: ['electronics', 'clothing']
    });
    
    return personalized.map(function(item) {
        return {
            product: ProductMgr.getProduct(item.productId),
            score: item.score,
            reason: item.reason
        };
    });
}

Einstein provides AI-powered recommendations. It analyzes customer behavior and product data. Recommendations are personalized to each customer.

AI Recommendations

AI recommendations suggest products.

Code Example:

// AI recommendation system
function getAIRecommendations(productId, customerId) {
    var recommendationService = require('*/cartridge/scripts/services/recommendationService');
    
    var request = {
        productId: productId,
        customerId: customerId,
        context: {
            sessionId: request.session.getID(),
            timestamp: new Date().toISOString()
        }
    };
    
    var response = recommendationService.call(request);
    if (response.getStatus() !== 200) {
        Logger.error('Recommendation service failed');
        return getFallbackRecommendations(productId);
    }
    
    var recommendations = response.getBody();
    return recommendations.map(function(rec) {
        return {
            product: ProductMgr.getProduct(rec.productId),
            score: rec.score,
            type: rec.type // 'similar', 'boughtTogether', 'trending'
        };
    });
}

function getFallbackRecommendations(productId) {
    var product = ProductMgr.getProduct(productId);
    var category = product.getCategories().asList()[0];
    if (!category) {
        return [];
    }
    
    var products = category.getProducts().asList();
    return products.filter(function(p) {
        return p.getID() !== productId;
    }).slice(0, 4);
}

AI recommendations use machine learning algorithms. They analyze customer behavior and product affinity. Fallbacks handle service failures.

Personalized Commerce

Personalized commerce tailors the experience to each customer.

Code Example:

// Personalized commerce
function getPersonalizedExperience() {
    var customer = session.privacy.customer;
    var segment = getCustomerSegment(customer);
    
    var experience = {
        greeting: getPersonalizedGreeting(customer),
        featuredProducts: getPersonalizedProducts(customer),
        promotions: getPersonalizedPromotions(customer),
        content: getPersonalizedContent(customer)
    };
    
    return experience;
}

function getPersonalizedGreeting(customer) {
    if (!customer) {
        return 'Welcome, Guest!';
    }
    
    var firstName = customer.getProfile().getFirstName();
    if (firstName) {
        return 'Welcome back, ' + firstName + '!';
    }
    return 'Welcome back!';
}

function getPersonalizedContent(customer) {
    if (!customer) {
        return getDefaultContent();
    }
    
    var interests = getCustomerInterests(customer);
    var content = getContentByInterests(interests);
    return content.slice(0, 3);
}

Personalized commerce tailors content to each customer. It uses customer data and behavior. Personalization improves engagement and conversion.

Conversational Commerce

Conversational commerce uses chat and AI for shopping.

Code Example:

// Conversational commerce
function handleChatMessage(message, customer) {
    var ChatGPT = require('chatgpt');
    var response = ChatGPT.sendMessage(message);
    
    // Parse intent
    var intent = detectIntent(message);
    var entities = extractEntities(message);
    
    switch (intent) {
        case 'product_search':
            return handleProductSearch(entities, customer);
        case 'add_to_cart':
            return handleAddToCart(entities, customer);
        case 'checkout':
            return handleCheckout(customer);
        default:
            return response;
    }
}

function handleProductSearch(entities, customer) {
    var ProductSearchModel = require('dw/catalog/ProductSearchModel');
    var search = new ProductSearchModel();
    search.setSearchPhrase(entities.query);
    search.search();
    
    var results = search.getProductSearchHits().asList();
    var productInfo = results.slice(0, 3).map(function(product) {
        return {
            name: product.getName(),
            price: product.getPriceModel().getPrice().getValue(),
            link: URLUtils.url('Product-Show', 'pid', product.getID())
        };
    });
    
    return {
        message: 'I found these products:',
        products: productInfo
    };
}

Conversational commerce uses chat interfaces. AI handles natural language processing. Intents are detected and actions are executed.

Production Architecture

Logging

Logging captures runtime information.

Code Example:

// Logging implementation
var Logger = require('dw/system/Logger');

function logRequest(req) {
    var logData = {
        method: req.requestMethod,
        url: req.requestURI,
        ip: req.getRemoteAddress(),
        timestamp: new Date().toISOString(),
        userAgent: req.getUserAgent()
    };
    
    Logger.info('Request: ' + JSON.stringify(logData));
}

function logError(error, context) {
    var logData = {
        error: error.message,
        stack: error.stack,
        context: context,
        timestamp: new Date().toISOString()
    };
    
    Logger.error('Error: ' + JSON.stringify(logData));
}

function logBusinessEvent(event, data) {
    var logData = {
        event: event,
        data: data,
        timestamp: new Date().toISOString()
    };
    
    Logger.info('BusinessEvent: ' + JSON.stringify(logData));
}

Logging records runtime events. Different log levels (info, error, debug) provide filtering. Structured logs are easier to analyze.

Monitoring

Monitoring tracks system health and performance.

Code Example:

// Monitoring implementation
function getSystemHealth() {
    var health = {
        status: 'healthy',
        checks: {
            database: checkDatabaseConnection(),
            cache: checkCacheConnection(),
            search: checkSearchIndex()
        },
        metrics: getSystemMetrics()
    };
    
    return health;
}

function checkDatabaseConnection() {
    try {
        var ProductMgr = require('dw/catalog/ProductMgr');
        var product = ProductMgr.getProduct('P001');
        return { status: 'healthy', latency: getResponseTime() };
    } catch (error) {
        return { status: 'unhealthy', error: error.message };
    }
}

function getSystemMetrics() {
    var metrics = {
        responseTime: getAverageResponseTime(),
        requestCount: getRequestCount(),
        errorRate: getErrorRate(),
        cacheHitRate: getCacheHitRate(),
        memoryUsage: getMemoryUsage()
    };
    
    return metrics;
}

Monitoring tracks system health and performance. Health checks verify dependencies. Metrics provide system insights.

Security

Security protects the platform and customer data.

Code Example:

// Security implementation
function validateSession() {
    var session = request.getSession();
    if (!session.isValid()) {
        redirectToLogin();
        return false;
    }
    
    // Check CSRF token
    var csrfToken = request.httpParameterMap.csrfToken.stringValue;
    if (csrfToken !== session.getCSRFToken()) {
        Logger.warn('CSRF validation failed');
        return false;
    }
    
    return true;
}

function sanitizeInput(input) {
    // Remove dangerous characters
    return input
        .replace(/<script/g, '<script')
        .replace(/<\/script>/g, '</script>')
        .replace(/javascript:/gi, '')
        .trim();
}

function encryptSensitiveData(data) {
    var Crypto = require('dw/crypto/Crypto');
    var cipher = Crypto.getCipher('AES-256-CBC');
    var encrypted = cipher.encrypt(data);
    return encrypted;
}

Security includes session validation, input sanitization, and data encryption. CSRF protection prevents cross-site request forgery. Sensitive data is encrypted.

Scalability

Scalability handles traffic growth.

Code Example:

// Scalability implementation
function getProductsForStorefront(page) {
    // Use pagination to limit results
    var pageSize = 12;
    var start = (page - 1) * pageSize;
    
    var ProductMgr = require('dw/catalog/ProductMgr');
    var products = ProductMgr.getProducts(start, pageSize);
    
    // Use caching for frequent queries
    var cacheKey = 'products_' + page + '_' + pageSize;
    var cached = CacheMgr.get(cacheKey);
    if (cached) {
        return cached;
    }
    
    CacheMgr.put(cacheKey, products, 300);
    return products;
}

function handleHighTraffic(request) {
    // Rate limiting
    var rateLimit = getRateLimit(request);
    if (rateLimit.exceeded) {
        return { error: 'Too many requests' };
    }
    
    // Queue processing for heavy operations
    if (request.isHeavy) {
        queueProcessing(request);
        return { status: 'processing' };
    }
    
    return processRequest(request);
}

Scalability includes pagination, caching, and rate limiting. Heavy operations are queued. Traffic is distributed across instances.

High Availability

High availability ensures continuous service.

Code Example:

// High availability implementation
function ensureHighAvailability() {
    // Service health checks
    var services = ['database', 'cache', 'search'];
    services.forEach(function(service) {
        if (!isServiceHealthy(service)) {
            failoverService(service);
        }
    });
    
    // Data backup
    if (shouldBackup()) {
        performBackup();
    }
    
    // Load balancing
    var instance = getCurrentInstance();
    if (instance.load > 0.8) {
        routeToOtherInstance(request);
    }
}

function failoverService(service) {
    Logger.warn('Failover initiated for ' + service);
    var backupService = getBackupService(service);
    if (backupService) {
        switchToService(backupService);
        Logger.info('Switched to backup ' + service);
    }
}

function getBackupService(service) {
    var services = {
        'database': 'database-backup',
        'cache': 'cache-backup',
        'search': 'search-backup'
    };
    return services[service] || null;
}

High availability includes failover, backup, and load balancing. Services are monitored for health. Backups are performed regularly.

Real-World Projects

Fashion Store

A fashion store with apparel and accessories.

Code Example:

// Fashion store implementation
// Features: Product categories, sizes, colors, product sets

function showFashionProduct() {
    var productId = request.httpParameterMap.pid.stringValue;
    var product = ProductMgr.getProduct(productId);
    
    var viewData = {
        product: product,
        images: product.getImages().asList(),
        sizes: product.getVariationModel().getVariationValues('size'),
        colors: product.getVariationModel().getVariationValues('color'),
        selectedSize: request.httpParameterMap.size.stringValue,
        selectedColor: request.httpParameterMap.color.stringValue
    };
    
    res.render('fashion/product/detail', viewData);
}
exports.ShowFashionProduct = showFashionProduct;

Fashion stores have products with sizes and colors. Variations handle different options. Product sets and bundles are common.

Luxury Brand Platform

A luxury brand platform with premium experience.

Code Example:

// Luxury brand implementation
// Features: High-end UI, personalized experience, premium services

function showLuxuryProduct() {
    var productId = request.httpParameterMap.pid.stringValue;
    var product = ProductMgr.getProduct(productId);
    
    var viewData = {
        product: product,
        images: product.getImages().asList(),
        isPremium: isPremiumCustomer(),
        relatedProducts: getRelatedProducts(productId),
        conciergeEnabled: isConciergeEnabled()
    };
    
    res.render('luxury/product/detail', viewData);
}
exports.ShowLuxuryProduct = showLuxuryProduct;

function isPremiumCustomer() {
    var customer = session.privacy.customer;
    if (!customer) {
        return false;
    }
    return CustomerMgr.isMemberOfGroup(customer, 'premium');
}

Luxury brands have premium experiences. They target high-value customers. Personalization and concierge services are common.

Electronics Store

An electronics store with complex product configurations.

Code Example:

// Electronics store implementation
// Features: Product comparisons, technical specs, compatibility

function showElectronicsProduct() {
    var productId = request.httpParameterMap.pid.stringValue;
    var product = ProductMgr.getProduct(productId);
    
    var viewData = {
        product: product,
        specs: product.getCustomPreferenceValue('technicalSpecs'),
        compatibility: getCompatibility(productId),
        reviews: getProductReviews(productId),
        compareProducts: getCompareProducts(productId)
    };
    
    res.render('electronics/product/detail', viewData);
}
exports.ShowElectronicsProduct = showElectronicsProduct;

function getCompatibility(productId) {
    var compatibility = {
        compatibleProducts: getCompatibleProducts(productId),
        requiredProducts: getRequiredProducts(productId)
    };
    return compatibility;
}

Electronics stores have complex products. Technical specs and compatibility are important. Comparison features help customers choose.

Subscription Commerce Platform

A subscription platform for recurring payments.

Code Example:

// Subscription commerce implementation
// Features: Recurring payments, subscription management, billing

function showSubscriptionProduct() {
    var productId = request.httpParameterMap.pid.stringValue;
    var product = ProductMgr.getProduct(productId);
    
    var viewData = {
        product: product,
        subscriptionPlans: getSubscriptionPlans(productId),
        recurringPrice: getRecurringPrice(productId),
        billingFrequency: getBillingFrequency(productId)
    };
    
    res.render('subscription/product/detail', viewData);
}
exports.ShowSubscriptionProduct = showSubscriptionProduct;

function createSubscription() {
    var form = request.httpParameterMap;
    var productId = form.productId.stringValue;
    var planId = form.planId.stringValue;
    
    var subscription = {
        productId: productId,
        planId: planId,
        customerId: session.privacy.customer.getID(),
        startDate: new Date(),
        status: 'active'
    };
    
    // Initialize recurring billing
    var billing = initializeBilling(subscription);
    
    res.json({
        success: true,
        subscription: subscription,
        billing: billing
    });
}
exports.CreateSubscription = createSubscription;

Subscription commerce has recurring payments. Plans and billing frequencies are configurable. Subscription management includes upgrades and cancellations.

AI-Powered Retail Platform

An AI-powered platform with personalization.

Code Example:

// AI-powered retail implementation
// Features: AI recommendations, personalization, predictive analytics

function showAIStorefront() {
    var customer = session.privacy.customer;
    var recommendations = getAIRecommendations(customer);
    var personalizedOffers = getPersonalizedOffers(customer);
    
    res.render('ai/storefront', {
        products: recommendations,
        offers: personalizedOffers,
        featuredProducts: getFeaturedProducts(customer)
    });
}
exports.ShowAIStorefront = showAIStorefront;

function getAIRecommendations(customer) {
    var EinsteinMgr = require('sfai/experience');
    var recommendations = EinsteinMgr.getRecommendations({
        customerId: customer?.getID(),
        count: 12,
        categories: getCustomerInterests(customer)
    });
    
    return recommendations.map(function(rec) {
        return {
            product: ProductMgr.getProduct(rec.productId),
            score: rec.score,
            reason: rec.reason,
            confidence: rec.confidence
        };
    });
}

AI-powered retail uses machine learning. Recommendations are personalized. Predictive analytics optimize inventory and pricing.

Career Readiness

Portfolio Building

Build a portfolio showcasing SFCC development skills.

Code Example:

// Portfolio project examples
// 1. Custom storefront extension
// Features: Custom checkout flow, personalized recommendations

// 2. Integration with external systems
// Features: ERP integration, payment gateway

// 3. Performance optimization
// Features: Caching strategies, CDN optimization

// 4. AI-powered features
// Features: Einstein integration, personalization

// Portfolio documentation
/*
## SFCC Portfolio Projects

### 1. Custom Checkout Extension
- Technology: SFRA, JavaScript, ISML
- Description: Extended checkout with one-click ordering
- Results: 25% increase in conversion rate

### 2. ERP Integration
- Technology: SFCC, REST APIs, OAuth
- Description: Real-time inventory sync with SAP
- Results: 99.9% inventory accuracy

### 3. Performance Optimization
- Technology: SFCC, CDN, Redis
- Description: Reduced page load time by 40%
- Results: Improved SEO and user experience

### 4. AI Recommendations
- Technology: Einstein, Node.js, React
- Description: Personalized product recommendations
- Results: 15% increase in average order value
*/

Portfolio projects demonstrate practical skills. Documentation explains the problem, solution, and results. Projects should show breadth and depth.

SFCC Interviews

Prepare for SFCC technical interviews.

Code Example:

// Common SFCC interview questions

// Q1: How does cartridge path work?
/*
A: Cartridge path determines load order. Paths are evaluated left to right.
The first cartridge containing a file is used. Custom cartridges should be
placed before core cartridges.
*/

// Q2: What is the difference between a controller and a script?
/*
A: Controllers handle HTTP requests and responses. They are the entry point
for web requests. Scripts contain reusable business logic that can be called
from controllers or other scripts.
*/

// Q3: How do you handle caching in SFCC?
/*
A: SFCC provides multiple caching strategies: page caching, object caching,
and content caching. Use CacheMgr for application-level caching.
*/

// Q4: Explain the request lifecycle.
/*
A: Browser request -> Route resolution -> Pre-middleware -> Controller ->
Post-middleware -> ISML rendering -> Response
*/

// Q5: How do you optimize search performance?
/*
A: Use indexed fields for sorting, limit result counts, use caching for
frequent searches, and use search refinements for filtering.
*/

Interview questions cover architecture, development, and best practices. Be prepared to explain concepts and code examples. Show understanding of the platform.

Certification Preparation

Prepare for SFCC certification.

Code Example:

// Certification topics

// 1. Platform architecture
// - SFCC architecture overview
// - Component interactions
// - Data models

// 2. SFRA development
// - Cartridge structure
// - Controller development
// - ISML templates

// 3. API development
// - OCAPI
// - SCAPI
// - Integration patterns

// 4. Performance optimization
// - Caching strategies
// - CDN optimization
// - Database tuning

// 5. Security
// - Authentication
// - Authorization
// - Data protection

// Study resources
var studyResources = {
    documentation: 'https://documentation.salesforce.com/commerce',
    trails: 'https://trailhead.salesforce.com',
    practiceExams: 'https://www.salesforce.com/trailblazer',
    community: 'https://trailblazer.salesforce.com'
};

Certification validates SFCC knowledge. Topics cover architecture, development, and best practices. Study resources include official documentation and Trailhead.

Enterprise Commerce Practices

Enterprise commerce practices for large-scale deployments.

Code Example:

// Enterprise commerce best practices

// 1. Code organization
// - Modular cartridges
// - Clear naming conventions
// - Version control

// 2. Development workflow
// - Feature branches
// - Code reviews
// - CI/CD pipelines

// 3. Testing strategy
// - Unit tests
// - Integration tests
// - Performance tests
// - User acceptance tests

// 4. Deployment strategy
// - Staging environment
// - Blue-green deployment
// - Rollback procedures

// 5. Monitoring and logging
// - Application logs
// - Performance metrics
// - Error tracking

// 6. Security practices
// - Secure coding
// - Vulnerability scanning
// - Access control

// 7. Performance optimization
// - Caching
// - CDN
// - Database optimization
// - Code optimization

// Example: CI/CD pipeline
/*
name: Deploy to Production
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Deploy to Staging
        run: sfcc-ci code:upload --sandbox staging --code-version staging
      - name: Run Tests
        run: npm test
      - name: Deploy to Production
        run: sfcc-ci code:upload --sandbox production --code-version production
*/

Enterprise commerce practices ensure quality and reliability. They cover development, testing, deployment, and monitoring. Large-scale deployments require robust processes.

Conclusion and Final Skill Stack

After completing this roadmap, you will be able to:

Foundation Skills:

  • Understand SFCC architecture and components
  • Navigate Business Manager
  • Work with sandboxes and instances
  • Configure cartridge paths
  • Deploy code to sandboxes

Development Skills:

  • Create custom cartridges
  • Develop controllers and routes
  • Write ISML templates
  • Implement middleware
  • Work with models and scripts
  • Use OCAPI and SCAPI

Commerce Skills:

  • Manage products and catalog
  • Handle variants and bundles
  • Implement search and merchandising
  • Manage cart and checkout
  • Apply promotions and campaigns
  • Manage customers and profiles

Advanced Skills:

  • Implement AI recommendations
  • Optimize performance
  • Ensure security and scalability
  • Integrate with third-party systems
  • Use Salesforce Einstein
  • Build real-world projects

Career Skills:

  • Build a portfolio
  • Prepare for interviews
  • Get certified
  • Practice enterprise commerce

Final Advice

To a beginner starting with Salesforce Commerce Cloud: Imagine you are building a city of commerce. SFRA is your architectural blueprint – it tells you where to put the buildings (controllers), how to connect them (cartridges), and how to make them beautiful (ISML). Business Manager is your control center. And Salesforce Einstein is your AI assistant, helping you personalize experiences for millions of visitors.

Your journey:

  1. Learn the platform fundamentals
  2. Understand SFRA architecture
  3. Build a Hello World cartridge
  4. Develop storefront features
  5. Manage products and catalog
  6. Implement search and checkout
  7. Add personalization
  8. Optimize performance
  9. Deploy to production
  10. Build real-world projects

Remember: Major brands like Adidas, Sephora, and Timberland use Salesforce Commerce Cloud. The skills you learn here power billions of dollars in e-commerce revenue. Your code could be the one that makes a customer’s shopping experience memorable.

Scroll to Top