Impacted Services: Workflow Services, Workflow Client
Links: Please refer to Workflow Services 1.0.0 Release Notes, Workflow Client Release Notes
This service was previously released as Beta, but has now been released as GA.
Impacted Services: Audit Services, Audit Common
Links: Please refer to Audit Services 1.0.0 Release Notes, Audit Common Release Notes
This service was previously released as Beta, but has now been released as GA.
Impacted Services: CatalogServices, PricingServices, OfferServices, CartOperationServices, OrderOperationServices, SubscriptionOperationServices, BillingServices, WorkflowServices, AuditServices
Highlights:
Subscription Purchase & Fulfillment: Out-of-box support for handling subscription-based products directly within the cart & checkout.
Subscription Management: Manage the full subscription lifecycle with configurable edit, upgrade, downgrade, and cancellation scenarios. Includes advanced support for sandboxing and delayed prepaid actions.
Recurring Billing: A highly configurable recurring billing engine that works in conjunction with Broadleaf’s Catalog, Pricing, and Offer Engines to support complex or unique recurring billing needs.
CSR Interactions: Allow CSRs to manage subscriptions price changes and add discounts to existing subscriptions.
Impacted Services: Payment Transaction Services
Links: Please refer to
Impacted Services: n/a (DevOps/Infra concern)
Links: Please refer to Kafka KRaft and Strimzi Operator Release Notes and Support Documentation for more information.
Impacted Services: Admin Navigation Services, Authentication Services, Cart Operation Services, Pricing Services
Links: Please refer to
2.3.0 Admin Navigation Release Notes (new navigation section)
2.3.0 Authentication Release Notes (introduced new scopes and permissions)
Impacted Services: Avalara Tax, Cart Operation Services, Order Services, Order Operation Services
Links: Please refer to
Impacted Services: Catalog Services, Catalog Browse Services, Pricing Services
Links: Please refer to
Impacted Services: Microservices Gateways
Highlights:
Rewrote OAuth2ClientCredentialsGatewayFilterFactory to use a fully non-blocking mechanism for all logic related to obtaining a new access token.
Rewrote ApplicationTokenGatewayFilterFactory and ExternalApplicationResolverService to move blocking cache interactions off of the event loop thread and into worker threads.
Links: Please refer to Gateways 2.0.5
Impacted Services: Admin Web, Auth SDK, Commerce SDK, Payment JS SDK, Commerce Microfrontends, Default and Telco Next.js Starters, and Open API.
Note: All projects still support Node 18 and 20. Upgrading Node is not required but is strongly recommended for security since all prior versions have reached end-of-life support.
Links: Please refer to
Impacted Services: Admin Web (@broadleaf/admin-components, @broadleaf/admin-style, @broadleaf/admin-tailwindcss)
Links: Enumerated under Admin Web 1.10.13: Important Updates.
Impacted Services: Admin Web (@broadleaf/admin-components, @broadleaf/admin-style, @broadleaf/admin-tailwindcss)
Links: See the Admin Web 1.10.13: TenantService section for more information.
Impacted Services: Admin Web (@broadleaf/admin-components, @broadleaf/admin-style, @broadleaf/admin-tailwindcss)
Links: See the Admin Web 1.10.13: Bootstrap section for more information.
Impacted Services: Auth SDK (@broadleaf/auth-web)
Links: Please refer to Auth JS SDK 1.6.6
Impacted Services: Cart Operations and Catalog Services
Links: Please refer to
Impacted Services: Catalog and Catalog Browse Services
Links: Please refer to
Impacted Services: Order Services
Links: Please refer to Order Services 2.2.0
Impacted Services: Order Operations Services
Links: Please refer to Order Operation Services 2.2.0
Impacted Services: Catalog and Pricing Services
Links: Please refer to 2.3.0 Catalog Release Notes
Links: Please refer to 2.2.0 Pricing Release Notes
Impacted Services: Pricing Services
Links: Please refer to 2.2.0 Pricing Release Notes
Impacted Services: Pricing Services
Links: Please refer to 2.2.0 Pricing Release Notes
Impacted Services: Catalog and Catalog Browse Services
Links: Please refer to
Links: Please refer to TMForumExtensions 1.1.0 release notes for more information
Impacted Services: All services implementing caching
Required action: In 2.3.0+, Caffeine is the new default cache implementation.
Code and property changes are required to fully migrate from Ignite to Caffeine.
Please review the Switching to Caffeine documentation for more details
Both Caffeine and Ehcache leverage Apache Fury for serialization, and this requires explicitly configuring a whitelist of serializable classes. Ensure that package prefixes for your custom classes are included in this whitelist. For more details about this, please see Caching Serialization Configuration.
Alternatively, if immediately migrating to Caffeine is not possible, you can continue using the deprecated Ignite approach by explicitly setting com.broadleafcommerce.cache.activeCacheManagerImplementation=com.broadleafcommerce.common.extension.autoconfigure.IgniteCacheAutoConfiguration in your configuration properties.
Links: Please refer to Caching for more information.
ProductCharacteristic domain separationImpacted Services: Catalog Services
Links: Please refer to ProductCharacteristic domain separation release notes and ProductCharacteristic reindexing change notes for more details.
Impacted Services: Inventory Services, Notification Services, Pricing Services, Order Operation Services
Links: Please refer to
Impacted Services: Order Operation Services
Links: Please refer to Order Operation Services 2.2.0: Bug Fixes
|
Important
|
|
ThemeProvider and update existing CSS|
Tip
|
This provides Runtime Admin Theming Support. |
We introduced a robust, CSS-variable-based runtime theming engine for the Admin application. The foundation is highly extensible, memory-leak safe, and 100% backwards compatible for downstream apps that do not wish to utilize theming.
Dynamic Theming Engine: Introduced a new <ThemeProvider> that programmatically accepts a nested Theme object and dynamically injects scoped CSS variables (e.g., --tw-colors-primary-500) into the document :root.
AdminProvider Integration: Integrated the new <ThemeProvider> directly into <AdminProvider>, allowing the theme to be passed cleanly as a top-level prop without disturbing existing context setups.
Tailwind Plugin & Config Upgrades:
Updated @broadleaf/admin-tailwindcss to utilize safe CSS variable fallbacks across all branding colors, mapping gray to the secondary scale and red to the danger scale.
Added a new adminTheme Tailwind plugin to dynamically generate shell-specific styling utilities (tw-shell-nav- and tw-shell-header-).
Shell Chrome Migration: Surgically migrated legacy SCSS from structural components like <Navigation> and <Header> to leverage the new theme-aware Tailwind classes instead of hardcoded background colors.
SASS Color Function Removal: Removed legacy SASS functions (like lighten() or color-yiq()) from older components in @broadleaf/admin-style, allowing them to safely compile and consume the new dynamic CSS variable fallbacks seamlessly.
You can now theme the admin by supplying a theme prop to your <AdminProvider>:
import { AdminProvider, Theme } from '@broadleaf/admin-components';
const brandTheme: Theme = {
colors: {
primary: { /* 50-950 scale */ },
secondary: { /* 50-950 scale (defaults to Tailwind 'gray') */ },
danger: { /* 50-950 scale (defaults to Tailwind 'red') */ },
link: '#3b82f6',
linkHover: '#2563eb'
},
shell: {
nav: { bg: '#111827', text: '#d1d5db', active: '#1f2937' },
header: { bg: '#1f2937' }
}
};
const App = () => (
<AdminProvider theme={brandTheme}>
{/* Admin Routes */}
</AdminProvider>
);
We introduced a significant architectural cleanup to the <BaseLayout> component and its associated global elements.
The goal of this refactor is to improve component cohesion, enable granular overrides for downstream consumers, and future-proof the codebase for modern React paradigms like Server Components (RSC).
The <BaseLayout> component was previously cluttered with global context providers and structural modals.
These have been cleanly extracted:
* ToastContainerContextProvider: Extracted the toast state logic into its own dedicated context provider.
* ConfirmModalContextProvider: Extracted the confirmation modal state.
The actual <ConfirmModal /> element is now rendered natively inside this provider (after {children}) rather than hanging off the <BaseLayout>.
* Both of these new providers have been injected into the default array of the <GlobalProviders> component, ensuring they are available across all routes without cluttering the layout tree.
To provide maximum flexibility for downstream applications, the following global UI components have been wrapped in enableOverrides, allowing them to be swapped out completely:
* ConfirmModal
* ToastContainer
* TransitionToasts
* Toast
<ScrollView> (Tree-shaking & RSC Support)The <ScrollView> component was previously exposing its sub-components via dot-notation (e.g., ScrollView.Header).
This has been refactored to use named flat exports (ScrollViewHeader, ScrollViewContent, ScrollViewFooter).
* Why? Flat exports drastically improve tree-shaking by allowing bundlers to eliminate dead code.
Furthermore, in React Server Component (RSC) environments (like Next.js App Router), dot-notation forces the entire object tree to be treated as a Client Component.
Flat exports allow for granular server/client boundary definitions.
* Backwards Compatibility: The dot-notation accessors have been kept intact on the default export but are marked as @deprecated.
Removed AuthService dependency injection from <BaseLayout>.
The <Header> component now directly imports and handles its own logout and changePassword logic, resulting in a much dumber, cleaner layout wrapper.
The following properties/accessors have been marked as @deprecated and should be migrated to their new paradigms:
* ScrollView.Header → Use named import ScrollViewHeader
* ScrollView.Content → Use named import ScrollViewContent
* ScrollView.Footer → Use named import ScrollViewFooter
* HeaderProps.onLogoutClick → Handled internally by <Header>
* HeaderProps.onChangePasswordClick → Handled internally by <Header>
|
Important
|
Requires Admin Navigation Services 3.0.0, which is part of Release Train 3.0.0 but also compatible with Release Train 2.3.1 if upgrading independently. |
We introduced the ability for Menu Items defined in the Admin Navigation Service to be rendered independently of any Metadata Routes.
They can now be filtered by their own predicates in a similar fashion to Routes, e.g., only return this item in a Tenant context rather than an Application.
They can also define the security scopes for whether the user has access to see them similar to Routes, e.g., a user needs READ_PRODUCT to see this item.
Introduced VITE_MAIN_NAVIGATION_BEHAVIOR.
To trigger the new behavior set it to ROUTE_INDEPENDENT
Introduced new hook, useSecureNavMenuItem to check whether the user has access to a NavMenuItem either using the old behavior based on a matching route or the new behavior checking the scopes of the NavMenuItem directly
Added debug logging to help diagnose why menu items appear or don’t appear
Enable using VITE_
Fixed lack of typing and documentation for various pieces of the UserOperationContext and related reducers to address technical debt in this area.
Deprecated useGetMatchingRoutesWithAccess and useHasMatchingRoute.
Instead, useSecureNavMenuItem should be used as it returns both whether the module or submodule has access as well as the map of URL/path for each submodule to whether it has access specifically.
Removed access check in NavSection as the access checks for each section has already been done by the time the component is rendered.
Instead filtration of the submenu items is explicitly done before rendering any NavSections.
We decoupled the application routing logic from the structural UI shell.
Previously, AdminApp was tightly coupled to both the layout and the React Router definition, making it difficult for downstream consumers to inject custom routing or entirely replace the application shell.
AdminRoutesThe react-router-dom <Routes> definition and the metadata-driven route grouping logic have been extracted from AdminApp into a new, standalone <AdminRoutes> component.
* This component is purely responsible for consuming the ComponentRouterContext and dynamically rendering the ComponentRouteResolver for each path.
* New Injection Slots: <AdminRoutes> now accepts beforeRoutes and afterRoutes props (typed as ReactNode).
This allows downstream consumers to seamlessly inject custom static routes alongside the dynamically generated metadata routes without interfering with the 404 catch-all logic.
AdminApp (Slot Pattern)The <AdminApp> component has been refactored to fully support the slotted children pattern.
* If children are provided to <AdminApp>, it now acts strictly as a lifecycle/routing wrapper and renders the provided children directly.
This explicitly supports downstream architectures (such as Capibara) that need to inject and manage their own UI shell layout.
* Backwards Compatibility: If no children are provided, <AdminApp> gracefully falls back to the original Out-Of-The-Box (OOB) behavior, rendering <BaseLayout><AdminRoutes /></BaseLayout>.
Verified that the ComponentRouterContext population is strictly decoupled from the UI shell rendering.
The ComponentRouter gateway successfully blocks rendering via the GatewayProvider until all metadata routes are fetched and the context is fully hydrated.
This guarantees that any custom shell or route definition passed into the application will have immediate, synchronous access to the fully resolved routing state.
Optimize fulfillment inventory loading to reduce redundant requests due to component re-renders
Fixed an issue where an incorrect quantity value was used during fulfillment
Updated useFulfillmentInventory to replace the skuCodes parameter with fulfillments
Separated inventoryQuantities from StatusChangeContext into a new InventoryContext
Note: A withInventoryContext provider is available to allow existing components taking in an inventoryQuantities prop to continue working as previously
Moved internal logic of <ApplicationSelector> into a useApplicationSelector hook, encapsulating the state, fetch orchestration, authorization logic, and event callbacks for selecting the active application context.
This allows easier customization of the <ApplicationSelector> in the nav sidebar.
import useApplicationSelector from '@broadleaf/admin-components/dist/view/components/ApplicationSelector/hooks/useApplicationSelector';
export const CustomApplicationSelector = () => {
const {
application,
applications,
isLoading,
formattedMessages,
handleApplicationChange,
queueFetchApplications,
resolveApplicationsWithQuery
} = useApplicationSelector();
return <>{/* Custom Selector Component */}</>;
}
These components are rendered while resolving the Application and Metadata Routes or when those requests encounter an error. This covers the following:
App-Level Error and Loading Splash (AppSplash)
Registered as blAppSplash
Subcomponents that support overrides
blAppSplashOverlay for AppSplashOverlay
blAppSplashBackground for AppSplashBackground
blAppSplashLoading for AppSplashLoading
blAppSplashError for AppSplashError
blAppSplashErrorNotFound for AppSplashErrorNotFound
blAppSplashErrorUnauthorized for AppSplashErrorUnauthorized
blAppSplashErrorServer for AppSplashErrorServer
blAppSplashErrorUnknown for AppSplashErrorUnknown
blAppSplashErrorTemplate for AppSplashErrorTemplate
Route/Metadata-Level Error and Loading Splash (ComponentRouteSplash)
Registered as blComponentRouteSplash
Subcomponents that support overrides
blTransitionComponentRouteSplashOverlay for TransitionComponentRouteSplashOverlay
blComponentRouteSplashOverlay for ComponentRouteSplashOverlay
blComponentRouteSplashBackground for ComponentRouteSplashBackground
blComponentRouteSplashLoading for ComponentRouteSplashLoading
blComponentRouteSplashError for ComponentRouteSplashError
blComponentRouteSplashErrorNotFound for ComponentRouteSplashErrorNotFound
blComponentRouteSplashErrorUnauthorized for ComponentRouteSplashErrorUnauthorized
blComponentRouteSplashErrorServer for ComponentRouteSplashErrorServer
blComponentRouteSplashErrorUnknown for ComponentRouteSplashErrorUnknown
blComponentRouteSplashErrorTemplate for ComponentRouteSplashErrorTemplate
We refactored the monolithic <Navigation> component into a set of highly granular, composable layout building blocks backed by a centralized context provider.
These changes enable users to build entirely custom navigation shells, e.g., top-level headers, custom mobile sidebars, off-canvas menus, while preserving the exact out-of-the-box (OOB) Admin navigation layout and DOM structure.
Users can now leverage the NavigationContextProvider alongside individual <Nav*> layout components to compose entirely custom sidebar or header shell layouts without needing to manually lift state or drill props.
The default <Navigation> component continues to function identically without requiring downstream changes.
State Extraction: Extracted all data fetching logic, cache interactions, and UI state (menuOpen, menuCollapsed, isHovered, filter) from the main component into a new NavigationContextProvider.
Granular Layout Building Blocks: Created atomic <Nav*> wrappers for each semantic layout section (<NavWrapper>, <NavMain>, <NavHeader>, <NavMenuWrapper>, <NavErrorSection>, <NavFooter>).
Layout V2 Alignment: Removed legacy branching logic from the new navigation wrappers, standardizing entirely on Layout V2 semantic HTML tags (<nav>, <section>, <header>, <aside>, <footer>).
OOB Preservation: Rebuilt the default <Navigation> component as a strict composition of these new atomic layout wrappers to ensure no regressions in default styling or DOM behavior.
Expanded Exports: Exported all atomic navigation blocks, types, contexts, and hooks to the root index layer for downstream consumption.
All new wrappers are fully extensible via enableOverrides.
import {
NavWrapper,
NavMain,
NavErrorSection,
NavError,
NavMenu,
NavFooter,
NavCollapser,
NavMobileToggle,
NavigationContextProvider,
useNavigationContext
} from '@broadleaf/admin-components/dist/view';
export const CustomNavigation: React.FC = () => {
const {
isError,
isSuccess,
menuCollapsed,
menuOpen,
isHovered,
filter,
setFilter,
setMenuOpen,
setMenuCollapsed,
setIsHovered,
modules,
fetchNavigation
} = useNavigationContext();
return (
<NavigationContextProvider>
<NavWrapper>
<NavMain>
{isError && (
<NavErrorSection>
<NavError fetchNavigation={fetchNavigation} />
</NavErrorSection>
)}
{isSuccess && (
<NavMenu
filter={filter}
modules={modules}
setFilter={setFilter}
setMenuOpen={setMenuOpen}
menuCollapsed={menuCollapsed && !isHovered && !menuOpen}
/>
)}
</NavMain>
<NavFooter>
<NavCollapser
menuCollapsed={menuCollapsed}
setMenuCollapsed={val => {
setMenuCollapsed(val);
setMenuOpen(!val);
setIsHovered(false);
}}
/>
</NavFooter>
</NavWrapper>
<NavMobileToggle
menuOpen={menuOpen}
setMenuOpen={val => {
setMenuOpen(val);
setMenuCollapsed(!val);
}}
/>
</NavigationContextProvider>
);
};
|
Important
|
Requires Metadata 2.0.9-GA (Release Trains 2.3.1, 2.2.3, 2.1.7) or 3.0.0-GA (Release Train 3.0.0). |
Introduces support for a "One-Time Success Response" feature, providing a highly integrated framework for safely displaying sensitive, transient API response payloads (such as generated API keys) natively within the Admin UI.
This feature looks for successResponse handler configurations on metadata actions.
Upon successful form submission, it dynamically hooks-into the onSubmit promise resolution to present the read-only payload values in a slide-over modal or inline-replacement view before the transient state is discarded.
It also includes setting a string field as "copyable" that triggers a "copy" action to render with the field and makes the field read-only.
While the successResponse handler can be configured for any action, a helper is included for Entity Create and Update views: submitSuccessResponse.
This passes the configuration function down to the appropriate submit action in the metadata.
submitSuccessResponseViews.entityViewCreate()
.submitSuccessResponse(response -> response
.title("Key Generated Successfully")
.message("Copy this secure key now. It will not be shown again.")
.displayMode(SuccessResponse.DisplayMode.REPLACE_CONTENT)
// Renders the API response's 'secret' property as a click-to-copy string field
.addField("secret", Fields.string()
.copyable()
.label("API Key")));
Added an error boundary in LocalStorageCache to gracefully handle failures to persist the in memory cache to local storage.
Modified the in-memory cache used by LocalStorageCache to act as an LRU map with additional byte-size-based eviction that can be set with LocalStorageCache#maxByteSize.
Introduce environment properties to fine-tune the behavior of different LocalStorageCache instances across the application.
This enables configuring time-to-live (TTL), maximum byte size limits, and local/session storage enablement dynamically.
The following configuration properties have been introduced (formatted as VITE_ prefixed, uppercase, snake_case dotenv variables) with their respective default values:
Authentication Cache:
VITE_AUTH_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_AUTH_CACHE_TTL: Default: 600000, 10 minutes
VITE_AUTH_CACHE_LOCAL_ENABLE: Default: true
VITE_AUTH_CACHE_SESSION_ENABLE: Default: true
Authentication State Cache:
VITE_AUTH_STATE_CACHE_MAX_BYTE_SIZE: Default: 0, not restricted as it is not persisted to local or session storage
VITE_AUTH_STATE_CACHE_TTL: Default: 0, no TTL
Authentication Transaction Storage:
VITE_AUTH_TRANSACTION_STORAGE_MAX_BYTE_SIZE: Default: 0, not restricted as it is not persisted to local or session storage
VITE_AUTH_TRANSACTION_STORAGE_TTL: Default: 0, no TTL
Metadata/Component Router Cache:
VITE_METADATA_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_METADATA_CACHE_TTL: Default: 1800000, 30 minutes
VITE_METADATA_CACHE_LOCAL_ENABLE: Default: true
VITE_METADATA_CACHE_SESSION_ENABLE: Default: true
Catalog Cache:
VITE_CATALOG_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_CATALOG_CACHE_TTL: Default: 600000, 10 minutes
VITE_CATALOG_CACHE_LOCAL_ENABLE: Default: true
VITE_CATALOG_CACHE_SESSION_ENABLE: Default: true
Customer Context Cache:
VITE_CUSTOMERCONTEXT_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_CUSTOMERCONTEXT_CACHE_TTL: Default: 600000, 10 minutes
VITE_CUSTOMERCONTEXT_CACHE_LOCAL_ENABLE: Default: true
VITE_CUSTOMERCONTEXT_CACHE_SESSION_ENABLE: Default: true
Sandbox Cache:
VITE_SANDBOX_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_SANDBOX_CACHE_TTL: Default: 600000, 10 minutes
VITE_SANDBOX_CACHE_LOCAL_ENABLE: Default: true
VITE_SANDBOX_CACHE_SESSION_ENABLE: Default: true
Search Settings Cache:
VITE_SEARCHSETTINGS_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_SEARCHSETTINGS_CACHE_TTL: Default: 600000, 10 minutes
VITE_SEARCHSETTINGS_CACHE_LOCAL_ENABLE: Default: true
VITE_SEARCHSETTINGS_CACHE_SESSION_ENABLE: Default: true
Tenant Cache:
VITE_TENANT_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_TENANT_CACHE_TTL: Default: 600000, 10 minutes
VITE_TENANT_CACHE_LOCAL_ENABLE: Default: true
VITE_TENANT_CACHE_SESSION_ENABLE: Default: true
Introduced a dedicated new component specifically designed to handle the toggle states of Placeholder Characteristics, registered as PLACEHOLDER_ENUM.
Added support to ActionListGridCreateAction to configure the modal max size with the modalSize attribute.
Supported values:
sm: 32rem (512 pixels)
lg: 48rem (768 pixels)
xl: 72rem (1152 pixels)
Refactored the ToggleSwitch component for improved keyboard accessibility and WAI-ARIA compliance
Addressed:
Limited Keyboard Shortcuts: Previously, keyboard support was restricted to a simple spacebar toggle which acted as a circular index cycler. This made navigating back and forth through multiple choices laborious and did not meet standard accessibility expectations.
Double Screen-Reader Announcements: Because both the underlying input element and the visible label/button were interactive and present in the DOM tree, screen readers frequently exposed redundant or competing focused states.
Improper Aria Roles: The selection element lacked programmatic group context and checked-state markers, making color changes the only indicator of active options.
Updated EntityView useContextParams to take the React Router match param into account to share the behavior used by EntityLongView to determine which form within the view is active.
Added support for using EntityViews as targets of slide-over form actions (as opposed to modal forms) like ActionListGridUpdateViewAction that can target an existing View to render when invoked.
Added support for overriding some subcomponents of ListGrids
blListGridHeaders for ListGridHeaders
blActionListGridQueryFilter for ActionListGridQueryFilter
Ensured that empty EntityView form tabs are hidden automatically
Fixed Admin Forms Initializing with Unsaved Changes
Fixed the ApplicationSelector disappearing when filtering by a query with no matching results
Fixed Workflow view not showing error page for invalid workflows (e.g., navigating to a URL for a workflow that doesn’t exist).
Fixed possibility of QuotaExceededError for CustomerContextCache used by the Customer Context Selector component in the Tenant-level admin.
Only cache the IDs and Names of Applications stored as these are the only ones relevant for admin functionality
Fixed Customize Form actions not opening modals to add Field or Group Augmentations when clicking on the button icon rather than the button background. Now clicking on either will open the modal.
Fixed management of placeholder enum characteristics to handle and send valid API request/response payloads.
Created a PlaceholderEnumField component (and corresponding internationalized messages) specifically designed to manage placeholder enum characteristics.
This avoids polluting the general-purpose select elements with complex active/inactive toggling logic.
Updated the conditional resolver in Field.tsx to automatically route characteristic placeholders to this new field type.
Fixed runtime TypeError, metadata?.actions?.find is not a function, that occurs in the EntityLongView component for auditable entities (set in metadata with .auditable("ENTITY_TYPE").
Logic now ensures that standard metadata actions collections always maintain a strict Array structure, preventing downstream components and hooks from crashing on native array method calls.
Fixed regression in 2.0.2: Added missing CSS styles resulting from removal of Bootstrap dependency.
|
Important
|
|
Introduced a dedicated new component specifically designed to handle the toggle states of Placeholder Characteristics, registered as PLACEHOLDER_ENUM.
Added an error boundary in LocalStorageCache to gracefully handle failures to persist the in memory cache to local storage.
Modified the in-memory cache used by LocalStorageCache to act as an LRU map with additional byte-size-based eviction that can be set with LocalStorageCache#maxByteSize.
Introduce environment properties to fine-tune the behavior of different LocalStorageCache instances across the application.
This enables configuring time-to-live (TTL), maximum byte size limits, and local/session storage enablement dynamically.
The following configuration properties have been introduced (formatted as VITE_ prefixed, uppercase, snake_case dotenv variables) with their respective default values:
Authentication Cache:
VITE_AUTH_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_AUTH_CACHE_TTL: Default: 600000, 10 minutes
VITE_AUTH_CACHE_LOCAL_ENABLE: Default: true
VITE_AUTH_CACHE_SESSION_ENABLE: Default: true
Authentication State Cache:
VITE_AUTH_STATE_CACHE_MAX_BYTE_SIZE: Default: 0, not restricted as it is not persisted to local or session storage
VITE_AUTH_STATE_CACHE_TTL: Default: 0, no TTL
Authentication Transaction Storage:
VITE_AUTH_TRANSACTION_STORAGE_MAX_BYTE_SIZE: Default: 0, not restricted as it is not persisted to local or session storage
VITE_AUTH_TRANSACTION_STORAGE_TTL: Default: 0, no TTL
Metadata/Component Router Cache:
VITE_METADATA_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_METADATA_CACHE_TTL: Default: 1800000, 30 minutes
VITE_METADATA_CACHE_LOCAL_ENABLE: Default: true
VITE_METADATA_CACHE_SESSION_ENABLE: Default: true
Catalog Cache:
VITE_CATALOG_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_CATALOG_CACHE_TTL: Default: 600000, 10 minutes
VITE_CATALOG_CACHE_LOCAL_ENABLE: Default: true
VITE_CATALOG_CACHE_SESSION_ENABLE: Default: true
Customer Context Cache:
VITE_CUSTOMERCONTEXT_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_CUSTOMERCONTEXT_CACHE_TTL: Default: 600000, 10 minutes
VITE_CUSTOMERCONTEXT_CACHE_LOCAL_ENABLE: Default: true
VITE_CUSTOMERCONTEXT_CACHE_SESSION_ENABLE: Default: true
Sandbox Cache:
VITE_SANDBOX_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_SANDBOX_CACHE_TTL: Default: 600000, 10 minutes
VITE_SANDBOX_CACHE_LOCAL_ENABLE: Default: true
VITE_SANDBOX_CACHE_SESSION_ENABLE: Default: true
Search Settings Cache:
VITE_SEARCHSETTINGS_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_SEARCHSETTINGS_CACHE_TTL: Default: 600000, 10 minutes
VITE_SEARCHSETTINGS_CACHE_LOCAL_ENABLE: Default: true
VITE_SEARCHSETTINGS_CACHE_SESSION_ENABLE: Default: true
Tenant Cache:
VITE_TENANT_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_TENANT_CACHE_TTL: Default: 600000, 10 minutes
VITE_TENANT_CACHE_LOCAL_ENABLE: Default: true
VITE_TENANT_CACHE_SESSION_ENABLE: Default: true
Fixed Admin Forms Initializing with Unsaved Changes
Fixed the ApplicationSelector disappearing when filtering by a query with no matching results
Fixed Workflow view not showing error page for invalid workflows (e.g., navigating to a URL for a workflow that doesn’t exist).
Fixed possibility of QuotaExceededError for CustomerContextCache used by the Customer Context Selector component in the Tenant-level admin.
Only cache the IDs and Names of Applications stored as these are the only ones relevant for admin functionality
Fixed Customize Form actions not opening modals to add Field or Group Augmentations when clicking on the button icon rather than the button background. Now clicking on either will open the modal.
Fixed management of placeholder enum characteristics to handle and send valid API request/response payloads.
Created a PlaceholderEnumField component (and corresponding internationalized messages) specifically designed to manage placeholder enum characteristics.
This avoids polluting the general-purpose select elements with complex active/inactive toggling logic.
Updated the conditional resolver in Field.tsx to automatically route characteristic placeholders to this new field type.
Fixed runtime TypeError, metadata?.actions?.find is not a function, that occurs in the EntityLongView component for auditable entities (set in metadata with .auditable("ENTITY_TYPE").
Logic now ensures that standard metadata actions collections always maintain a strict Array structure, preventing downstream components and hooks from crashing on native array method calls.
Fixed regression in 2.0.2: Added missing CSS styles resulting from removal of Bootstrap dependency.
|
Tip
|
|
Added an error boundary in LocalStorageCache to gracefully handle failures to persist the in memory cache to local storage.
Modified the in-memory cache used by LocalStorageCache to act as an LRU map with additional byte-size-based eviction that can be set with LocalStorageCache#maxByteSize.
Introduce environment properties to fine-tune the behavior of different LocalStorageCache instances across the application.
This enables configuring time-to-live (TTL), maximum byte size limits, and local/session storage enablement dynamically.
The following configuration properties have been introduced (formatted as VITE_ prefixed, uppercase, snake_case dotenv variables) with their respective default values:
Authentication Cache:
VITE_AUTH_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_AUTH_CACHE_TTL: Default: 600000, 10 minutes
VITE_AUTH_CACHE_LOCAL_ENABLE: Default: true
VITE_AUTH_CACHE_SESSION_ENABLE: Default: true
Authentication State Cache:
VITE_AUTH_STATE_CACHE_MAX_BYTE_SIZE: Default: 0, not restricted as it is not persisted to local or session storage
VITE_AUTH_STATE_CACHE_TTL: Default: 0, no TTL
Authentication Transaction Storage:
VITE_AUTH_TRANSACTION_STORAGE_MAX_BYTE_SIZE: Default: 0, not restricted as it is not persisted to local or session storage
VITE_AUTH_TRANSACTION_STORAGE_TTL: Default: 0, no TTL
Metadata/Component Router Cache:
VITE_METADATA_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_METADATA_CACHE_TTL: Default: 1800000, 30 minutes
VITE_METADATA_CACHE_LOCAL_ENABLE: Default: true
VITE_METADATA_CACHE_SESSION_ENABLE: Default: true
Catalog Cache:
VITE_CATALOG_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_CATALOG_CACHE_TTL: Default: 600000, 10 minutes
VITE_CATALOG_CACHE_LOCAL_ENABLE: Default: true
VITE_CATALOG_CACHE_SESSION_ENABLE: Default: true
Customer Context Cache:
VITE_CUSTOMERCONTEXT_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_CUSTOMERCONTEXT_CACHE_TTL: Default: 600000, 10 minutes
VITE_CUSTOMERCONTEXT_CACHE_LOCAL_ENABLE: Default: true
VITE_CUSTOMERCONTEXT_CACHE_SESSION_ENABLE: Default: true
Sandbox Cache:
VITE_SANDBOX_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_SANDBOX_CACHE_TTL: Default: 600000, 10 minutes
VITE_SANDBOX_CACHE_LOCAL_ENABLE: Default: true
VITE_SANDBOX_CACHE_SESSION_ENABLE: Default: true
Search Settings Cache:
VITE_SEARCHSETTINGS_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_SEARCHSETTINGS_CACHE_TTL: Default: 600000, 10 minutes
VITE_SEARCHSETTINGS_CACHE_LOCAL_ENABLE: Default: true
VITE_SEARCHSETTINGS_CACHE_SESSION_ENABLE: Default: true
Tenant Cache:
VITE_TENANT_CACHE_MAX_BYTE_SIZE: Default: 1048576, 1MB
VITE_TENANT_CACHE_TTL: Default: 600000, 10 minutes
VITE_TENANT_CACHE_LOCAL_ENABLE: Default: true
VITE_TENANT_CACHE_SESSION_ENABLE: Default: true
Fixed Admin Forms Initializing with Unsaved Changes
Fixed the ApplicationSelector disappearing when filtering by a query with no matching results
Fixed Workflow view not showing error page for invalid workflows (e.g., navigating to a URL for a workflow that doesn’t exist).
Fixed possibility of QuotaExceededError for CustomerContextCache used by the Customer Context Selector component in the Tenant-level admin.
Only cache the IDs and Names of Applications stored as these are the only ones relevant for admin functionality
|
Important
|
Compatibility Warning: If your frontend application is updated to use this version of the SDK but your backend |
|
Tip
|
This release is otherwise compatible with Release Trains starting in the 1.8.x line. |
The frontend Auth Web SDK (@broadleaf/auth-web) now supports automatic token revocation during logout or session clearing.
Automatic Revocation: Before the token cache is cleared, the SDK will automatically iterate over the cached tokens, detect if a refresh token is present, and make a request to the /oauth2/revoke endpoint in AuthenticationServices to revoke it.
Compatibility Gating Property: To maintain backward compatibility with older versions of AuthenticationServices that do not support public clients calling the token revocation endpoint, this feature can be explicitly disabled.
Toggle Option: A new boolean option enableTokenRevocation has been added to AuthClientOptions which defaults to true. If your frontend application is updated to use the new SDK but your AuthenticationServices backend is on an older version that does not support public clients calling /oauth2/revoke, you should set enableTokenRevocation: false when instantiating the AuthClient.
To support the lookup and revocation of refresh tokens in the cache, the TokenCache interface now exposes a getEntries method:
Added getEntries?(): TokenCacheEntry[] to the TokenCache interface.
Implemented getEntries(): TokenCacheEntry[] in both InMemoryTokenCache and WebStorageTokenCache implementations.
|
Tip
|
This release is compatible with Release Trains starting in the 2.1.x line. |
Support has been introduced to query both paymentRequired and savedPaymentMethodRequired indicators, along with gathering details about available payment method options, in a single aggregate backend request (under the /checkout/payment-expectations endpoint). This simplifies checkout step transitions and payment status evaluation in storefront integrations.
|
Tip
|
This release is compatible with Release Trains starting in the 2.1.x line. |
|
Important
|
Minimum React version upgraded to React 18. Minimum Node version upgraded to Node 18. |
|
Tip
|
This release is compatible with Release Trains starting in the 2.2.x line. |
|
Important
|
Minimum React version upgraded to React 18. Minimum Node version upgraded to Node 18. |
|
Tip
|
This release is compatible with Release Trains starting in the 2.2.x line. |
|
Important
|
Minimum React version upgraded to React 18. Minimum Node version upgraded to Node 18. |
|
Tip
|
This release is compatible with Release Trains starting in the 2.1.x line. |
|
Caution
|
This is the final planned release of the 1.3.x line. |
|
Tip
|
This release is compatible with Release Trains starting in the 2.0.x line. |
|
Note
|
Docker URL: |
|
Important
|
Dropped Node 20 support |
Upgraded the Checkout.com frontend implementation to use Flow instead of Frames.
See full details in our 2.1.0 Checkout.com payment library release notes.
Upgraded the PayPal SDK from v5 to v6.
This upgrade is based on PayPal’s Checkout JavaScript SDK v6 upgrade guide. See our Frontend Integration documentation for an example with the latest.
See paypal-checkout-js and paypal-checkout-react documentation for our SDK changes.
Upgraded Adyen payment implementation to version 6
Upgraded Stripe to use StripeClient to call Stripe APIs
Fixed an issue in which the anonymous endpoint was used to read historical carts for an authorized customer, causing an error.
Updated the configuration property names for the CSP to fix content loading.
Fixed loading issues with Stripe scripts
Fixed context issues when using @broadleaf/commerce-quote-react
Ignore 404 errors when the customer’s cart hasn’t been created yet
Improved the guest cart transfer page loading transition
Fixed cart state being lost when rejecting a quote request
Fixed resolution of findDOMNode and 409 cart version conflict errors during checkout
Fixed default locale not having a default value and being applied inconsistently in the LocaleContext
|
Note
|
Docker URL: |
Fixed an issue in which the anonymous endpoint was used to read historical carts for an authorized customer, causing an error.
Updated the configuration property names for the CSP to fix content loading.
Fixed loading issues with Stripe scripts
Fixed context issues when using @broadleaf/commerce-quote-react
Ignore 404 errors when the customer’s cart hasn’t been created yet
Improved the guest cart transfer page loading transition
Fixed cart state being lost when rejecting a quote request
Fixed resolution of findDOMNode and 409 cart version conflict errors during checkout
Fixed default locale not having a default value and being applied inconsistently in the LocaleContext
|
Caution
|
This is the final planned release for the 1.6.x line of starters. |
|
Note
|
Docker URL: |
|
Tip
|
Security and maintenance release. Includes all changes for 1.6.10. |
|
Note
|
Docker URL: |
|
Tip
|
Security and maintenance release. Includes all changes for 1.1.3. |
Upgraded to Next 16 and React 19
Dropped support for Node 18
Verified support for Node 22 and 24
Pass product when fetching additional pricing targets
Made a PDP specific to products with recurring pricing
Handles a new display template name, BLC_SUBSCRIPTION, meant to handle demo subscription products (Office 365 and VPNs)
The DefaultRecurringPricingPdp is the exact same copy of DefaultPdp except that DefaultPdp now does NOT use the AdditionalPricingOptions while DefaultRecurringPricingPdp does
This is to prevent /price-targets requests from being called unnecessarily on the DefaultPdp
Products using the PAY_AS_YOU_GO_PHONE template will use the DefaultPdp as they do not have recurring pricing.
Added Fee total to Cart Summary and list fees underneath
Added generic recurring pricing template and logic to reprice a cart before submitting checkout for virtual or non-shipping fulfillment groups
Added condition for GENERIC_RECURRING_PRICING display template
Reprice cart right before checkout for nonShippingFulfillment
Since they need the BillingAddress to calculate taxes and everything
Now reprices the cart right before checkout for fulfillments that have DefaultFulfillmentType of VIRTUAL or NONE. This is done so that taxes and other pricing mechanisms can be run after the BillingAddress has been populated.taxes and everything
=== Payment Offers Support
Add a useAddAttributeToCart hook to facilitate requests to cartClient#addAttributeToCart.
Add a useRemoveAttributeFromCart hook to facilitate requests to cartClient#removeAttributeFromCart.
The Passthrough Payment Form now uses the useAddAttributeToCart hook to update the PAYMENTS_LIST when a new payment is submitted or removed.
The AddAttributeRequest contains invalidatePricing: true, so that the cart will be repriced once the attribute has been updated.
The PAYMENTS_LIST attribute is used by the backend to apply offers based on the type of payment. For more details visit the Cart Operation Service release notes.
Fixed issues with telco product initial pricing and products with recurring prices added to cart
Use frequency when adding to cart, fix term messaging to allow 1-year terms
Update to pass frequency when adding to cart with additional pricing options
Add logic to reset Product PriceInfo to basePrice before fetching additional pricing options
The product at this point is already priced, but we don’t want the already-determined bestPrice to be used as basePrice when pricing these additional targets
Make sure to pass frequency for dependent items
Fixed an issue in which the anonymous endpoint was used to read historical carts for an authorized customer, causing an error.
Improved the guest cart transfer page loading transition
Fixed default locale not having a default value and being applied inconsistently in the LocaleContext
|
Caution
|
This is the final planned release in the 1.0.x line of the Telco starter |
|
Note
|
Docker URL: |
|
Tip
|
Security and maintenance release. Includes all changes for 1.0.5. |
Upgraded to Next 16 and React 19
Dropped support for Node 18
Verified support for Node 22 and 24
Pass product when fetching additional pricing targets
Made a PDP specific to products with recurring pricing
Handles a new display template name, BLC_SUBSCRIPTION, meant to handle demo subscription products (Office 365 and VPNs)
The DefaultRecurringPricingPdp is the exact same copy of DefaultPdp except that DefaultPdp now does NOT use the AdditionalPricingOptions while DefaultRecurringPricingPdp does
This is to prevent /price-targets requests from being called unnecessarily on the DefaultPdp
Products using the PAY_AS_YOU_GO_PHONE template will use the DefaultPdp as they do not have recurring pricing.
Added Fee total to Cart Summary and list fees underneath
Added generic recurring pricing template and logic to reprice a cart before submitting checkout for virtual or non-shipping fulfillment groups
Added condition for GENERIC_RECURRING_PRICING display template
Reprice cart right before checkout for nonShippingFulfillment
Since they need the BillingAddress to calculate taxes and everything
Now reprices the cart right before checkout for fulfillments that have DefaultFulfillmentType of VIRTUAL or NONE. This is done so that taxes and other pricing mechanisms can be run after the BillingAddress has been populated.taxes and everything
=== Payment Offers Support
Add a useAddAttributeToCart hook to facilitate requests to cartClient#addAttributeToCart.
Add a useRemoveAttributeFromCart hook to facilitate requests to cartClient#removeAttributeFromCart.
The Passthrough Payment Form now uses the useAddAttributeToCart hook to update the PAYMENTS_LIST when a new payment is submitted or removed.
The AddAttributeRequest contains invalidatePricing: true, so that the cart will be repriced once the attribute has been updated.
The PAYMENTS_LIST attribute is used by the backend to apply offers based on the type of payment. For more details visit the Cart Operation Service release notes.
Fixed issues with telco product initial pricing and products with recurring prices added to cart
Use frequency when adding to cart, fix term messaging to allow 1-year terms
Update to pass frequency when adding to cart with additional pricing options
Add logic to reset Product PriceInfo to basePrice before fetching additional pricing options
The product at this point is already priced, but we don’t want the already-determined bestPrice to be used as basePrice when pricing these additional targets
Make sure to pass frequency for dependent items
|
Tip
|
The 2.x versions are Spring Boot 3 compatible. |
Added @ConditionalOnMissingBean annotations to several auto-configured beans in AuthI18nAutoConfiguration and AuthServiceTemplateAutoConfiguration to support easier customization and overriding in client implementations:
Internationalization & Mapping:
authMessageSourcePostProcessor
authTranslationPostMapperMember
Thymeleaf & OAuth2 Template Engine / Resolvers:
oAuth2ClientIdTemplateEngine
viewResolverPostProcessor (updated to return the concrete ViewResolverPostProcessor type, which has been made public)
oAuth2DefaultTemplateResolver
broadleafTemplateResolver
broadleafOAuth2DefaultTemplateResolver
The OAuth2 Token Revocation Endpoint is now accessible to public clients. Please review OAuth2 Token Revocation endpoint documentation for more details.
Introduced a new PublicClientTokenRevocationAuthenticationConverter that specifically targets the token revocation endpoint and establishes a PublicClientTokenRevocationAuthenticationToken authentication
Updated PublicRefreshPublicClientAuthenticationProvider to handle PublicClientTokenRevocationAuthenticationToken
Add the IMPERSONATE security scope and its root permission-scope mapping to the required starter data.
This is the Authentication Services half of the admin change that hides the View Quote Details action from users who lack impersonation permissions — without the scope in place, the action is hidden from every user because there is nothing for the permission to map to.
The changesets are guarded by preconditions and will not insert rows that already exist, so a deployment that added the scope by hand needs no further action.
Fixed an issue within the paging implementation of the CategoryModifiedEventListener, SingleProductIndexedEventListener, and InitializeBulkOperationItemsListener.
Previously, the Pageable request was stuck at page 0 during bulk operations parsing product memberships and auto-included categories, resulting in an infinite loop when the number of items exceeded the initial batch size. The pageable objects are now correctly advanced (e.g., searchPageable = searchPageable.next()) to appropriately traverse search results and auto-included categories. New comprehensive test suites were also added to validate correct paging behaviors.
|
Tip
|
The 2.x versions are Spring Boot 3 compatible. |
Introduced new version of CartEndpoint#readHistoricalCartForAnonymousCustomer that returns only anonymous carts.
GET /api/cart/carts?emailAddress=<value>&orderNumber=<value>&historical=true
Deprecated older version that returned mixed carts
Include Accept-Version=2 as a header to use the new endpoint if calling in custom code, or set broadleaf.cartoperation.cartprovider.readHistoricalCartForAnonymousCustomerEndpointVersion=2 in Cart Operations Service to use the new endpoint.
Introduced new endpoint to read historical carts by Order Number only for both anonymous and registered users.
GET /api/cart/carts?orderNumber=<value>
Additional ownership filtering should be performed by the caller and is automatically performed in Cart Operations Service in the following versions:
2.1.6 (RT 2.1.7)
2.2.3 (RT 2.2.3)
2.3.1 (RT 2.3.1)
Previously, the View Quote Details action on the Quote list grid in the Admin would appear even if the user did not have impersonation permissions despite those being required for the action to succeed.
To address this, the IMPERSONATE scope has been added to the View Quote Details action to ensure it is hidden for users that lack it so they avoid encountering the error and having to spend time debugging.
This requires also including the following changes in the Auth Service schema to add a missing security scope and permission-scope mapping for impersonation:
-- Add scope
INSERT INTO blc_security_scope (id, name, open) VALUES ('IMPERSONATE', 'IMPERSONATE', 'N');
-- Map to the root permission
INSERT INTO blc_permission_scope (id, permission, is_permission_root, scope_id) VALUES ('IMPERSONATE', 'IMPERSONATE', 'Y', 'IMPERSONATE');
|
Tip
|
If for any reason, you need to disable this change, set the following
|
|
Tip
|
The 2.x versions are Spring Boot 3 compatible. |
Added configuration properties to allow users to disable the anonymous history endpoints in Cart Ops altogether if not in use. Cart Ops was chosen for this as it will short-circuit the requests at the earliest point to improve performance. This is granular in case some endpoints are in use but not all. Additionally, users may have added their own custom endpoints in Cart Ops that use the same endpoints in Cart, making Cart Ops the most straightforward placement for this configuration.
To disable each:
broadleaf:
cartoperation:
endpoint:
cart-history:
read-anonymous-customer-cart-enabled: false
read-cart-by-order-number-for-anonymous-customer-enabled: false
read-cart-by-order-number-for-anonymous-customer-hydrate-payments-enabled: false
Added CartProvider#retrieveHistoricalCartByOrderNumber for looking up both registered and anonymous historical carts by Order Number only.
Additional ownership checks are handled in CartHistoryService to allow a more streamlined experience.
Added property to control whether CartProvider#retrieveHistoricalCartForAnonymousCustomer can retrieve only anonymous user carts or both registered and anonymous historical carts by email address and order number.
Previously the method returned both despite the name implying only anonymous carts being returned.
Recommended: Restrict it to only retrieve anonymous carts by setting the following property: broadleaf.cartoperation.cartprovider.readHistoricalCartForAnonymousCustomerEndpointVersion=2
All cart retrieval logic in CartHistoryEndpoint methods has been moved to methods in CartHistoryService to better consolidate business logic.
CartHistoryService centralizes handling of user access checks for retrieved all historical carts.
This enhances the capabilities of the endpoints so that Account Carts can be retrieved by either the owner or an Account Admin/Approver to streamline the behavior on the order confirmation page.
Add CartOperationService#removeOfferAndCampaignCodesFromCart(Cart, List, boolean, Map, ContextInfo), which accepts the payment lock tokens held by the calling flow.
The checkout offer validation activity now passes its lock tokens through when it strips invalid offer codes, so the reprice that follows can act on payments the flow already holds locks for instead of failing to acquire them.
Fix an issue where transferring an anonymous cart to a customer returned an error if the cart had already been transferred. The cart is now returned unchanged, so a repeated transfer request is harmless.
Fix an issue where the stale cart pricing checkout validation ignored its own configuration.
broadleaf.cartoperation.checkout.activity.validation.cart-stale-pricing.should-reject-lower-price and broadleaf.cartoperation.checkout.activity.validation.cart-stale-pricing.use-real-time-cart-pricing could not be bound, so both behaved as if left at their defaults regardless of what was configured.
The fluent accessors shouldRejectLowerPrice() and useRealTimeCartPricing() are deprecated for removal.
Use isShouldRejectLowerPrice()/setShouldRejectLowerPrice(boolean) and isUseRealTimeCartPricing()/setUseRealTimeCartPricing(boolean) instead.
Fix a NullPointerException raised while pricing a cart when a merchandising product resolved to a price with no recurring price.
Fixed an issue where an invalid offer would cause validation to fail during checkout
Fixed properties not binding in CartStalePricingValidationActivityProperties because the field were not utilizing any configured property values due to a @Fluent annotation preventing correct binding.
Fixed an NPE caused by Merchandising Products not having a recurring price field.
|
Tip
|
The 2.x versions are Spring Boot 3 compatible. |
Fixed various bugs with placeholder characteristics
Fixed a bug where CharacteristicValidator was not allowing empty values for placeholder characteristics
Removed the synchronizePlaceholderCharacteristics method and a variety of related specialized behavior for placeholder characteristics from DefaultProductHydrationService.
Fix property paths for ProductCharacteristic validations to ensure we are always targeting valid paths instead of relying on auto-grow-nested path behavior from Spring
Originally this behavior was intended to work around limitations of the admin frontend application, but had the consequence of corrupting certain fields.
The admin frontend has been updated to properly interpret and send placeholder characteristic values, so the incorrect backend workarounds have been removed.
Fixed a bug where Characteristic.id was using @JsonView(ResponseView.class), preventing the Characteristic ID from coming through on Product update calls even in a nested context.
As part of this, the characteristic update endpoint now sets the id on the submitted body from the path variable, so the path is always authoritative for which characteristic is updated.
Fixed a bug where policy validation would reject product update attempts if the API caller only had the UPDATE_PRODUCT permission, but a new product characteristic was being created as part of that request
Fixed a bug where inactive and date-expired catalog records were skipped by processes that do not run in a storefront request. The active-flag and active-date filters are now disabled when handling catalog entity deletion events, when running product bulk updates, and when reading variants for variant-based product type validation, so each of those processes sees every record it is meant to act on. Previously an inactive product could survive a deletion event and an inactive variant could be missed by product type validation.
Fixed the property paths reported in product validation errors for product characteristics.
Errors were previously reported against nested paths such as characteristics['<key>'].characteristic and characteristics['<key>'].value[0], which relied on Spring’s auto-grow-nested-path behavior and could fail to resolve.
Reference errors and cardinality errors are now reported against characteristics['<key>'], and cardinality errors on business-type characteristics against characteristics.
Clients that map validation messages to form fields using the field value in the error response need to be updated to the new paths.
This release contains security fixes. For detailed information regarding this security item, please refer to the Broadleaf Security Advisory. You will need your login credentials originally provided for accessing the Broadleaf nexus.
Introduced support for initializing tracking/persistence notification states based on their suppressed state within the active SuppressNotificationContext
Updated trackable domain mapper member supports (DefaultTrackableDomainMapperMemberSupport and JpaTrackableDomainMapperMemberSupport) to check if the specific notification type is suppressed before mapping trackable entities
When executing inside a suppressed context, the stopped field of the corresponding trackable domain NotificationState (userState for ChangeSummaryProducer#TYPE and persistenceState for PersistenceProducer#TYPE) is initialized to true dynamically
Updated NotificationStateInitializingDomainMapperMember to dynamically resolve and set the stopped property based on the suppressed context check of SuppressNotificationContext.isSuppressed(state.getName())
Fix an issue where ContextInfo#filterByActiveFlag was lost when a ContextInfo was copied, and where restoring the flag after an active-flag-filtered operation wrote to filterByActiveDates instead. Queries run after such an operation could filter on the wrong flag.
Updated DefaultProjectionFactory to assign an explicit parent package to AutoProjection classes
Some versions of Apache Fury (now Fory), used for serialization/deserialization in Caffeine and EHCache caching implementations, are susceptible to an internal race condition when dealing with unnamed-package classes.
This can result in corrupted output, and cause failures (such as NullPointerException) during cacheable operations.
By ensuring AutoProjection classes have an explicit package, Broadleaf reduces exposure to this edge case.
As of Broadleaf Release Train 2.3.0-GA, support for Spring Boot 3.3 & 3.5 for all common libraries has been added.
|
Important
|
Requires AdminWeb 2.1.0. |
Introduces support for a "One-Time Success Response" feature, providing a highly integrated framework for safely displaying sensitive, transient API response payloads (such as generated API keys) natively within the Admin UI.
This feature looks for successResponse handler configurations on metadata actions.
Upon successful form submission, it dynamically hooks-into the onSubmit promise resolution to present the read-only payload values in a slide-over modal or inline-replacement view before the transient state is discarded.
It also includes setting a string field as "copyable" that triggers a "copy" action to render with the field and makes the field read-only.
While the successResponse handler can be configured for any action, a helper is included for Entity Create and Update views: submitSuccessResponse.
This passes the configuration function down to the appropriate submit action in the metadata.
submitSuccessResponseViews.entityViewCreate()
.submitSuccessResponse(response -> response
.title("Key Generated Successfully")
.message("Copy this secure key now. It will not be shown again.")
.displayMode(SuccessResponse.DisplayMode.REPLACE_CONTENT)
// Renders the API response's 'secret' property as a click-to-copy string field
.addField("secret", Fields.string()
.copyable()
.label("API Key")));
As of Broadleaf Release Train 2.3.0-GA, support for Spring Boot 3.3 & 3.5 for all common libraries has been added.
Introduced RoundRobinRetryScheduler to manage retry handlers more efficiently.
Addresses resource exhaustion by using a fixed-size thread pool instead of creating a dedicated thread per handler.
In the past, thread counts for retry scheduling could get up to ~2600. This should now be reduced to a constant of 30 (the default).
Ensures fairness via a round-robin scheduling algorithm, preventing "noisy" handlers from monopolizing resources.
Implements a non-blocking design where the scheduler skips full pools and retries on the next cycle.
Added "Burst Mode" support for high-load scenarios.
Allows handlers to request immediate execution on a dedicated "Burst Pool" when a full page of records is processed.
Helps drain large backlogs quickly without starving other handlers in the main fair pool.
Added new configuration properties for tuning the retry scheduler and burst mode behavior.