← Back to list

Tech lens: Solutioning a data bridge for application hosted on eCommerce webpages

Alternative pattern choices of two or more tech stacks serving the modern online shopping experience.

Andre Le · 2025-11-16 04:54 · 0 claps · 14.7 min read paywalled
#technical-solution #ecommerce-web-development #aem #single-page-applications #react-app
Open on Medium ↗
Wiki topics: OPS · LLMOps & Inference 🌐 · Web Development

Tech lens: Solutioning a data bridge for application hosted on eCommerce webpages

Alternative pattern choices of two or more tech stacks serving the modern online shopping experience.

— — —

This article also posted to my 021Lab Substack

— — —

Introduction

Enterprise’s eCommerce sites are often made of various layers. This might sound strange, but most online shopper out there might not realize that a website for this purpose, under the surface, are made up from more than one tech stacks — where multiple JavaScripts modules are served through different applications, platforms or plugins. This modern design is to ensure engaging user shopping experience and making informed purchase decision.

Despite the above apparent advange, multi-stack design come with its own challenge when there is need to require these modules exchange data with each other during the customer’s activities and interaction with the site. Choosing the right data exchange pattern is not just a simple sending / receiving data but it is also influenced by many factors including:

  • User experience: Does customer interaction require the front-end UI to have short-term “memory” that persists for a period of time?
  • Data management and validation: How frequently or responsively should the data be updated? How long should it be cached?
  • Online security: Does the data bridge accidentally expose any sensitive information?
  • Load performance: How responsive and fast should the front-end components update when users move through their sales journey?

…and many more.

In this article, we shall examine various mechanisms for a data bridge between a single-page application (SPA) and a headless Content Management System (CMS) component. For CMS, I will cover my experience with the Adobe Experience Manager (AEM) platform.

The end goal is to have shopping cart components that are updated by users’ activities while simultaneously exchanging data and communicating back and forth with the application’s backend-for-frontend layer (BFF).

This setup deals with two main parts:

AEM Components

Built on a robust Java-based architecture, Adobe Experience Manager (AEM) stands as an enterprise-grade Content Management System that leverages a sophisticated technology stack comprising Apache Sling (RESTful web framework), Java Content Repository (JCR — specifically Apache Jackrabbit Oak), and OSGi (modular system for Java).

AEM is renowned for its powerful server-side rendering capabilities, primarily through HTL (HTML Template Language, formerly known as Sightly) — Adobe’s recommended templating system that has replaced JSP (JavaServer Pages) since AEM 6.0. AEM’s strength is further amplified by its position within the Adobe Experience Cloud ecosystem, offering seamless integrations with complementary Adobe products:

  • Adobe Campaign: Native integration for managing email delivery content and forms directly within AEM, enabling coordinated marketing campaigns
  • Adobe Firefly: Integration of generative AI capabilities for content creation, allowing marketers and content authors to generate and modify images with text-to-image functionality directly within the DAM
  • Adobe Creative Cloud (formerly Creative Suite): Deep integration with Creative Cloud applications through Adobe Asset Link and Adobe Express, enabling creative teams to access, modify, and synchronize DAM assets while staying within their familiar creative tools
  • Adobe Experience Platform: Foundation for customer data management and real-time insights
  • Adobe Analytics & Target: For comprehensive analytics and personalization capabilitiesReact / Angular Single-Page Application (SPA)

Sources:

[embed]AEM Technical Foundations | Adobe Experience Manager An overview of the technical foundations of AEM including how AEM is structured and fundamental technologies like JCR…experienceleague.adobe.com

[embed]Assets Integrations | Adobe Experience Manager Assets Streamline asset production and integrate with Adobe and third-party tools to boost collaboration, governance, and…business.adobe.com

React / Angular Single-Page Application (SPA)

Both React and Angular have emerged as leading frameworks for building dynamic eCommerce experiences, each bringing distinct advantages to the table:

React:

  • Component-based architecture: React’s modular approach allows teams to build isolated, reusable cart components, product listings, and checkout flows that can be independently tested and deployed
  • Virtual DOM performance: For eCommerce sites with frequent cart updates and dynamic product filtering, React’s efficient reconciliation algorithm ensures smooth, lag-free interactions even with hundreds of products on a page
  • Rich ecosystem: Libraries like Redux for state management, React Query for server state synchronization, and Next.js for server-side rendering make React particularly attractive for complex shopping experiences
  • Flexibility: React’s unopinionated nature allows teams to choose their preferred routing, state management, and styling solutions, adapting easily to existing tech stacks
  • Progressive adoption: React can be incrementally integrated into existing AEM sites, starting with small components like “Add to Cart” buttons before expanding to full checkout flows

Angular:

  • Full-featured framework: Angular provides an opinionated, batteries-included approach with built-in routing, form validation, HTTP clients, and dependency injection — reducing decision fatigue for enterprise teams
  • TypeScript-first: Strong typing catches cart calculation errors, shipping address validation issues, and product data mismatches at compile time rather than in production
  • Two-way data binding: Simplifies complex form interactions common in checkout processes, automatically synchronizing user inputs with the underlying cart model
  • Enterprise scalability: Angular’s structure and conventions make it easier to maintain consistency across large teams working on different parts of the eCommerce experience
  • RxJS integration: Reactive programming patterns excel at handling complex asynchronous scenarios like real-time inventory updates, shipping cost calculations, and multi-step checkout flows

In the eCommerce Context:

For cart management specifically, React’s lighter weight and faster initial rendering make it ideal for quick “add to cart” interactions and product quick-views. Angular’s comprehensive form handling and validation shine in multi-step checkout processes with complex business rules. React typically excels in marketing-heavy pages where content needs to be highly dynamic and personalized, while Angular’s structure provides better long-term maintainability for large-scale enterprise commerce platforms with extensive product catalogs and complex pricing logic.

Both frameworks support progressive web app (PWA) capabilities essential for mobile commerce, offline cart persistence, and push notifications for abandoned cart recovery. The choice often comes down to existing team expertise, integration requirements with backend systems, and the specific performance characteristics needed for your customer base.

As discussed previously, there are different mean to enable the data exchange between AEM and SPA, each with their own complexity and benefits. We shall explore three different patterns:

  • Pattern #1: API with Middleware Layer
  • Pattern #2: prominent Adobe Stack with AEM GraphQL client to Adobe Commerce (CRM)
  • Pattern #3: Web-browser session storage

Pattern 1: API with Middleware Layer

How it works at high-level

  • AEM components make REST/GraphQL calls to an established API gateway
  • The gateway handles authentication, rate limiting, and request routing
  • Backend cart service (CRM) processes the business logic
  • Response flows back through the middleware layer to AEM
┌─────────────┐      ┌──────────────┐       ┌───────────────┐
│ AEM Frontend│─────▶│ API Gateway  │─────▶│   Backend     │
│ Components  │◀─────│  Middleware  │◀─────│ Cart Service  │
│             │      │              │       │  (BFF)        │ 
└─────────────┘      └──────────────┘       └───────────────┘

Implementation focus

Implementation will center on establishing the core technical foundations for the new cart service in the BFF layer (if there is not an existing one). A primary requirement is the creation of comprehensive API endpoint documentation and firm contracts, which will define the precise rules of interaction between the front-end events and expected payload from the BFF. Alongside this, a secure authentication token management system must be developed to govern machine-to-machine access. To ensure stability and prevent abuse, we will configure system-wide rate limiting. Furthermore, the design must include robust error handling and intelligent retry logic to manage failures gracefully. Finally, a strategic response caching strategy will be implemented to optimize performance and reduce load by serving frequently requested data efficiently.

Technical Constraint & Challenges

  • Additional network hop introduces latency: A user’s request on the mobile app normally goes directly to the UserService (20ms response). With middleware, the request goes App -> Middleware -> UserService. Even if the middleware just forwards the request instantly, the physical time to establish that extra network connection and send/receive the data packets adds 15ms, making the total response time 35ms.
  • Middleware layer requires ongoing maintenance: in enterprise context, request into backend modules often need to be routed though API gateway — the platform team who maintain the API gateway may have additional patching requirements when new vulnerable or threat emerge as well as loggings resources. Having this middle layer also means that new change will have to be tested (to ensure patching didn’t break routing), and re-deploy the entire middleware layer, potentially requiring a small amount of downtime
  • Changes require multi-service coordination: The business wants to add a “loyalty points” discount to the checkout. This requires the UserService to expose the points, the PromoService to calculate the discount, and the PaymentService to apply it. With middleware, the Middleware itself must also be updated to combine this data. All four teams (Front-end, Middleware, User, Promo, Payment) must coordinate their code, testing, and deployment, as deploying one part without the others will break the checkout flow
  • API versioning complexity: If your web app (v1) expects a user’s address as a single string: "address": "123 Main St". The new web app (v2) needs it as an object: "address": { "street": "123 Main St", "city": "Anytown" }. The backend service is updated to v2. The middleware must now look at every request: if it's a v1 request, it must get the v2 object from the backend and transform it back into a single string. This transformation logic has to be built and maintained until all v1 mobile apps are retired

Pattern 2: GraphQL to Adobe Commerce(*)

(*) Adobe Commerce (formerly known as Magento) is the native CRM platform by Adobe

How it works at high-level

  • AEM components include a GraphQL client library
  • Direct queries to Adobe Commerc’s GraphQL API endpoints
  • Flexible query structures fetch exactly what’s needed
  • Real-time cart state updates without middleware translation

Note: If your company use a different CRM platforms such as Salesforce, HubSpot, or Microsoft Dynamics for lead management, customer data synchronization, and personalization, then an additional effort will be require to develop a connector layer using the aforementioned vendor’s Web SDKs. Check to see if there could be a pre-built, out-of-the-box (OOTB) connectors provided by Adobe already for such a vendor (e.g., Salesforce); otherwise the engineering team would need to implement custom-built AEM (OSGi) services that consume the CRM’s specific SDKs or REST APIs.

┌─────────────┐      ┌─────────────────────────┐
│ AEM Frontend│─────▶│     Adobe Commerce     │
│   + GraphQL │◀─────│   GraphQL API          │
│   Client    │      └────────────────────────┘
└─────────────┘

Implementation focus

Of the three options, this approach is heavily intended for Adobe stacks, as Adobe Commerce (aka Magento) and AEM are both within the company’s ecosystem. At its foundation, we will continue to utilize AEM 6.5+, but its interaction with backend data will be modernized through a GraphQL client library. This library will enable AEM components to directly consume data from the GraphQL layer, providing precise data retrieval capabilities.

On the frontend, for complex interactions or where a full-fledged data layer is beneficial, we will integrate a robust GraphQL framework such as Apollo Client. This framework will empower the frontend applications to construct sophisticated queries, manage local state, and interact seamlessly with our GraphQL endpoints. The core data source for product, cart, and customer information will be the Adobe Commerce GraphQL endpoints. This allows engineering teams leverage directly into the Adobe Commerce’s rich commerce capabilities using a standardized, self-documenting API.

Security for these frontend interactions will be handled via JWT (JSON Web Token) authentication, ensuring that all requests from the client are properly authenticated and authorized. The implementation requirements for this shift are substantial: we must first define and validate our GraphQL schema and type definitions, ensuring consistency and clarity across all data interactions. We will focus heavily on client-side query optimization to minimize network roundtrips and data over-fetching. Robust frontend authentication token handling will be developed to securely manage JWT lifecycles, including refreshing and storage. A comprehensive cache invalidation strategy is critical for ensuring data freshness, especially in a distributed environment. Finally, error boundary implementation will be crucial for gracefully handling GraphQL errors on the client, preventing application crashes and providing a better user experience.

Example of GraphQL Schema (for illustration)

type Cart {
  id: ID!
  items: [CartItem!]!
  subtotal: Money!
  discounts: [Discount!]
  tax: Money!
  total: Money!
}

type Mutation {
  addToCart(input: AddToCartInput!): Cart!
  updateCartItem(input: UpdateCartItemInput!): Cart!
  removeFromCart(cartItemId: ID!): Cart!
}

Technical Constraint & Challenges

  • Team upskilling may required for GraphQL: GraphQL is not as common as RESTful or HTTP Webrequest query. Introducing GraphQL means if current engineers in the team were not familiar with its syntax, they would need to learn a new query language, understand schema definitions, grasp concepts like fragments and directives, and adapt to a different way of thinking about data fetching (e.g., using useQuery hooks instead of fetch with specific endpoints). Without dedicated training and hands-on practice, developers might initially write inefficient queries that over-fetch, causing performance issues, or struggle with complex mutations, leading to slower development cycles.
  • Frontend layer assumes more responsibility: In a traditional REST setup, a backend service might aggregate data from multiple sources (e.g., product details from CRM, customer reviews from a separate review service) into a single /product-detail endpoint. With GraphQL, the frontend is often responsible for constructing a single query that explicitly requests data from different parts of the schema (e.g., product { id name reviews { text rating } }). This means the frontend developers now need a deeper understanding of the entire data model and potential performance implications of their queries, rather than just consuming a predefined API response.
  • Authentication complexity increases: With traditional session cookies, the browser handles much of the authentication flow. With JWTs for a GraphQL frontend, the application itself is responsible for storing the token (e.g., in localStorage or HttpOnly cookies), attaching it to every GraphQL request, managing its expiration, and securely refreshing it when it nears expiry. If the refresh mechanism fails or the token is compromised (e.g., through an XSS attack), the user's session can be broken, or their data exposed. This requires meticulous implementation of secure token management on the client-side.

Pattern 3: SPA + Browser Storage

How it works at high-level

  • Cart state lives entirely in the browser (cookies or localStorage)
  • SPA team’s application manages all cart interactions
  • AEM components render the cart UI but defer logic to client-side JavaScript
  • Periodic sync with backend for persistence and checkout
┌─────────────┐      ┌──────────────┐
│ AEM Frontend│─────▶│ SPA Cart App │
│  (Minimal)  │      │   + Storage  │
└─────────────┘      └──────┬───────┘
                             │ (Async Sync)
                     ┌───────▼───────┐
                     │    Backend    │
                     │  Persistence  │
                     └───────────────┘

Implementation focus

The core of this approach is a shift in architecture, moving critical cart functionality from the server to the client. We will use AEM as the primary content delivery platform, but its role in the checkout process will be intentionally minimal. Instead, we will be developing a dedicated Single Page Application (SPA), using one of the popular JavaScript framewoks React, Angular or Vue, to manage all aspects of the shopping cart. This SPA will be injected into the AEM-rendered pages, taking full control of the user’s cart management. The central requirement for this build is an offline-first architecture, ensuring that a user can add or modify cart items even with an unstable or non-existent internet connection. To achieve this, we will rely on browser-side storage, specifically localStorage for simple data and IndexedDB for more complex cart objects and user details. A robust state management library, such as Redux or Vuex, will be implemented to manage this client-side data and UI state effectively. A critical component of this strategy is the background sync service worker. This service worker will be responsible for detecting network availability and managing the periodic backend synchronization process. When a user is offline, all changes (like adding an item) will be queued locally. Once a connection is re-established, the service worker will automatically sync these changes with the backend. This asynchronous process necessitates the design of sophisticated conflict resolution algorithms to handle data discrepancies between the local state and the server state. Finally, given that we will be storing user and cart data on the client’s device, a comprehensive security audit for all client-side storage is a mandatory deliverable to protect against data theft and manipulation

Technical Constraint & Challenges

  • Limited persistence: if we plan to use localStorage or IndexedDB, but these have hard quotas, typically around 5-10MB per origin. If a user is a power shopper, or if they leave items in their cart for months, the accumulated product data, metadata, and thumbnails could eventually hit this cap. When the browser throws a QuotaExceededError , the "add to cart" function will fail. The design must therefore include data-caching policies, LRU (Least Recently Used) eviction strategies, or clear error handling for when storage is full.
  • State Synchronization complexity: This challenge come from the issue when we try to reconcile browser state with server state. A simple example is that auser on their phone (offline in a tunnel) adds the last “Medium Blue Shirt” to their cart. Before the phone regains signal, they log into their laptop (online) and also add the same “Medium Blue Shirt” and check out. The server now shows “0” in stock. A minute later, the phone comes back online. Its background sync service worker tries to tell the server, “Add one Medium Blue Shirt.” Our conflict resolution algorithm must handle this: it cannot simply add the item. It must recognize the conflict, see the item is now out of stock, and then sync this “out of stock” information back to the phone’s cart, showing the user a message.
  • Security considerations: To maintain the cart session, we might store a cart ID or even a temporary authentication token in localStorage. If the website has any Cross-Site Scripting (XSS) vulnerability (e.g., in a user review component), an attacker can inject a script to read the entire localStorage contents. They could steal the user’s token, impersonate them, and access their cart or personal information. Therefore, we must be exceptionally rigorous in sanitizing all inputs, setting HttpOnly flags on primary authentication cookies (even if the SPA uses a different token), and performing a security audit specifically targeting data exfiltration from client-side storage
  • Testing burden: Typical purchasing journey may consist of 3 or 4 different steps, including Add to cart → View cart → Update / modify cart → Shipping → Payment. Before reaching the final Confirmation step, the browser’s localStorage need to continue to reflect the correct information of the cart component. Therefore, this complex state management requires extensive testing, that need to be coordinated between the two layer stacks SPA and AEM.

A high-level comparison between 3 patterns

┌───────────────────────┬───────────────────────┬───────────────────────┐
│  SOLUTION 1: API/MW   │  SOLUTION 2: GraphQL  │  SOLUTION 3: SPA+Web  │
├───────────────────────┼───────────────────────┼───────────────────────┤
│ PROS:                 │ PROS:                 │ PROS:                 │
│ ✓ Low risk            │ ✓ Efficient queries  │ ✓ Fastest UX          │
│ ✓ 1-2 sprints         │ ✓ Less latency       │ ✓ Offline works       │
│ ✓ Team knows it       │ ✓ Modern API         │ ✓ Low server load     │
│ ✓ Security ready      │ ✓ Type safety        │ ✓ Simple AEM          │
│ ✓ Monitoring exists   │ ✓ Direct connection  │ ✓ Cost efficient      │
│                       │ ✓ Flexible data      │ ✓ <50ms response      │
├───────────────────────┼───────────────────────┼───────────────────────┤
│ CONS:                 │ CONS:                 │ CONS:                 │
│ ✗ Latency overhead    │ ✗ Team learning      │ ✗ Team dependency     │
│ ✗ Extra middleware    │ ✗ Auth complexity    │ ✗ Storage limits      │
│ ✗ Less flexible       │ ✗ More FE logic      │ ✗ Sync complexity     │
│ ✗ Higher infra cost   │ ✗ 3-4 sprints        │ ✗ Security concerns   │
│ ✗ More scaling        │ ✗ Cache rethink      │ ✗ Complex testing     │
│                       │ ✗ New validation     │ ✗ State conflicts     │
└───────────────────────┴───────────────────────┴───────────────────────┘

Closing Thoughts

The choice between these three architectural patterns is not merely a technical decision — it’s a strategic one that must balance immediate business needs with long-term maintainability, team capabilities, and evolving customer expectations.

Pattern 1 (API with Middleware) represents the path of least resistance for many enterprise organizations. It leverages existing infrastructure, minimizes learning curves, and provides clear separation of concerns. Choose this pattern when your organization values stability over innovation, when you have established DevOps practices around API gateways, or when you’re working under tight deadlines with limited room for experimentation. The trade-off is accepting some performance overhead and infrastructure complexity in exchange for reduced technical risk.

Pattern 2 (GraphQL to Adobe Commerce) is the modern, Adobe-centric approach that shines when you’re deeply invested in the Adobe ecosystem and willing to invest in your team’s technical growth. This pattern offers the best balance of performance and flexibility, but requires a commitment to learning new paradigms and accepting increased frontend complexity. It’s ideal for organizations building next-generation commerce experiences, where the ability to fetch exactly the data you need can significantly improve page load times and user experience. However, ensure your team has the bandwidth for the 3–4 sprint investment and the ongoing maintenance of a more sophisticated frontend architecture.

Pattern 3 (SPA + Browser Storage) pushes the boundaries of what’s possible with client-side state management. It delivers the fastest, most responsive user experience and works beautifully offline — critical for mobile commerce scenarios. However, this pattern demands sophisticated engineering around state synchronization, conflict resolution, and security. Choose this when user experience is paramount, when your customer base has unreliable connectivity, or when you want to minimize backend infrastructure costs. Be prepared for the complexity that comes with distributed state management and ensure you have strong frontend engineering expertise.

Question to aid your decision for adoption

Consider these questions when choosing your pattern:

  1. What’s your risk tolerance? Lower risk → Pattern 1; Balanced → Pattern 2; High but calculated → Pattern 3
  2. How important is offline functionality? Critical → Pattern 3; Nice to have → Pattern 2; Not required → Pattern 1
  3. What’s your team’s skillset? Traditional backend-heavy → Pattern 1; Modern full-stack → Pattern 2; Frontend-first → Pattern 3
  4. Are you fully locked in to Adobe stack? Yes → Pattern 2; Partially → Pattern 1; No → Pattern 1 or 3
  5. What’s your performance requirement? Good enough → Pattern 1; Fast → Pattern 2; Blazing fast → Pattern 3

💡 Found This Helpful?

What patterns have you implemented in your eCommerce architecture? Share your experiences and lessons learned in the comments below.


메타데이터
post_id
35aedd13c3bd
slug
tech-lens-solutioning-a-data-bridge-for-application-hosted-on-ecommerce-webpages-35aedd13c3bd
url
https://medium.com/@expdal3/tech-lens-solutioning-a-data-bridge-for-application-hosted-on-ecommerce-webpages-35aedd13c3bd
canonical_url
https://medium.com/@expdal3/tech-lens-solutioning-a-data-bridge-for-application-hosted-on-ecommerce-webpages-35aedd13c3bd
author_url
https://medium.com/@expdal3
status
ok
fetched_at
2026-06-13 12:55:53