Share

[[{“value”:”

If you’re reading this, you’re probably wondering whether it’s time to move from your SAP Commerce Accelerator to Composable Storefront. Maybe your front-end team is frustrated with JSP templates, or you need better mobile experience. Let me walk you through what this migration actually looks like, based on real experience.

Why Migrate?

What you’re leaving behind:

  • Server-side JSP rendering
  • Tightly coupled front-end and back-end
  • Limited mobile experience

What you’re getting:

  • Modern Angular-based SPA
  • Decoupled architecture via OCC APIs
  • Better performance with SSR
  • Independent front-end deployment

The catch? You’re moving from monolithic to microservices-style architecture. Your team needs JavaScript/TypeScript skills.

Step 1: Assessment

Start by cataloging your customizations:

# Find custom JSP files
find web/webroot/WEB-INF/views -name "*.jsp" | grep -v "/yacceleratorstorefront/"

# Custom controllers
grep -r "@Controller" --include="*Controller.java" | grep -v "de.hybris.platform"

Create a spreadsheet with every customization. This becomes your migration backlog.

Step 2: Build OCC Foundation

You need to expose everything via OCC APIs first. Here’s a quick example for custom product data:

// Custom WsDTO
@ApiModel(value = "customProduct")
public class CustomProductWsDTO extends ProductWsDTO {
    private String warrantyInfo;
    private String installationGuideUrl;
    // getters/setters
}

// Populator
public class CustomProductPopulator implements Populator<ProductModel, CustomProductWsDTO> {
    @Override
    public void populate(ProductModel source, CustomProductWsDTO target) {
        target.setWarrantyInfo(source.getWarrantyInfo());
        target.setInstallationGuideUrl(source.getInstallationGuideUrl());
    }
}

For custom business logic, create OCC endpoints:

@Controller
@RequestMapping(value = "/{baseSiteId}/custom")
public class CustomOccController {
    
    @GetMapping("/products/{productCode}/compatibility")
    @ResponseBody
    public CompatibilityWsDTO checkCompatibility(
            @PathVariable String productCode,
            @RequestParam String customerProductId) {
        
        CompatibilityData data = customProductFacade
            .checkProductCompatibility(productCode, customerProductId);
        return dataMapper.map(data, CompatibilityWsDTO.class);
    }
}

Step 3: Setup Composable Storefront

# Install and setup
ng new my-storefront
cd my-storefront
ng add @spartacus/schematics --base-site=electronics --base-url=https://localhost:9002

Configure your endpoints:

// spartacus-configuration.module.ts
provideConfig({
  backend: {
    occ: {
      baseUrl: environment.occBaseUrl,
      prefix: '/occ/v2/',
      endpoints: {
        product: 'products/${productCode}?fields=DEFAULT,warrantyInfo',
        productCompatibility: 'custom/products/${productCode}/compatibility'
      }
    }
  },
  context: {
    baseSite: ['electronics'],
    currency: ['USD'],
    language: ['en']
  }
})

Step 4: Migrate Components

Here’s a real migration example.

Old Accelerator JSP:

<div class="product-detail">
    <h1>${product.name}</h1>
    <div class="warranty-info">
        <strong>Warranty:</strong> ${product.warrantyInfo}
    </div>
</div>

New Angular Component:

// custom-product-detail.component.ts
@Component({
  selector: 'app-custom-product-detail',
  templateUrl: './custom-product-detail.component.html'
})
export class CustomProductDetailComponent implements OnInit {
  product$: Observable<CustomProduct>;
  
  constructor(
    private currentProductService: CurrentProductService,
    private customProductService: CustomProductService
  ) {}
  
  ngOnInit(): void {
    this.product$ = this.customProductService.getCustomProduct();
  }
}
<!-- custom-product-detail.component.html -->
<div *ngIf="product$ | async as product">
  <h1>{{ product.name }}</h1>
  <div *ngIf="product.warrantyInfo">
    <strong>{{ 'product.warranty' | cxTranslate }}:</strong>
    <p>{{ product.warrantyInfo }}</p>
  </div>
</div>

Replace default Spartacus components via config:

provideConfig({
  cmsComponents: {
    ProductDetailsTabComponent: {
      component: CustomProductDetailComponent
    }
  }
})

Step 5: Checkout

Adding custom checkout steps is straightforward:

// Custom step configuration
export const customCheckoutSteps = [
  {
    id: 'deliveryAddress',
    name: 'checkoutProgress.deliveryAddress',
    routeName: 'checkoutDeliveryAddress',
    type: [CheckoutStepType.DELIVERY_ADDRESS]
  },
  {
    id: 'giftMessage',  // Your custom step
    name: 'checkoutProgress.giftMessage',
    routeName: 'checkoutGiftMessage',
    type: [CheckoutStepType.PAYMENT_DETAILS]
  },
  // ... more steps
];

Step 6: SSR Setup

ng add @spartacus/setup --ssr

Add caching for better performance:

// server.ts
const cache = new LRU({
  max: 100,
  ttl: 1000 * 60 * 60 // 1 hour
});

app.engine('html', (filePath, options, callback) => {
  const cacheKey = options.req.url;
  const cachedHtml = cache.get(cacheKey);
  
  if (cachedHtml) {
    return callback(null, cachedHtml);
  }
  
  ngExpressEngine({ bootstrap: AppServerModule })(filePath, options, (err, html) => {
    if (!err && html) cache.set(cacheKey, html);
    callback(err, html);
  });
});

Step 7: Deploy

npm run build:ssr

Simple Kubernetes deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: composable-storefront
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: storefront-ssr
        image: your-registry/composable-storefront:latest
        ports:
        - containerPort: 4000
        env:
        - name: OCC_BASE_URL
          value: "https://your-commerce-backend.com"

Common Issues & Quick Fixes

CORS errors?

# local.properties
corsfilter.commercewebservices.allowedOrigins=http://localhost:4200

Random logouts?

provideConfig({
  session: { synchronization: true }
})

Translations not working? Structure your i18n files properly:

// assets/i18n/en/product.json
{
  "product": {
    "warranty": "Warranty",
    "downloadGuide": "Download Guide"
  }
}

My Advice

Don’t try to migrate everything at once. Start with one section, test thoroughly, then expand. The Composable Storefront is actively maintained by SAP, so you’re not just modernizing—you’re joining an ecosystem that keeps evolving.

The migration is substantial but worth it. Your team gets modern tooling, faster deployments, and better customer experience.

DISCLAIMER – This is the process according to my experience which I have done in the past, this is not a official documentation.

“}]] 

 [[{“value”:”If you’re reading this, you’re probably wondering whether it’s time to move from your SAP Commerce Accelerator to Composable Storefront. Maybe your front-end team is frustrated with JSP templates, or you need better mobile experience. Let me walk you through what this migration actually looks like, based on real experience.Why Migrate?What you’re leaving behind:Server-side JSP renderingTightly coupled front-end and back-endLimited mobile experienceWhat you’re getting:Modern Angular-based SPADecoupled architecture via OCC APIsBetter performance with SSRIndependent front-end deploymentThe catch? You’re moving from monolithic to microservices-style architecture. Your team needs JavaScript/TypeScript skills.Step 1: AssessmentStart by cataloging your customizations:# Find custom JSP files
find web/webroot/WEB-INF/views -name “*.jsp” | grep -v “/yacceleratorstorefront/”

# Custom controllers
grep -r “@Controller” –include=”*Controller.java” | grep -v “de.hybris.platform”Create a spreadsheet with every customization. This becomes your migration backlog.Step 2: Build OCC FoundationYou need to expose everything via OCC APIs first. Here’s a quick example for custom product data:// Custom WsDTO
@ApiModel(value = “customProduct”)
public class CustomProductWsDTO extends ProductWsDTO {
private String warrantyInfo;
private String installationGuideUrl;
// getters/setters
}

// Populator
public class CustomProductPopulator implements Populator<ProductModel, CustomProductWsDTO> {
@Override
public void populate(ProductModel source, CustomProductWsDTO target) {
target.setWarrantyInfo(source.getWarrantyInfo());
target.setInstallationGuideUrl(source.getInstallationGuideUrl());
}
}For custom business logic, create OCC endpoints:@Controller
@RequestMapping(value = “/{baseSiteId}/custom”)
public class CustomOccController {

@GetMapping(“/products/{productCode}/compatibility”)
@ResponseBody
public CompatibilityWsDTO checkCompatibility(
@PathVariable String productCode,
@RequestParam String customerProductId) {

CompatibilityData data = customProductFacade
.checkProductCompatibility(productCode, customerProductId);
return dataMapper.map(data, CompatibilityWsDTO.class);
}
}Step 3: Setup Composable Storefront# Install and setup
ng new my-storefront
cd my-storefront
ng add @spartacus/schematics –base-site=electronics –base-url=https://localhost:9002Configure your endpoints:// spartacus-configuration.module.ts
provideConfig({
backend: {
occ: {
baseUrl: environment.occBaseUrl,
prefix: ‘/occ/v2/’,
endpoints: {
product: ‘products/${productCode}?fields=DEFAULT,warrantyInfo’,
productCompatibility: ‘custom/products/${productCode}/compatibility’
}
}
},
context: {
baseSite: [‘electronics’],
currency: [‘USD’],
language: [‘en’]
}
})Step 4: Migrate ComponentsHere’s a real migration example.Old Accelerator JSP:<div class=”product-detail”>
<h1>${product.name}</h1>
<div class=”warranty-info”>
<strong>Warranty:</strong> ${product.warrantyInfo}
</div>
</div>New Angular Component:// custom-product-detail.component.ts
@Component({
selector: ‘app-custom-product-detail’,
templateUrl: ‘./custom-product-detail.component.html’
})
export class CustomProductDetailComponent implements OnInit {
product$: Observable<CustomProduct>;

constructor(
private currentProductService: CurrentProductService,
private customProductService: CustomProductService
) {}

ngOnInit(): void {
this.product$ = this.customProductService.getCustomProduct();
}
}<!– custom-product-detail.component.html –>
<div *ngIf=”product$ | async as product”>
<h1>{{ product.name }}</h1>
<div *ngIf=”product.warrantyInfo”>
<strong>{{ ‘product.warranty’ | cxTranslate }}:</strong>
<p>{{ product.warrantyInfo }}</p>
</div>
</div>Replace default Spartacus components via config:provideConfig({
cmsComponents: {
ProductDetailsTabComponent: {
component: CustomProductDetailComponent
}
}
})Step 5: CheckoutAdding custom checkout steps is straightforward:// Custom step configuration
export const customCheckoutSteps = [
{
id: ‘deliveryAddress’,
name: ‘checkoutProgress.deliveryAddress’,
routeName: ‘checkoutDeliveryAddress’,
type: [CheckoutStepType.DELIVERY_ADDRESS]
},
{
id: ‘giftMessage’, // Your custom step
name: ‘checkoutProgress.giftMessage’,
routeName: ‘checkoutGiftMessage’,
type: [CheckoutStepType.PAYMENT_DETAILS]
},
// … more steps
];Step 6: SSR Setupng add @spartacus/setup –ssrAdd caching for better performance:// server.ts
const cache = new LRU({
max: 100,
ttl: 1000 * 60 * 60 // 1 hour
});

app.engine(‘html’, (filePath, options, callback) => {
const cacheKey = options.req.url;
const cachedHtml = cache.get(cacheKey);

if (cachedHtml) {
return callback(null, cachedHtml);
}

ngExpressEngine({ bootstrap: AppServerModule })(filePath, options, (err, html) => {
if (!err && html) cache.set(cacheKey, html);
callback(err, html);
});
});Step 7: Deploynpm run build:ssrSimple Kubernetes deployment:apiVersion: apps/v1
kind: Deployment
metadata:
name: composable-storefront
spec:
replicas: 3
template:
spec:
containers:
– name: storefront-ssr
image: your-registry/composable-storefront:latest
ports:
– containerPort: 4000
env:
– name: OCC_BASE_URL
value: “https://your-commerce-backend.com”Common Issues & Quick FixesCORS errors?# local.properties
corsfilter.commercewebservices.allowedOrigins=http://localhost:4200Random logouts?provideConfig({
session: { synchronization: true }
})Translations not working? Structure your i18n files properly:// assets/i18n/en/product.json
{
“product”: {
“warranty”: “Warranty”,
“downloadGuide”: “Download Guide”
}
}My AdviceDon’t try to migrate everything at once. Start with one section, test thoroughly, then expand. The Composable Storefront is actively maintained by SAP, so you’re not just modernizing—you’re joining an ecosystem that keeps evolving.The migration is substantial but worth it. Your team gets modern tooling, faster deployments, and better customer experience.DISCLAIMER – This is the process according to my experience which I have done in the past, this is not a official documentation.”}]] Read More Technology Blog Posts by SAP articles 

#SAPCHANNEL

By ali