Salesforce
Salesforce is a cloud-based software company best known for its customer relationship management (CRM) platform. It helps businesses manage sales, customer service, marketing, and more from a single, unified system

Introduction To Salesforce
- Complete Salesforce Commerce Cloud (SFRA) Learning Roadmap
- Introduction to Salesforce Commerce Cloud and SFRA
- SFCC Architecture and Internal Working
- Environment Setup and First Application
- Your First Program – Hello World in SFRA (Complete Step-by-Step)
- AI Integration with AI Tools
- Commerce Cloud Fundamentals
- JavaScript Foundations
- SFRA Architecture
- ISML Development
- Controllers and Routing
- Catalog Management
- Customer Management
- Search and Merchandising
- Cart and Checkout
- Promotions and Campaigns
- OCAPI and SCAPI
- Third-Party Integrations
- Testing and Quality Assurance
- Performance Optimization
- AI-Powered Commerce
- Production Architecture
- Real-World Projects
- Career Readiness
- Conclusion and Final Skill Stack
- 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
| Type | Description | Examples |
|---|---|---|
| B2C Commerce | Business-to-consumer online stores | Retail websites |
| B2B Commerce | Business-to-business commerce | Wholesale portals |
| Order Management | Cross-channel order processing | Inventory management |
| Headless Commerce | API-first commerce | Mobile 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
| Benefit | Explanation |
|---|---|
| Scalability | Handles Black Friday-level traffic |
| Multi-site | Manage multiple brands from one instance |
| Multi-currency | Support global commerce |
| Integration ready | CRM, Marketing Cloud, ERP connectors |
| Cloud-native | No server management |
| Security | PCI 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:
| Industry | Use Case |
|---|---|
| Retail | Global e-commerce stores |
| Fashion | Multi-brand fashion retailers |
| Electronics | Consumer electronics stores |
| Luxury goods | High-end brand stores |
| B2B | Wholesale 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
| Prerequisite | Level Needed |
|---|---|
| JavaScript | Functions, objects, promises |
| HTML/CSS | Basic web development |
| REST APIs | Understanding HTTP methods |
| Git basics | Version 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:
| Section | Purpose |
|---|---|
| Catalogs | Manage product catalogs and categories |
| Products | Add/edit products, variants, bundles |
| Pricing | Set price books and price adjustments |
| Promotions | Create discounts and campaigns |
| Orders | View and manage customer orders |
| Sites | Configure multi-site settings |
| Merchant Tools | Import/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:
| Concept | Description |
|---|---|
| Controllers | Handle HTTP requests (like Express routes) |
| Models | Business logic and data processing |
| ISML Templates | HTML rendering (similar to JSX) |
| Cartridges | Modular code packages |
| Hooks | Extend 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
- Browser sends a request to
/Product-Show?pid=001 - SFRA routes to
Product.jscontroller,show()function - Controller uses
ProductMgrto fetch product data - Data is processed and prepared for the template
- ISML template renders HTML with the product data
- 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):
- Custom cartridge (your code)
- Plugin cartridges (extensions)
- app_storefront_base (core SFRA)
- 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:
- Log into Business Manager
- Go to Administration → Sites → Manage Sites
- Select your site
- Go to Settings → Developer Settings
- 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_cartridgehas acontrollers/Home.js, it overrides the one inapp_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:
- Request sandbox access from Salesforce
- Receive credentials for Business Manager
- Business Manager URL:
https://your-sandbox.demandware.net - 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:
| Component | Requirement |
|---|---|
| OS | Windows 10/11, macOS 11+, Ubuntu 22.04+ |
| RAM | Minimum 16 GB (strongly recommended) |
| Storage | At least 30 GB free space |
| Internet | Required for downloads |
| Node.js | v16.x or higher |
| Git | Latest version |
| SFCC Sandbox | Required (provided by Salesforce) |
| Browser | Chrome, Firefox, or Edge |
| Text Editor | VS 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:
- Log into your Business Manager
- URL:
https://your-sandbox.demandware.net/on/demandware.store/Sites-Site/default/ViewApplication-Start - Go to Administration → Sites → Manage Sites to access the site management settings.
- Click on your site name (e.g., “RefArch”)
- Go to Settings → Developer Settings tab
- Find “Cartridge Path” field
- Update the cartridge path to:
my_custom_cartridge:app_storefront_base - Click “Apply” and then “Save”
What this does:
my_custom_cartridgeis loaded first (highest priority)app_storefront_baseis 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;
| Code | What 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 = show | Exports function to router (maps to /Hello-Show) |
URL pattern explained:
| Component | Example | Source |
|---|---|---|
| Controller name | Hello | File name (Hello.js) |
| Action name | Show | Exported function name (Show) |
| Full URL | /Hello-Show | Combined |
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>
| Code | What 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:
| Command | Purpose |
|---|---|
code:upload | Uploads your cartridges to the sandbox |
code-version | A version label for your code (use any name) |
sandbox:start | Starts the sandbox runtime |
sandbox:status | Checks 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:
| Code | What 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 = show | Exports function to router (maps to /Hello-Show) |
URL pattern explained:
| Component | Example | Source |
|---|---|---|
| Controller name | Hello | File name (Hello.js) |
| Action name | Show | Exported function name (Show) |
| Full URL | /Hello-Show | Combined |
ISML Template (hello.isml) – Detailed explanation:
| Code | What 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
| Problem | Likely Cause | Solution |
|---|---|---|
| 404 Not Found | Cartridge path not configured | Check cartridge path in Business Manager |
| Template not found | ISML file in wrong folder | Ensure file is in templates/default/ |
| Controller not found | Controller not exported | Check exports.Show = show line |
| Changes not visible | Code not deployed | Run sfcc-ci code:upload again |
| Sandbox not running | Sandbox stopped | Run 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:
| Section | Purpose |
|---|---|
| Catalogs | Product and category management |
| Products | Add/edit products, variants, bundles |
| Pricing | Price books and adjustments |
| Promotions | Discounts, coupons, campaigns |
| Orders | View and manage customer orders |
| Sites | Multi-site configuration |
| Merchant Tools | Import/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:
| Type | Purpose |
|---|---|
| Development Sandbox | Code development and testing |
| Staging Sandbox | Pre-production testing |
| Production Sandbox | Live 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:
| URL | Controller | Action |
|---|---|---|
/Product-Show | Product.js | Show |
/Product-AddToCart | Product.js | AddToCart |
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>
| Tag | Purpose |
|---|---|
<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:
- Browser request
- Route resolution (file + function)
- Pre‑middleware
- Controller execution
- Post‑middleware
- ISML rendering
- 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:
| URL | Controller | Action |
|---|---|---|
/Home-Show | Home.js | Show |
/Product-Show?pid=123 | Product.js | Show |
/Search-Show?q=shoe | Search.js | Show |
/Cart-AddProduct | Cart.js | AddProduct |
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:
- Learn the platform fundamentals
- Understand SFRA architecture
- Build a Hello World cartridge
- Develop storefront features
- Manage products and catalog
- Implement search and checkout
- Add personalization
- Optimize performance
- Deploy to production
- 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.