SAP Commerce Cloud Architecture Overview
SAP Commerce Cloud architecture: platform services, CCv2 aspects, deployment pipelines, cluster topology, and integration patterns.
Dr. Elena Kovács
SAP Commerce Platform Architect
Core platform architecture, Spring, extension design, performance tuning, clustering, and JDK upgrades.
SAP Commerce Cloud (formerly Hybris) is a Java-based e-commerce platform built on Spring Framework, deployed on a managed cloud infrastructure (CCv2). This guide covers the core architectural patterns that every commerce architect and developer must understand: platform services, the extension system, CCv2-specific deployment model, and integration patterns.
Platform Services Architecture#
The SAP Commerce platform is built around a service-oriented architecture with three key layers:
- Type System: dynamic data model with runtime type definition
- Service Layer: business logic, transactions, validation
- Facades: simplified API for frontend/integration consumption
Type System#
SAP Commerce uses a custom type system defined in *-items.xml files. Types are compiled into JaLo classes (legacy) and Models (current standard).
<itemtype code="Product" extends="GenericItem">
<deployment table="products" typecode="1"/>
<attributes>
<attribute qualifier="code" type="java.lang.String">
<modifiers unique="true" optional="false"/>
<persistence type="property"/>
</attribute>
<attribute qualifier="name" type="localized:java.lang.String">
<persistence type="property"/>
</attribute>
<attribute qualifier="catalogVersion" type="CatalogVersion">
<modifiers optional="false"/>
<persistence type="property"/>
</attribute>
</attributes>
</itemtype>
Key type system concepts:
- Deployment: table name + typecode (numeric identifier for serialization)
- Attributes: can be stored (persisted to DB) or dynamic (calculated at runtime)
- Relations: one-to-many and many-to-many via separate relation items
- Interceptors: validate, prepare, or react to model changes (lifecycle hooks)
- Localization: attributes can be localized per language via
localized:prefix
Service Layer#
Business logic lives in service beans. Services are Spring-managed, transactional, and testable:
@Service
public class DefaultProductService implements ProductService {
@Resource
private FlexibleSearchService flexibleSearchService;
@Resource
private ModelService modelService;
@Override
public ProductModel getProductForCode(String code) {
final FlexibleSearchQuery query = new FlexibleSearchQuery(
"SELECT {pk} FROM {Product} WHERE {code} = ?code"
);
query.addQueryParameter("code", code);
return flexibleSearchService.searchUnique(query);
}
@Override
@Transactional
public void updateProduct(ProductModel product) {
modelService.save(product);
}
}
Service layer best practices:
- Use FlexibleSearch for queries (platform-managed SQL abstraction)
- Transaction boundaries via
@Transactional(Spring TX) - Validation via Interceptors and Validators
- No UI concerns. Service layer is backend-only
- Avoid direct DAO access. Use ModelService for CRUD
Facades#
Facades simplify service layer complexity for frontends and integrations. They convert Models to DTOs (Data Transfer Objects):
@Component
public class DefaultProductFacade implements ProductFacade {
@Resource
private ProductService productService;
@Resource
private Converter<ProductModel, ProductData> productConverter;
@Override
public ProductData getProductForCode(String code) {
final ProductModel product = productService.getProductForCode(code);
return productConverter.convert(product);
}
}
Facades return DTOs (Data Transfer Objects), never models directly. DTOs are serialization-safe, versioned, and decouple the API from internal models.
Extension System#
SAP Commerce is modular. All functionality ships as extensions. Core platform extensions:
| Extension | Purpose |
|---|---|
core | Platform kernel, type system, Spring context |
catalog | Catalogs, categories, classification |
basecommerce | Product, price, stock fundamentals |
commercefacades | Standard facades + DTOs |
commerceservices | Standard services (cart, order, customer) |
commercewebservices | OCC REST API (headless commerce) |
backoffice | Admin UI framework |
acceleratorservices | B2C/B2B storefront foundation |
acceleratorstorefrontcommons | Storefront web layer (controllers, tags) |
Extension Structure#
myextension/
├── extensioninfo.xml # extension metadata, dependencies
├── project.properties # build config, cache regions
├── resources/
│ ├── myextension-items.xml # type system definitions
│ ├── myextension-spring.xml # Spring bean wiring
│ ├── localization/ # i18n bundles
│ └── impex/ # initial data, migrations
├── src/ # Java source
├── testsrc/ # unit/integration tests
└── web/ # web UI (storefront/backoffice)
Extensions declare dependencies in extensioninfo.xml:
<extension name="myextension">
<requires-extension name="commerceservices"/>
<requires-extension name="commercefacades"/>
<coremodule generated="true" packageroot="com.example.myextension"/>
<webmodule webroot="/myextension"/>
</extension>
Build order is calculated from dependency graph. Circular dependencies are rejected at compile time.
CCv2 Architecture (SAP Commerce Cloud v2)#
CCv2 is the managed cloud platform for SAP Commerce. It introduces aspects, independently scalable deployment units.
Aspect Model#
An aspect is a logical deployment unit with a specific role. CCv2 supports:
| Aspect | Purpose | Scalability |
|---|---|---|
accstorefront | Customer-facing storefront (B2C/B2B) | Horizontal (auto-scale) |
backoffice | Admin UI for content/catalog management | Vertical (fixed instances) |
backgroundProcessing | Async jobs (cronjobs, indexing, batch) | Horizontal (job-based) |
api | OCC REST API (headless commerce) | Horizontal (auto-scale) |
admin | Platform admin and initialisation tasks | Vertical (fixed) |
Each aspect runs as a separate cluster of nodes with isolated configuration.
Aspect Configuration#
Aspects are configured via manifest.json in the cloud portal repository:
{
"commerceSuiteVersion": "2211.24",
"aspects": [
{
"name": "accstorefront",
"properties": [
{
"key": "spring.session.enabled",
"value": "true"
},
{
"key": "cluster.node.groups",
"value": "integration,yHotfolderCandidate"
}
],
"webapps": [
{
"name": "mystorefront",
"contextPath": ""
}
]
},
{
"name": "backgroundProcessing",
"properties": [
{
"key": "cluster.node.groups",
"value": "integration,yHotfolderCandidate,backgroundProcessing"
}
]
}
],
"extensions": ["mystorefront", "mycore"]
}
Key aspect config patterns:
- cluster.node.groups: controls which cronjobs run on which aspect
- spring.session.enabled: turns on HTTP session failover, which persists sessions to the database (
storedhttpsessions) so a lost node does not log the shopper out - webapps: which web applications deploy to this aspect (storefront, backoffice)
CCv2 Build Process#
CCv2 builds are triggered via Git push to the cloud portal repository. Build pipeline:
graph LR
A[Git Push] --> B[Cloud Portal Webhook]
B --> C[Build Server: ant clean all]
C --> D[Docker Image Build]
D --> E[Image Push to Registry]
E --> F[Deployment to Environment]
F --> G[Health Check]
G --> H[Traffic Cutover]
Build stages:
- Source checkout: Cloud portal clones the repository
- Ant build:
ant clean allcompiles the platform and every extension in the build path - Docker image: Platform + extensions packaged into Docker image
- Image push: Image pushed to CCv2 registry (GCR/ACR)
- Deployment: Rolling deployment to target environment
- Health check: the platform must answer before the load balancer admits traffic
- Traffic cutover: Load balancer switches to new pods
Build artifacts:
hybris/bin/platform: compiled platformhybris/data: initial data (ImpEx, media)manifest.json: aspect configurationsolr/: Solr core config (if using embedded Solr)
CCv2 Deployment Environments#
CCv2 provides isolated environments for each stage of the SDLC:
| Environment | Purpose | Refresh Strategy |
|---|---|---|
| Development | Feature development, integration testing | Database copy on request (Cloud Portal) |
| Staging | Pre-production testing, UAT | Database copy on request (Cloud Portal) |
| Production | Live customer traffic | Blue/green deployment |
Each environment has:
- Dedicated database (Azure SQL)
- Dedicated Solr cluster (search index)
- Dedicated Azure Blob storage (media files)
Environment Variables#
CCv2 injects environment-specific config via environment variables:
# hybris/config/local.properties, for local development only.
# CCv2 runs on Azure SQL, so the driver is the Microsoft one.
db.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
db.url=jdbc:sqlserver://localhost:1433;databaseName=commerce
On CCv2 you do not set the datasource yourself. The platform receives it from the environment, and the configuration you control arrives two ways:
manifest.json: properties committed with the code, per aspect, and theuseConfigblock that points at property files in the repository- Cloud Portal service configuration: environment-specific values, including secrets, held outside the repository
Anything a Kubernetes habit tells you to set as a pod environment variable belongs in one of those two places instead.
Data Model Patterns#
Product Model#
Products in SAP Commerce are hierarchical:
- Product (base type): sku, name, description
- VariantProduct (extends Product): color, size variants
- ApparelProduct / ElectronicsProduct: domain-specific extensions
Products belong to Catalogs and Categories. Classification via ClassificationClass and ClassificationAttribute for faceted navigation.
Catalog versioning:
- Staged: content editing, not visible to customers
- Online: published content, customer-facing
Price Model#
Pricing is multi-dimensional via PriceRow:
PriceRow: product + user group + currency + unit + date range → price
Price calculation via PriceFactory and PriceService. Discounts and promotions run on the Drools rule engine (ruleengineservices, promotionengineservices), which compiles rules into a rule module and evaluates them against the cart.
Price resolution order:
- User-specific price (B2B negotiated pricing)
- User group price (customer segment)
- Base price (fallback)
Order Model#
Order lifecycle:
- Cart (
CartModel): the shopping cart. It is a sibling ofOrderModel, not a mode of it; both extendAbstractOrderModel. - Order (OrderModel submitted): placed order
- ConsignmentEntry: fulfillment/shipment
Order calculation via CalculationService applies totals, taxes, and discounts in sequence:
- Item prices
- Discounts (order-level, line-level)
- Delivery cost
- Taxes
- Payment cost
Cluster Topology#
CCv2 runs SAP Commerce in a clustered environment. Key clustering patterns:
Session Replication#
CCv2 does not provision a Redis instance, so the Spring Boot session stores you may have used elsewhere are not on the menu. Two mechanisms carry the session:
| Mechanism | What it does | Where it applies |
|---|---|---|
| Sticky sessions | The load balancer keeps a shopper on the node that holds their session | Always on, and the first line of defence |
| HTTP Session Failover | Spring Session persists the session to the database (storedhttpsessions) so another node can pick it up when one dies | Opt-in, per web application |
Enable failover per webapp rather than globally, because every persisted session is a database write on the hot path:
spring.session.enabled=true
spring.session.yacceleratorstorefront.save=async
Sticky sessions alone lose the cart when a node restarts mid-deployment. Failover costs write throughput. Pick per application, not per project.
Media Storage#
Media files (images, documents) must be shared across nodes:
- On-premise: Shared filesystem (NFS)
- CCv2: Azure Blob Storage or AWS S3
Azure Blob config:
media.default.url.strategy=azure
media.azure.storage.account.connection-string=${AZURE_STORAGE_CONNECTION_STRING}
media.azure.storage.container.name=commerce-media
Task Engine#
The Task Engine runs background jobs (cronjobs). In a cluster:
- Tasks are locked at the database level (distributed lock)
- Only one node executes a given task at a time
- Node groups control which aspect executes which cronjob
Node group assignment:
cluster.node.groups=integration,yHotfolderCandidate,backgroundProcessing
Integration Patterns#
OCC (Omni Commerce Connect)#
Standard REST API for headless storefronts:
- Base path:
/occ/v2/{baseSiteId}/ - Endpoints:
/products,/carts,/users,/orders - OAuth2 authentication (client credentials, password grant)
- Extensible via custom controllers and DTOs
OCC endpoint example:
GET /occ/v2/electronics/products/1234?fields=FULL
Authorization: Bearer <token>
Response:
{
"code": "1234",
"name": "Sample Product",
"price": {
"value": 99.99,
"currencyIso": "USD"
},
"stock": {
"stockLevel": 10
}
}
ImpEx#
Data import/export DSL (Domain-Specific Language):
INSERT_UPDATE Product; code[unique=true]; name; catalogVersion(catalog(id),version)
; product123 ; "Sample Product" ; Default:Staged
; product456 ; "Another Product" ; Default:Staged
INSERT_UPDATE Category; code[unique=true]; name; catalogVersion(catalog(id),version)
; cat001 ; "Electronics" ; Default:Staged
INSERT_UPDATE CategoryProductRelation; source(code,catalogVersion(catalog(id),version)); target(code,catalogVersion(catalog(id),version))
; cat001:Default:Staged ; product123:Default:Staged
Used for:
- Initial data load (essential data, sample data)
- Migrations (data model changes)
- Test data setup (integration tests)
- Bulk operations (price updates, catalog sync)
Event System#
SAP Commerce publishes Business Events for async processing:
@Component
public class OrderPlacedEventListener extends AbstractEventListener<OrderPlacedEvent> {
@Resource
private EmailService emailService;
@Override
protected void onEvent(OrderPlacedEvent event) {
final OrderModel order = event.getOrder();
emailService.sendOrderConfirmation(order);
}
}
Events are:
- Synchronous by default: an event published on one node runs its listeners on
the caller's thread. Only events implementing
ClusterAwareEventleave the node and go asynchronous, so a slow listener is your slow request. - Not transactional by default: the event fires on the change, not on the
commit. To wait for the commit, implement
TransactionAwareEventand setpublishOnCommitOnly. Otherwise a rolled-back transaction has already told the rest of the system it happened. - In-memory: the event bus holds nothing. A listener that is down when the event fires never sees it, and there is no replay. Where you need delivery guarantees, use webhooks or write your own audit record.
Common events:
OrderPlacedEventProductModifiedEventCustomerRegisteredEventCartModifiedEvent
Performance Considerations#
Caching#
SAP Commerce uses multi-layer caching:
| Cache Type | Mechanism | Scope |
|---|---|---|
| Region Cache | Ehcache | Type system, catalogs, CMS |
| FlexibleSearch Cache | Query result cache | Read-heavy queries |
| CMS Page Cache | Pre-rendered pages | Storefront performance |
Region cache sizes are set per region, not per extension. The region names are fixed by the platform (entityregion, typesystemregion, querycacheregion and so on):
regioncache.entityregion.size=2000000
regioncache.entityregion.evictionpolicy=LRU
Database Optimization#
- Use FlexibleSearch with proper indexing (not raw SQL)
- Avoid N+1 queries. Fetch relations in one query
- Partition large tables (
OrderEntry,PriceRow,CustomerReview) - Monitor slow queries via DB Performance Monitoring in HAC
Index example:
CREATE INDEX idx_product_code ON products(p_code);
CREATE INDEX idx_order_user ON orders(p_user);
Clustering Best Practices#
- Session replication: sticky sessions plus database-backed failover on the storefront webapp; there is no Redis on CCv2
- Media storage: External blob storage (Azure/S3), not filesystem
- Task Engine: Assign cronjobs to
backgroundProcessingaspect only - Health checks: CCv2 runs these for you; your job is to keep startup deterministic so a node is ready when it says it is
- Logging: Centralized logging (ELK, Splunk) for distributed tracing
Next Steps#
These deeper guides are in development. Topics planned:
- OCC API Integration Patterns
- Backoffice Customization
- Promotion Engine (CAP) deep dive
- Spartacus / Composable Storefront architecture
- CCv2 deployment troubleshooting