<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Spryker Documentation</title>
        <description>Spryker documentation center.</description>
        <link>https://docs.spryker.com/</link>
        <atom:link href="https://docs.spryker.com/feed.xml" rel="self" type="application/rss+xml"/>
        <lastBuildDate>Mon, 30 Mar 2026 10:24:52 +0000</lastBuildDate>
        <generator>Jekyll v4.2.2</generator>
        
        
        <item>
            <title>Upgrade the OMS module</title>
            <description>{% include pbc/all/upgrade-modules/upgrade-the-oms-module.md %} &lt;!-- To edit, see /_includes/pbc/all/upgrade-modules/upgrade-the-oms-module.md --&gt;
</description>
            <pubDate>Mon, 30 Mar 2026 10:24:17 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/order-management-system/latest/base-shop/install-and-upgrade/upgrade-modules/upgrade-the-oms-module.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/order-management-system/latest/base-shop/install-and-upgrade/upgrade-modules/upgrade-the-oms-module.html</guid>
            
            
        </item>
        
        <item>
            <title>Data import optimization guidelines</title>
            <description>&lt;p&gt;This article will define the best practices for Spryker modules that need to work with two infrastructure concepts like DataImport and Publish &amp;amp; Synchronize. After several reviews and tests, we found that we need to define these rules to help developers to write more scalable and high-performance code when they implementing their features. Most of the time when developers create features, they don’t consider very high traffic or heavy data processing for big data. This article is going to describe all necessary requirements when you want to create new features and they should work with big data, for example, you want to create a new DataImport or a new P&amp;amp;S module which save millions of entities into a database in a very short amount of time.&lt;/p&gt;
&lt;h2 id=&quot;rules-for-data-importers&quot;&gt;Rules for data importers&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;DataImport&lt;/code&gt; module is responsible for reading data from different formats like CSV, JSON, etc and import them into a database with proper Spryker data structure. Usually importing of data is a time-consuming process and we need to follow some best practices to increase the performance. Here you will find some of them:&lt;/p&gt;
&lt;h3 id=&quot;progress-bar&quot;&gt;Progress bar&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;--progress-bar&lt;/code&gt; flag lets you monitor data import in real time using the &lt;a href=&quot;https://symfony.com/doc/current/components/console/helpers/progressbar.html&quot;&gt;Symfony Console Progress Bar&lt;/a&gt; component. While the import runs, the progress bar displays the current memory usage and processing speed, so you can identify bottlenecks without adding custom logging.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Update the &lt;code&gt;spryker/data-import&lt;/code&gt; package to version 1.32.0 or later:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;composer update spryker/data-import:&lt;span class=&quot;s2&quot;&gt;&quot;^1.32.0&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Add the &lt;code&gt;--progress-bar&lt;/code&gt; flag to any data import command:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;console data:import combined-product-abstract &lt;span class=&quot;nt&quot;&gt;--progress-bar&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;section class=&apos;info-block info-block--warning&apos;&gt;&lt;i class=&apos;info-block__icon icon-warning&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Performance note&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;--progress-bar&lt;/code&gt; flag enables debug mode, which adds overhead to the import process. Use it for diagnostics and testing, not for production data imports.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;h3 id=&quot;single-vs-batch-operation&quot;&gt;Single vs batch operation&lt;/h3&gt;
&lt;p&gt;Assuming you are writing a data importer for &lt;code&gt;ProductAbstract&lt;/code&gt;, you might want to find a category for each product abstract, your very basic code would be something like this:&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;importProductAbstract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;DataSetInterface&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$dataSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$categoryKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$dataSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;category_key&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$productCategory&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SpyCategoryQuery&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;findOneByCategoryKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$categoryKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$dataSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;product_category&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$productCategory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;importProductCategories&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$dataSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This will work fine and you already achieved to your goals, but can you see the problem here?&lt;/p&gt;
&lt;p&gt;Here is the problem:&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;importProductAbstract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;DataSetInterface&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$dataSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;mf&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$productCategory&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SpyCategoryQuery&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;findOneByCategoryKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$categoryKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// expensive call&lt;/span&gt;
 &lt;span class=&quot;mf&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;importProductAbstract&lt;/code&gt; method will call for each line of your CSV, imagine if you have one CSV file with 1,000,000 lines, it means you will run this query again and again for 1 million times! The possible solution is to avoid single processing and implementing a batch query for it.&lt;/p&gt;
&lt;p&gt;The current solution for DataImport is to add another step before the main step to gather all the information you need for the next steps. like querying all categories and remember them in memory and the next step can do a fast PHP look up from that result in memory.&lt;/p&gt;
&lt;section class=&apos;info-block info-block--warning&apos;&gt;&lt;i class=&apos;info-block__icon icon-warning&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Note&lt;/div&gt;
&lt;p&gt;&lt;code&gt;DataImport&lt;/code&gt; v1.4.x doesn’t support the batch processing by default and the next version will provide a very clear solution for it.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;h3 id=&quot;orm-vs-pdo&quot;&gt;ORM vs PDO&lt;/h3&gt;
&lt;p&gt;ORM (Object-relational mapping) is a very good approach when we are working on very big and complex software but it’s not always the answer to all problems especially when it comes to batch processing. ORM is slow by design as they need to handle so many internal hydration and mapping.&lt;/p&gt;
&lt;p&gt;Here is an example of using the Propel ORM, this is a very clean and nice approach but not optimized enough for importing big data.&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createOrUpdateProductAbstract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;DataSetInterface&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$dataSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;SpyProductAbstract&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$productAbstractEntityTransfer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getProductAbstractTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$dataSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;nv&quot;&gt;$productAbstractEntity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SpyProductAbstractQuery&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;filterBySku&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$productAbstractEntityTransfer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getSku&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;findOneOrCreate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$productAbstractEntity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This approach has two problems:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It runs two queries, one SELECT for &lt;code&gt;findOneOrCreate&lt;/code&gt; and one INSERT or UPDATE for &lt;code&gt;save&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Single process approach (repeated per each entry)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The solution is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Avoid ORM, you can use a very simple raw SQL but you should also avoid complex raw or big raw SQL queries.&lt;/li&gt;
&lt;li&gt;Implement &lt;code&gt;DataSetWriterInterface&lt;/code&gt; to achieve the batch processing approach, prepare one by one and write them once (Take a look at &lt;code&gt;ProductAbstractWriter&lt;/code&gt; in &lt;code&gt;Dataimport&lt;/code&gt; as an example).&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;facade-calls&quot;&gt;Facade calls&lt;/h3&gt;
&lt;p&gt;Sometimes you may need to run some validation or business logic for each data set, the easiest and safest way would be a Facade API call, that’s totally fine, but then imagine if these APIs also call some heavy queries very deep! this has a huge side effect on your performance during importing millions of data.&lt;/p&gt;
&lt;p&gt;Here you can see for each product stock, there are two facade calls, each facade call may run more than 5 queries, this means for importing 1,000,000 data, you will have 10,000,000 queries! (this will never finish!).&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;updateBundleAvailability&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$stockProductCollection&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$stockProduct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$stockProduct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ProductStockHydratorStep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;KEY_IS_BUNDLE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;productBundleFacade&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;updateBundleAvailability&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$stockProduct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ProductStockHydratorStep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;KEY_CONCRETE_SKU&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;productBundleFacade&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;updateAffectedBundlesAvailability&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$stockProduct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ProductStockHydratorStep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;KEY_CONCRETE_SKU&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The solution is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Implement a new Facade API for batch operation&lt;/li&gt;
&lt;li&gt;Only call facade if they are very lightweight and they don’t run any query to a database&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;memory-management&quot;&gt;Memory management&lt;/h3&gt;
&lt;p&gt;Let’s say you already started to work with the batch operation, one of the challenges would be to keep the memory as low as possible. Sometimes you create variables and try to remember them always, but you may need them only until the end of the batch operation, so it’s better to release them as soon as possible.&lt;/p&gt;
&lt;h3 id=&quot;database-vendor-approach&quot;&gt;Database vendor approach&lt;/h3&gt;
&lt;p&gt;Spryker supports PostgreSQL, MySQL, and MariaDB. When working with databases, it’s good to know their related features. For example, one of the great features we like is &lt;a href=&quot;https://www.postgresql.org/docs/9.1/queries-with.html&quot;&gt;CTE&lt;/a&gt;. If you are inserting or updating big amounts of data, like millions of millions, use CTE as a replaceable for multiple inserts and updates. You can find examples of implementations in our &lt;a href=&quot;/docs/about/all/about-spryker.html#demo-shops&quot;&gt;Demo Shops&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;rules-for-publish-and-synchronize&quot;&gt;Rules for Publish and Synchronize&lt;/h2&gt;
&lt;p&gt;P&amp;amp;S is a concept for transferring data from Zed database to Yves databases like key-value storage (Redis or Valkey) and ES, This operation is separated into two isolated processes which call &lt;strong&gt;Publish&lt;/strong&gt; and &lt;strong&gt;Synchronize&lt;/strong&gt;. Publishing is a process to aggregating data and writing it to Database and Queue. Synchronization is a process to read an aggregated message from a queue and write it to external endpoints. The performance issues mostly come from &lt;strong&gt;Publishing&lt;/strong&gt; part. Again we need to follow the best practices to increase the performance. Here you will find some of them:&lt;/p&gt;
&lt;h3 id=&quot;single-vs-batch-operation-1&quot;&gt;Single vs batch operation&lt;/h3&gt;
&lt;p&gt;When you are creating a new listener you should consider these rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run your logic against a chunk of event messages not per each.&lt;/li&gt;
&lt;li&gt;Don’t run the query inside of for-loop&lt;/li&gt;
&lt;li&gt;Try to save them with a bulk operation, not one by one&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Take a look at this example:&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;publish&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$productAbstractIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$productAbstractIds&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$idProductAbstract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$productAbstractProductListStorageEntity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;queryProductAbstractProductListEntity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$idProductAbstract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here we are passing a set of ids and then we try to run a query for each product abstract. Imagine if you have 2000 events as a chunk, then you have 2000 queries to a database.&lt;/p&gt;
&lt;p&gt;We can easily fix this by changing the query and run query only once per 2000 ids.&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;publish&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$productAbstractIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
     &lt;span class=&quot;nv&quot;&gt;$productAbstractProductListStorageEntities&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;queryProductAbstractProductListEntities&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$productAbstractIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;facade-calls-1&quot;&gt;Facade calls&lt;/h3&gt;
&lt;p&gt;Another point that we need to be very careful here is to call Facade API without any thinking through, we must make sure that these APIs will not run queries inside same as DataImport rule. You are allowed to call Facade API but if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There is no query inside&lt;/li&gt;
&lt;li&gt;Facade API designed for batch operation (&lt;code&gt;findPriceForSku&lt;/code&gt; vs &lt;code&gt;findPricesForSkus&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;triggering-events&quot;&gt;Triggering events&lt;/h3&gt;
&lt;p&gt;DataImporters are triggering events manually, this is happening because of performance reasons :&lt;/p&gt;
&lt;p&gt;Triggering events automatically will generate so many duplicates events during data importing, (e.g: Inserting a Product into &lt;code&gt;spy_product&lt;/code&gt; and &lt;code&gt;spy_product_localized_attribute&lt;/code&gt; table will generate two events with the same &lt;code&gt;id_product&lt;/code&gt;).
Events will be triggered one by one.&lt;/p&gt;
&lt;p&gt;You can always switch the Event Triggering process with two methods:&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Spryker\Zed\EventBehavior\EventBehaviorConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;mf&quot;&gt;...&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;cd&quot;&gt;/**
         * Disable the events triggering automatically
         */&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;EventBehaviorConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;disableEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// 1.Create many entities in multiple tables (e.g API bulk import, nightly update jobs)&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 2.Trigger proper events if it&apos;s necessary ($eventFacade-&amp;gt;triggerBulk(&apos;ProductAbstractPublish&apos;, $eventTransfers))&lt;/span&gt;

        &lt;span class=&quot;cd&quot;&gt;/**
         * Enable the events triggering automatically
         */&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;EventBehaviorConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;enableEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;pamps-and-cte&quot;&gt;P&amp;amp;S and CTE&lt;/h3&gt;
&lt;p&gt;Sometimes the amount of the data which needs be synced is very high, for this reason, we can not rely on a standard ORM solution for storing data in the database tables. we recommend you to use bulk insert operation whenever you have more than hundreds of thousand of data. you can still use the CTE technique which was used in DataImporter before. Spryker suite comes with several examples of using CTE technique in Storage and Search module you can replace them by overwriting the Business Factory in the modules:&lt;/p&gt;
&lt;section class=&apos;info-block info-block--warning&apos;&gt;&lt;i class=&apos;info-block__icon icon-warning&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Note&lt;/div&gt;
&lt;p&gt;These examples only tested for PostgreSQL.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/Pyz/Zed/PriceProductStorage/Business/Storage/PriceProductAbstractStorageWriter.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/Pyz/Zed/PriceProductStorage/Business/Storage/PriceProductConcreteStorageWriter.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/Pyz/Zed/ProductPageSearch/Business/Publisher/ProductAbstractPagePublisher.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/Pyz/Zed/ProductPageSearch/Business/Publisher/ProductConcretePageSearchPublisher.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/Pyz/Zed/ProductStorage/Business/Storage/ProductAbstractStorageWriter.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/Pyz/Zed/ProductStorage/Business/Storage/ProductConcreteStorageWriter.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/Pyz/Zed/UrlStorage/Business/Storage/UrlStorageWriter.php&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example classes are going to be replaced with a Core CTE solution.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;When we are facing some batch operation, we need to think about big data and performance under heavy loading, we are not allowed to write same code that only does the job, it needs to be scalable and fast for high usages. Below you can find our main points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create batch queries and processes&lt;/li&gt;
&lt;li&gt;Don’t use ORM for batch processing as it’s slow by design&lt;/li&gt;
&lt;li&gt;Don’t run separated queries for each data-set&lt;/li&gt;
&lt;li&gt;Don’t call any facade logic if they are slow or run internal queries&lt;/li&gt;
&lt;li&gt;Release memory after each bulk operations to prevent memory issues&lt;/li&gt;
&lt;li&gt;Use CTE technique (supported by PostgreSQL or MySQL &amp;gt;= 8, and MariaDB &amp;gt;= 10.2)&lt;/li&gt;
&lt;/ul&gt;
</description>
            <pubDate>Mon, 30 Mar 2026 08:28:02 +0000</pubDate>
            <link>https://docs.spryker.com/docs/dg/dev/data-import/latest/data-import-optimization-guidelines.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/dg/dev/data-import/latest/data-import-optimization-guidelines.html</guid>
            
            
        </item>
        
        <item>
            <title>Ratings and Reviews</title>
            <description>Drive sales by including user reviews and ratings. Reviews and ratings are a proven sign of trust; they allow brands to receive valuable and moderate feedback in the Administration Interface. The Ratings and Reviews feature also comes with the functionality to add text-free reviews and star ratings.

## Video tutorial

For more details about managing ratings and reviews, check the video:


&lt;figure class=&quot;video_container&quot;&gt;
    &lt;video width=&quot;100%&quot; height=&quot;auto&quot; controls&gt;
      &lt;source src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/pbc/all/ratings-reviews/ratings-and-reviews.md/How+to+Manage+Ratings+and+Reviews+in+Spryker+B2C-efvyq9vfb8.mp4&quot; type=&quot;video/mp4&quot;&gt;
  &lt;/video&gt;
&lt;/figure&gt;


## Ratings &amp; Reviews capabilities available in Spryker

| NAME | MARKETPLACE COMPATIBLE |
| --- | --- |
| Spryker | No |

## Current constraints

The feature has the following functional constraints, which are going to be resolved in the future:
- Product reviews are linked to locales but not stores.
- A review is available in all the stores that share the locale of the store in which it has been originally created.


## Related Business User documents

| BACK OFFICE USER GUIDES |
| - |
| [Manage product reviews in the Back Office](/docs/pbc/all/ratings-reviews/latest/manage-product-reviews-in-the-back-office.html) |


## Related Developer documents

| INSTALLATION GUIDES | GLUE API GUIDES  | DATA IMPORT | TUTORIALS AND HOWTOS |
|---------|---------|---------| - |
| [Install the Product Rating and Reviews feature](/docs/pbc/all/ratings-reviews/latest/install-and-upgrade/install-the-product-rating-and-reviews-feature.html) | [Managing product ratings and reviews using Glue API](/docs/pbc/all/ratings-reviews/latest/manage-using-glue-api/glue-api-manage-product-reviews.html)  | [File details: product_review.csv](/docs/pbc/all/ratings-reviews/latest/import-and-export-data/import-file-details-product-review.csv.html)  | [HowTo: Configure product reviews](/docs/pbc/all/ratings-reviews/latest/tutorials-and-howtos/howto-configure-product-reviews.html) |
| [Install the Product Rating and Reviews Glue API](/docs/pbc/all/ratings-reviews/latest/install-and-upgrade/install-the-product-rating-and-reviews-glue-api.html)   | [Retrieve product reviews when retrieving abstract products](/docs/pbc/all/ratings-reviews/latest/manage-using-glue-api/glue-api-retrieve-product-reviews-when-retrieving-abstract-products.html)  |  | |
| [Install the Product Rating and Reviews + Product Group feature](/docs/pbc/all/ratings-reviews/latest/install-and-upgrade/install-the-product-rating-and-reviews-product-group-feature.html) | [Retrieving product reviews when retrieving concrete products](/docs/pbc/all/ratings-reviews/latest/manage-using-glue-api/glue-api-retrieve-product-reviews-when-retrieving-concrete-products.html) | | |
</description>
            <pubDate>Thu, 26 Mar 2026 10:56:54 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/ratings-reviews/latest/ratings-and-reviews.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/ratings-reviews/latest/ratings-and-reviews.html</guid>
            
            
        </item>
        
        <item>
            <title>Migrate from the ACP Vertex app</title>
            <description>This document describes how to migrate from the MessageBroker-based [ACP Vertex](https://docs-archive.spryker.com/docs/pbc/all/tax-management/202507.0/base-shop/third-party-integrations/vertex/vertex) integration to the direct `spryker-eco/vertex` module.

{% info_block infoBox &quot;Info&quot; %}

The tax calculation logic remains the same. The ECO module communicates directly with the Vertex API from your application instead of going through the MessageBroker.

{% endinfo_block %}

## 1. Install and integrate the module

Follow the [Integrate Vertex](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex.html) guide to install and set up the module.

## 2. Remove old ACP plugins and configuration

### 2a. Remove the TaxApp MessageBroker handler

In `src/Pyz/Zed/MessageBroker/MessageBrokerDependencyProvider.php`, remove the following import and plugin registration:

```php
// Remove this use statement:
use Spryker\Zed\TaxApp\Communication\Plugin\MessageBroker\TaxAppMessageHandlerPlugin;

// Remove from getMessageHandlerPlugins():
new TaxAppMessageHandlerPlugin(),
```

{% info_block infoBox &quot;Info&quot; %}

If TaxApp was the only ACP app using the MessageBroker, you can also disable the `message-broker-consume-channels` cronjob in `config/Zed/cronjobs/jenkins.php` and set `MessageBrokerConstants::IS_ENABLED` to `false` in `config/Shared/config_default.php` to stop unnecessary background processing.

{% endinfo_block %}

### 2b. Remove the TaxApp publisher plugin for DMS projects

In `src/Pyz/Zed/Publisher/PublisherDependencyProvider.php`, remove the following import and plugin registration:

```php
// Remove this use statement:
use Spryker\Zed\TaxApp\Communication\Plugin\Publisher\Store\RefreshTaxAppStoreRelationPublisherPlugin;

// In getTaxAppPlugins(), return an empty array:
protected function getTaxAppPlugins(): array
{
    return [];
}
```

### 2c. Replace the TaxApp calculation plugin

In `src/Pyz/Zed/Calculation/CalculationDependencyProvider.php`, replace `TaxAppCalculationPlugin` with `VertexCalculationPlugin` in both quote and order calculator stacks:

```php
// Remove:
use Spryker\Zed\TaxApp\Communication\Plugin\Calculation\TaxAppCalculationPlugin;

// Add:
use SprykerEco\Zed\Vertex\Communication\Plugin\Calculation\VertexCalculationPlugin;
```

In `getQuoteCalculatorPluginStack()` and `getOrderCalculatorPluginStack()`, replace:

```php
// Before:
new TaxAppCalculationPlugin(),

// After:
new VertexCalculationPlugin(),
```

### 2d. Replace the TaxApp OMS plugins

In `src/Pyz/Zed/Oms/OmsDependencyProvider.php`, replace the plugins:

```php
// Remove:
use Spryker\Zed\TaxApp\Communication\Plugin\Oms\Command\SubmitPaymentTaxInvoicePlugin;
use Spryker\Zed\TaxApp\Communication\Plugin\Oms\OrderRefundedEventListenerPlugin;

// Add:
use SprykerEco\Zed\Vertex\Communication\Plugin\Oms\Command\VertexSubmitPaymentTaxInvoicePlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Oms\VertexOrderRefundedEventListenerPlugin;
```

In `extendCommandPlugins()`, replace:

```php
// Before:
$commandCollection-&gt;add(new SubmitPaymentTaxInvoicePlugin(), &apos;TaxApp/SubmitPaymentTaxInvoice&apos;);

// After:
$commandCollection-&gt;add(new VertexSubmitPaymentTaxInvoicePlugin(), &apos;Vertex/SubmitPaymentTaxInvoice&apos;);
```

In `getOmsEventTriggeredListenerPlugins()`, replace:

```php
// Before:
new OrderRefundedEventListenerPlugin(),

// After:
new VertexOrderRefundedEventListenerPlugin(),
```

### 2e. Replace the TaxApp Glue Storefront API plugin

In `src/Pyz/Glue/GlueApplication/GlueApplicationDependencyProvider.php`, replace the plugin:

```php
// Remove:
use Spryker\Glue\TaxAppRestApi\Plugin\TaxValidateIdResourceRoutePlugin;

// Add:
use SprykerEco\Glue\Vertex\Plugin\VertexTaxValidateIdResourceRoutePlugin;
```

In `getResourceRoutePlugins()`, replace:

```php
// Before:
new TaxValidateIdResourceRoutePlugin(),

// After:
new VertexTaxValidateIdResourceRoutePlugin(),
```

### 2f. Update OMS state machine XML

Update your OMS process XML files — for example, `config/Zed/oms/DummyPayment01.xml` — to reference the new command name:

```xml
&lt;!-- Before: --&gt;
&lt;event name=&quot;submit tax invoice&quot; onEnter=&quot;true&quot; command=&quot;TaxApp/SubmitPaymentTaxInvoice&quot;/&gt;

&lt;!-- After: --&gt;
&lt;event name=&quot;submit tax invoice&quot; onEnter=&quot;true&quot; command=&quot;Vertex/SubmitPaymentTaxInvoice&quot;/&gt;
```

### 2g. Clean up config_default.php

Remove TaxApp-specific configuration and MessageBroker channel mappings from `config/Shared/config_default.php`:

```php
// Remove these transfer use statements:
use Generated\Shared\Transfer\ConfigureTaxAppTransfer;
use Generated\Shared\Transfer\DeleteTaxAppTransfer;
use Generated\Shared\Transfer\SubmitPaymentTaxInvoiceTransfer;

// Remove this use statement:
use Spryker\Shared\TaxApp\TaxAppConstants;

// Remove TaxAppConstants from OAuth and tenant assignments:
// $config[TaxAppConstants::OAUTH_PROVIDER_NAME] = ...
// $config[TaxAppConstants::OAUTH_GRANT_TYPE] = ...
// $config[TaxAppConstants::OAUTH_OPTION_AUDIENCE] = ...
// $config[TaxAppConstants::TENANT_IDENTIFIER] = ...

// Remove TaxApp MessageBroker channel mappings from $config[MessageBrokerConstants::CHANNEL_TO_RECEIVER_TRANSPORT_MAP]:
// ConfigureTaxAppTransfer::class =&gt; &apos;tax-commands&apos;,
// DeleteTaxAppTransfer::class =&gt; &apos;tax-commands&apos;,
// SubmitPaymentTaxInvoiceTransfer::class =&gt; &apos;payment-tax-invoice-commands&apos;,
```

## 3. Add new Vertex configuration

### 3a. Add Vertex credentials

In `config/Shared/config_default.php`, add the following:

```php
use SprykerEco\Shared\Vertex\VertexConstants;

$config[VertexConstants::IS_ACTIVE] = getenv(&apos;VERTEX_IS_ACTIVE&apos;) ?: null;
$config[VertexConstants::CLIENT_ID] = getenv(&apos;VERTEX_CLIENT_ID&apos;) ?: null;
$config[VertexConstants::CLIENT_SECRET] = getenv(&apos;VERTEX_CLIENT_SECRET&apos;) ?: null;
$config[VertexConstants::SECURITY_URI] = getenv(&apos;VERTEX_SECURITY_URI&apos;) ?: null;
$config[VertexConstants::TRANSACTION_CALLS_URI] = getenv(&apos;VERTEX_TRANSACTION_CALLS_URI&apos;) ?: null;

// Optional: Tax ID Validator (Vertex Validator / Taxamo)
$config[VertexConstants::TAXAMO_API_URL] = getenv(&apos;TAXAMO_API_URL&apos;) ?: null;
$config[VertexConstants::TAXAMO_TOKEN] = getenv(&apos;TAXAMO_TOKEN&apos;) ?: null;
```

### 3b. Override feature flags

Create `src/Pyz/Zed/Vertex/VertexConfig.php`:

```php
&lt;?php

namespace Pyz\Zed\Vertex;

use SprykerEco\Zed\Vertex\VertexConfig as SprykerEcoVertexConfig;

class VertexConfig extends SprykerEcoVertexConfig
{
    public function isTaxIdValidatorEnabled(): bool
    {
        return true;
    }

    public function isTaxAssistEnabled(): bool
    {
        return true;
    }

    public function isInvoicingEnabled(): bool
    {
        return true;
    }
}
```

### 3c. Register expander and fallback plugins

Create `src/Pyz/Zed/Vertex/VertexDependencyProvider.php`:

```php
&lt;?php

namespace Pyz\Zed\Vertex;

use Spryker\Zed\Calculation\Communication\Plugin\Calculator\ItemTaxAmountFullAggregatorPlugin;
use Spryker\Zed\Calculation\Communication\Plugin\Calculator\PriceToPayAggregatorPlugin;
use Spryker\Zed\MerchantProfile\Communication\Plugin\TaxApp\MerchantProfileAddressCalculableObjectTaxAppExpanderPlugin;
use Spryker\Zed\MerchantProfile\Communication\Plugin\TaxApp\MerchantProfileAddressOrderTaxAppExpanderPlugin;
use Spryker\Zed\ProductOfferAvailability\Communication\Plugin\TaxApp\ProductOfferAvailabilityCalculableObjectTaxAppExpanderPlugin;
use Spryker\Zed\ProductOfferAvailability\Communication\Plugin\TaxApp\ProductOfferAvailabilityOrderTaxAppExpanderPlugin;
use Spryker\Zed\Tax\Communication\Plugin\Calculator\TaxAmountAfterCancellationCalculatorPlugin;
use Spryker\Zed\Tax\Communication\Plugin\Calculator\TaxAmountCalculatorPlugin;
use Spryker\Zed\Tax\Communication\Plugin\Calculator\TaxRateAverageAggregatorPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Order\OrderCustomerWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Order\OrderExpensesWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Order\OrderItemProductOptionWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Order\OrderItemWithVertexSpecificFieldsExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Quote\CalculableObjectCustomerWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Quote\CalculableObjectExpensesWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Quote\CalculableObjectItemProductOptionWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Quote\CalculableObjectItemWithVertexSpecificFieldsExpanderPlugin;
use SprykerEco\Zed\Vertex\VertexDependencyProvider as SprykerVertexDependencyProvider;

class VertexDependencyProvider extends SprykerVertexDependencyProvider
{
    /**
     * @return array&lt;\SprykerEco\Zed\Vertex\Dependency\Plugin\CalculableObjectVertexExpanderPluginInterface|\Spryker\Zed\TaxAppExtension\Dependency\Plugin\CalculableObjectTaxAppExpanderPluginInterface&gt;
     */
    protected function getCalculableObjectVertexExpanderPlugins(): array
    {
        return [
            new CalculableObjectCustomerWithVertexCodeExpanderPlugin(),
            new CalculableObjectExpensesWithVertexCodeExpanderPlugin(),
            new CalculableObjectItemProductOptionWithVertexCodeExpanderPlugin(),
            new CalculableObjectItemWithVertexSpecificFieldsExpanderPlugin(),
            new MerchantProfileAddressCalculableObjectTaxAppExpanderPlugin(),
            new ProductOfferAvailabilityCalculableObjectTaxAppExpanderPlugin(),
        ];
    }

    /**
     * @return array&lt;\SprykerEco\Zed\Vertex\Dependency\Plugin\OrderVertexExpanderPluginInterface|\Spryker\Zed\TaxAppExtension\Dependency\Plugin\OrderTaxAppExpanderPluginInterface&gt;
     */
    protected function getOrderVertexExpanderPlugins(): array
    {
        return [
            new OrderCustomerWithVertexCodeExpanderPlugin(),
            new OrderExpensesWithVertexCodeExpanderPlugin(),
            new OrderItemProductOptionWithVertexCodeExpanderPlugin(),
            new OrderItemWithVertexSpecificFieldsExpanderPlugin(),
            new MerchantProfileAddressOrderTaxAppExpanderPlugin(),
            new ProductOfferAvailabilityOrderTaxAppExpanderPlugin(),
        ];
    }

    /**
     * @return array&lt;\Spryker\Zed\CalculationExtension\Dependency\Plugin\CalculationPluginInterface&gt;
     */
    protected function getFallbackQuoteCalculationPlugins(): array
    {
        return [
            new TaxAmountCalculatorPlugin(),
            new ItemTaxAmountFullAggregatorPlugin(),
            new PriceToPayAggregatorPlugin(),
            new TaxRateAverageAggregatorPlugin(),
        ];
    }

    /**
     * @return array&lt;\Spryker\Zed\CalculationExtension\Dependency\Plugin\CalculationPluginInterface&gt;
     */
    protected function getFallbackOrderCalculationPlugins(): array
    {
        return [
            new TaxAmountCalculatorPlugin(),
            new ItemTaxAmountFullAggregatorPlugin(),
            new PriceToPayAggregatorPlugin(),
            new TaxAmountAfterCancellationCalculatorPlugin(),
        ];
    }
}
```

## 4. Set up the database and transfers

```bash
vendor/bin/console propel:install
vendor/bin/console transfer:generate
```

## 5. Import glossary data

The module provides translation data for tax validation messages.

**Option 1: Import using the module&apos;s configuration file**

```bash
vendor/bin/console data:import --config=vendor/spryker-eco/vertex/data/import/vertex.yml
```

**Option 2: Copy file content and import individually**

Copy content from `vendor/spryker-eco/vertex/data/import/*.csv` to the corresponding files in `data/import/common/common/`. Then run:

```bash
vendor/bin/console data:import glossary
```

**Option 3: Add to the project&apos;s main import configuration**

Add the import actions to your project&apos;s main data import configuration file and include them in your regular import pipeline.

## 6. Verify the migration

1. Clear caches: `vendor/bin/console cache:empty-all`.
2. Place a test order and verify that tax calculation works.
3. If invoicing is enabled, verify that the `Vertex/SubmitPaymentTaxInvoice` OMS command triggers correctly.
4. If tax ID validation is enabled, test the `POST /tax-id-validate` Glue Storefront API endpoint.

For detailed verification steps, see [Verify Vertex connection](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/verify-vertex-connection.html).

## Summary of changes

| Component | ACP (before) | ECO (after) |
|-----------|-------------|-------------|
| Tax calculation plugin | `TaxAppCalculationPlugin` | `VertexCalculationPlugin` |
| OMS invoice command | `SubmitPaymentTaxInvoicePlugin` (`TaxApp/...`) | `VertexSubmitPaymentTaxInvoicePlugin` (`Vertex/...`) |
| OMS refund listener | `OrderRefundedEventListenerPlugin` | `VertexOrderRefundedEventListenerPlugin` |
| Glue tax validation | `TaxValidateIdResourceRoutePlugin` | `VertexTaxValidateIdResourceRoutePlugin` |
| MessageBroker handler | `TaxAppMessageHandlerPlugin` | Removed (not needed) |
| Publisher plugin | `RefreshTaxAppStoreRelationPublisherPlugin` | Removed (not needed) |
| Configuration | `TaxAppConstants` + OAuth | `VertexConstants` + direct API credentials |
| Communication | Via MessageBroker (async) | Direct Vertex API calls (sync) |
</description>
            <pubDate>Wed, 25 Mar 2026 12:51:03 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/migrate-from-acp-to-vertex.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/migrate-from-acp-to-vertex.html</guid>
            
            
        </item>
        
        <item>
            <title>Performance guidelines</title>
            <description>These performance guidelines originate from Spryker&apos;s years of experience across all kinds of projects, environments, and setups. They cover topics that are often missed at the project level, leading to poor performance or other related issues. The guidelines help you analyze and optimize performance of your website from different perspectives:

- [Keeping dependencies updated](/docs/dg/dev/guidelines/performance-guidelines/keeping-dependencies-updated.html) to maintain optimal performance and security by staying current with Spryker module updates.
- [Monitoring](/docs/dg/dev/guidelines/performance-guidelines/monitoring.html) to ensure effective application monitoring using APM tools.
- [General performance guidelines](/docs/dg/dev/guidelines/performance-guidelines/general-performance-guidelines.html) for general approaches to optimizing the server-side execution time.
- [Architecture performance guidelines](/docs/dg/dev/guidelines/performance-guidelines/architecture-performance-guidelines.html) to optimize performance in the very end servers.
- [Frontend performance guidelines](/docs/dg/dev/guidelines/performance-guidelines/front-end-performance-guidelines.html) to do the frontend-specific optimization.
- [Twig performance best practices](/docs/dg/dev/guidelines/performance-guidelines/twig-performance-best-practices.html) to optimize Twig templating engine performance.
- [Session locks](/docs/dg/dev/guidelines/performance-guidelines/session-locks.html) to optimize session locking mechanisms and reduce performance impact. Also see [Redis session lock](/docs/dg/dev/troubleshooting/troubleshooting-performance-issues/redis-session-lock.html) for troubleshooting session lock issues.
- [Bot control](/docs/dg/dev/guidelines/performance-guidelines/bot-control.html) to manage honest and malicious bot traffic effectively.
- [Batch processing of Propel entities](/docs/dg/dev/guidelines/performance-guidelines/performance-guidelines-batch-processing-propel-entities.html) for efficient batch processing, reduced database load, and support for complex entity relationships.
- [Database performance guidelines](/docs/dg/dev/guidelines/performance-guidelines/database-performance-guidelines.html) to optimize database operations through proper indexing, query optimization, and avoiding common database anti-patterns.
- [Key-Value storage performance guidelines](/docs/dg/dev/guidelines/performance-guidelines/key-value-storage-performance-guidelines.html) to optimize Redis/ValKey usage by limiting operations, avoiding admin commands in runtime, and implementing proper caching strategies.
- [External HTTP requests](/docs/dg/dev/guidelines/performance-guidelines/external-http-requests.html) to understand Spryker&apos;s architecture principle of reading from fast storage and learn how to manage external HTTP requests when they&apos;re necessary.
- [Search performance guidelines](/docs/dg/dev/guidelines/performance-guidelines/search-performance-guidelines.html) to optimize Elasticsearch and OpenSearch performance, avoid common search anti-patterns, and implement efficient search queries.
- [Infrastructure and worker configuration guidelines](/docs/dg/dev/guidelines/performance-guidelines/infrastructure-worker-configuration-guidelines.html) to optimize nginx configuration and worker orchestration for multi-store setups.
- [CDN and traffic management integration](/docs/dg/dev/guidelines/performance-guidelines/cdn-and-traffic-management-integration.html) to configure CDN solutions like Akamai or Cloudflare to work correctly with Spryker&apos;s nginx compression and avoid unnecessary data transfer overhead.
- [Custom code performance guidelines](/docs/dg/dev/guidelines/performance-guidelines/custom-code-performance-guidelines.html) to implement performant custom code including caching strategies, background processing, and Quote calculator optimization.
- [Common pitfalls in OMS design](/docs/pbc/all/order-management-system/latest/base-shop/datapayload-conversion/state-machine/common-pitfalls-in-oms-design.html) to avoid performance bottlenecks in Order Management System processes, especially ensuring heavy operations run in CLI context rather than during web requests.
- [Order management system multi-thread](/docs/pbc/all/order-management-system/latest/base-shop/datapayload-conversion/state-machine/order-management-system-multi-thread.html) to process OMS timeouts and conditions in parallel for improved order processing performance.
- [Troubleshooting performance issues](/docs/dg/dev/troubleshooting/troubleshooting-performance-issues/troubleshooting-performance-issues.html) for detecting and fixing common performance problems.
- [Order details page performance guidance](/docs/pbc/all/order-management-system/latest/base-shop/order-management-feature-overview/order-details-page-performance-overview.html) to optimize the order detail page in the Back Office
</description>
            <pubDate>Wed, 25 Mar 2026 12:42:04 +0000</pubDate>
            <link>https://docs.spryker.com/docs/dg/dev/guidelines/performance-guidelines/performance-guidelines.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/dg/dev/guidelines/performance-guidelines/performance-guidelines.html</guid>
            
            
        </item>
        
        <item>
            <title>Order details page performance guidance</title>
            <description>The Back Office order details page can contain a large number of sub-requests. While sub-requests are a valid architectural pattern, in high-traffic environments they can become a source of performance issues—each sub-request adds latency and load to the system.

To address this, Spryker introduces two plugin stacks that replace sub-requests with direct plugin-based data expansion and rendering on the order details page.

## How it works

Previously, the order details page loaded data and rendered blocks by making sub-requests to other modules. Each sub-request was an independent HTTP call processed by the application stack, which multiplied response time and resource consumption proportionally to the number of blocks on the page.

The new approach uses two plugin stacks:

1. **Data expansion plugins**: Plugins collect and provide data directly, bypassing sub-requests.
2. **Block renderer plugins**: Plugins render template blocks directly, bypassing sub-requests.

If a plugin is registered, its data or rendered output is used. If a plugin is not registered, the system falls back to the original sub-request behavior, ensuring backward compatibility.

## Install the feature

To install the feature, update the required modules using Composer. The following is the full list of modules involved—your project may not require all of them.

```bash
composer update spryker/gift-card:&quot;^1.13.0&quot; spryker/manual-order-entry:&quot;^1.3.0&quot; spryker/money:&quot;^2.17.0&quot; spryker/oms:&quot;^11.52.0&quot; spryker/refund:&quot;^5.15.0&quot; spryker/sales:&quot;^11.81.0&quot; spryker/sales-extension:&quot;^1.14.0&quot; spryker/sales-order-threshold-gui:&quot;^2.2.0&quot; spryker/sales-payment-detail:&quot;^1.6.0&quot; spryker/sales-product-configuration-gui:&quot;^1.1.0&quot; spryker/sales-return-gui:&quot;^2.2.0&quot; spryker/shipment-gui:&quot;^3.2.0&quot; spryker-feature/self-service-portal:&quot;^19.4.0&quot; spryker/merchant-user:&quot;^1.9.1&quot;
```

For a full integration example, see the [B2B Demo Marketplace integration PR](https://github.com/spryker-shop/b2b-demo-marketplace/pull/957/changes).

For the complete release details, see [Release Group 6396](https://api.release.spryker.com/release-group/6396).

## Plugin stacks

### Data expansion plugins

The `getSalesOrderDetailDataExpanderPlugins()` method in `SalesDependencyProvider` registers plugins that expand order detail data directly, without sub-requests.

**Location:** `src/Pyz/Zed/Sales/SalesDependencyProvider.php`

```php
/**
 * @return array&lt;\Spryker\Zed\SalesExtension\Dependency\Plugin\SalesOrderDetailDataExpanderPluginInterface&gt;
 */
protected function getSalesOrderDetailDataExpanderPlugins(): array
{
    return [
        new ShipmentSalesOrderDetailDataExpanderPlugin(),
        new ProductConfigurationSalesOrderDetailDataExpanderPlugin(),
        new CommentsSalesOrderDetailDataExpanderPlugin(),
        new OmsFormsSalesOrderDetailDataExpanderPlugin(),
        new ThresholdExpensesSalesOrderDetailDataExpanderPlugin(),
        new ShipmentExpensesSalesOrderDetailDataExpanderPlugin(),
    ];
}
```

{% info_block infoBox &quot;Plugin registration&quot; %}

Register only the plugins that are relevant to your project. Not all plugins may be required depending on the modules you use.

{% endinfo_block %}

### Block renderer plugins

The `getSalesDetailBlockRendererPlugins()` method in `SalesDependencyProvider` registers plugins that render order detail blocks directly, without sub-requests.

**Location:** `src/Pyz/Zed/Sales/SalesDependencyProvider.php`

```php
/**
 * @return array&lt;\Spryker\Zed\SalesExtension\Dependency\Plugin\SalesDetailBlockRendererPluginInterface&gt;
 */
protected function getSalesDetailBlockRendererPlugins(): array
{
    return [
        new OrderTransferBlockRendererPlugin(),
        new SalesCommentBlockRendererPlugin(),
        new SalesReturnListBlockRendererPlugin(),
        new SalesPaymentDetailListBlockRendererPlugin(),
        new RefundSalesListBlockRendererPlugin(),
        new SelfServicePortalOrderInquiryListBlockRendererPlugin(),
    ];
}
```

{% info_block infoBox &quot;Plugin registration&quot; %}

Register only the plugins that are relevant to your project. Not all plugins may be required depending on the modules you use.

{% endinfo_block %}

This plugin stack replaces the sub-request configuration defined in `\Pyz\Zed\Sales\SalesConfig::getSalesDetailExternalBlocksUrls`.

### OrderTransferBlockRendererPlugin template map

`OrderTransferBlockRendererPlugin` requires an additional configuration on the project level that maps block URLs to Twig templates.

**Location:** `src/Pyz/Zed/Sales/SalesConfig.php`

```php
/**
 * @return array&lt;string, string&gt;
 */
public function getOrderDetailBlockUrlToTemplateMap(): array
{
    return [
        &apos;/cart-note/sales/list&apos; =&gt; &apos;@CartNote/Sales/list.twig&apos;,
        &apos;/comment-sales-connector/sales/list&apos; =&gt; &apos;@CommentSalesConnector/Sales/list.twig&apos;,
        &apos;/cart-note-product-bundle-connector/sales/list&apos; =&gt; &apos;@CartNoteProductBundleConnector/Sales/list.twig&apos;,
        &apos;/sales-payment-gui/sales/list&apos; =&gt; &apos;@SalesPaymentGui/Sales/list.twig&apos;,
        &apos;/discount/sales/list&apos; =&gt; &apos;@Discount/Sales/list.twig&apos;,
    ];
}
```

Include only the entries that correspond to the modules enabled in your project.
</description>
            <pubDate>Wed, 25 Mar 2026 12:35:52 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/order-management-system/latest/base-shop/order-management-feature-overview/order-details-page-performance-overview.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/order-management-system/latest/base-shop/order-management-feature-overview/order-details-page-performance-overview.html</guid>
            
            
        </item>
        
        <item>
            <title>Integrate Vertex</title>
            <description>This document describes how to integrate [Vertex](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/vertex.html) into a Spryker shop.

## Prerequisites

Before integrating Vertex, ensure the following prerequisites are met:

- Make sure that your deployment pipeline executes database migrations.

## 1. Install the module

Install the Vertex module using Composer:

```bash
composer require spryker-eco/vertex
```

## 2. Configure the module

Add the following configuration to `config/Shared/config_default.php`:

```php
use SprykerEco\Shared\Vertex\VertexConstants;

$config[VertexConstants::IS_ACTIVE] = getenv(&apos;VERTEX_IS_ACTIVE&apos;);
$config[VertexConstants::CLIENT_ID] = getenv(&apos;VERTEX_CLIENT_ID&apos;);
$config[VertexConstants::CLIENT_SECRET] = getenv(&apos;VERTEX_CLIENT_SECRET&apos;);
$config[VertexConstants::SECURITY_URI] = getenv(&apos;VERTEX_SECURITY_URI&apos;);
$config[VertexConstants::TRANSACTION_CALLS_URI] = getenv(&apos;VERTEX_TRANSACTION_CALLS_URI&apos;);
// Optional: Tax ID Validator (requires Vertex Validator, previously known as Taxamo, see https://developer.vertexinc.com/vertex-e-commerce/docs/stand-alone-deployments)
$config[VertexConstants::TAXAMO_API_URL] = getenv(&apos;TAXAMO_API_URL&apos;);
$config[VertexConstants::TAXAMO_TOKEN] = getenv(&apos;TAXAMO_TOKEN&apos;);

// Optional: Vendor Code
$config[VertexConstants::VENDOR_CODE] = &apos;&apos;;
```

### Required configuration constants

| Constant | Description | Where to get the value |
|----------|-------------|------------------------|
| `IS_ACTIVE` | Enables or disables Vertex tax calculation. | Set to `true` to enable. |
| `CLIENT_ID` | OAuth client ID for the Vertex API. | Obtain from your Vertex account. For details, see [Vertex documentation](https://tax-calc-api.vertexcloud.com/resources/index.html). |
| `CLIENT_SECRET` | OAuth client secret for the Vertex API. | Obtain from your Vertex account. For details, see [Vertex documentation](https://tax-calc-api.vertexcloud.com/resources/index.html). |
| `SECURITY_URI` | Vertex OAuth security endpoint. | Obtain from your Vertex platform. For details, see [Vertex documentation](https://tax-calc-api.vertexcloud.com/resources/index.html). |
| `TRANSACTION_CALLS_URI` | Vertex transaction calls endpoint. | Obtain from your Vertex platform. For details, see [Vertex documentation](https://tax-calc-api.vertexcloud.com/resources/index.html). |

### Optional configuration constants

| Constant | Description | Where to get the value |
|----------|-------------|------------------------|
| `TAXAMO_API_URL` | Vertex Validator API URL for tax ID validation. | Obtain from your Vertex Validator environment. For details, see [Standalone Vertex Validator](https://developer.vertexinc.com/vertex-e-commerce/docs/stand-alone-deployments). |
| `TAXAMO_TOKEN` | Vertex Validator API authentication token. | Obtain from your Vertex Validator account. For details, see [Accessing the APIs](https://developer.vertexinc.com/vertex-marketplaces/docs/getting-started-1). |
| `VENDOR_CODE` | Vendor code for Vertex tax calculations. | Set in your Vertex account. |
| `DEFAULT_TAXPAYER_COMPANY_CODE` | Default taxpayer company code. | The company code you set in your Vertex account. |

## 3. Override feature flags

The `isTaxIdValidatorEnabled`, `isTaxAssistEnabled`, and `isInvoicingEnabled` methods default to `false` and are not driven by constants. To enable them, override `src/Pyz/Zed/Vertex/VertexConfig.php`:

```php
namespace Pyz\Zed\Vertex;

use SprykerEco\Zed\Vertex\VertexConfig as SprykerEcoVertexConfig;

class VertexConfig extends SprykerEcoVertexConfig
{
    public function isTaxIdValidatorEnabled(): bool
    {
        return true;
    }

    public function isTaxAssistEnabled(): bool
    {
        return true;
    }

    public function isInvoicingEnabled(): bool
    {
        return true;
    }
}
```

### Config methods

The following methods must be overridden in `src/Pyz/Zed/Vertex/VertexConfig.php` to enable the respective features:

| Method | Default | Description                                                                                                                                                                       |
|--------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `isTaxIdValidatorEnabled()` | `false` | Enables tax ID validation via [Vertex Validator](https://developer.vertexinc.com/vertex-e-commerce/docs/stand-alone-deployments). Requires `TAXAMO_API_URL` and `TAXAMO_TOKEN` to be set.                                                                                     |
| `isTaxAssistEnabled()` | `false` | Enables the tax assist feature. Return Assisted Parameters in the response that will provide more details about the calculation. The logs can be checked in the Vertex Dashboard. |
| `isInvoicingEnabled()` | `false` | Enables invoicing functionality. Requires OMS plugins to be registered. See [Register OMS plugins](#register-oms-plugins).                                                        |
| `getSellerCountryCode()` | `&apos;&apos;` | Overrides the default seller country code (2-letter ISO code, for example, `US`). Defaults to the first country of the store.                                                     |
| `getCustomerCountryCode()` | `&apos;&apos;` | Overrides the default customer country code (applied only when no customer billing address is provided).  Defaults to the first country of the store.                             |

## 4. Set up the database schema

Install the database schema:

```bash
vendor/bin/console propel:install
```

## 5. Generate transfer objects

Generate transfer objects for the module:

```bash
vendor/bin/console transfer:generate
```

## 6. Register plugins

### Register the tax calculation plugin

Add the Vertex calculation plugin to `src/Pyz/Zed/Calculation/CalculationDependencyProvider.php`:

```php
use SprykerEco\Zed\Vertex\Communication\Plugin\Calculation\VertexCalculationPlugin;

protected function getQuoteCalculatorPluginStack(Container $container): array
{
    return [
        //...

        # Suggested plugins order is shown.

        new ItemDiscountAmountFullAggregatorPlugin(),

        # This plugin is replacing other tax calculation plugins in the stack and will use them as a fallback.
        # No other tax calculation plugins except for VertexCalculationPlugin should be present in the stack.
        new VertexCalculationPlugin(),

        new PriceToPayAggregatorPlugin(),

        //...
    ];
}

protected function getOrderCalculatorPluginStack(Container $container): array
{
    return [
        //...

        # Suggested plugins order is shown.

        new ItemDiscountAmountFullAggregatorPlugin(),

        # This plugin is replacing other tax calculation plugins in the stack and will use them as a fallback.
        # No other tax calculation plugins except for VertexCalculationPlugin should be present in the stack.
        new VertexCalculationPlugin(),

        new PriceToPayAggregatorPlugin(),

        //...
    ];
}
```

#### Register Fallback Calculation Plugins

Add order and quote Fallback Calculation Plugins to `src/Pyz/Zed/Vertex/VertexDependencyProvider.php`:

```php
use Spryker\Zed\Calculation\Communication\Plugin\Calculator\ItemTaxAmountFullAggregatorPlugin;
use Spryker\Zed\Calculation\Communication\Plugin\Calculator\PriceToPayAggregatorPlugin;
use Spryker\Zed\Tax\Communication\Plugin\Calculator\TaxAmountAfterCancellationCalculatorPlugin;
use Spryker\Zed\Tax\Communication\Plugin\Calculator\TaxAmountCalculatorPlugin;
use Spryker\Zed\Tax\Communication\Plugin\Calculator\TaxRateAverageAggregatorPlugin;

/**
 * {@inheritDoc}
 *
 * @return array&lt;\Spryker\Zed\CalculationExtension\Dependency\Plugin\CalculationPluginInterface&gt;
 */
protected function getFallbackQuoteCalculationPlugins(): array
{
    return [
        # These plugins will be called if Vertex configuration is missing or Vertex is disabled.
        # Please note that this list includes PriceToPayAggregatorPlugin - this plugin isn&apos;t a part of tax calculation logic but it&apos;s required by TaxRateAverageAggregatorPlugin.
        new TaxAmountCalculatorPlugin(),
        new ItemTaxAmountFullAggregatorPlugin(),
        new PriceToPayAggregatorPlugin(),
        new TaxRateAverageAggregatorPlugin(),
    ];
}

/**
 * {@inheritDoc}
 *
 * @return array&lt;\Spryker\Zed\CalculationExtension\Dependency\Plugin\CalculationPluginInterface&gt;
 */
protected function getFallbackOrderCalculationPlugins(): array
{
    return [
        # These plugins will be called if Vertex configuration is missing or Vertex is disabled.
        # Please note that this list includes PriceToPayAggregatorPlugin - this plugin isn&apos;t a part of tax calculation logic but it&apos;s required by TaxAmountAfterCancellationCalculatorPlugin.
        new TaxAmountCalculatorPlugin(),
        new ItemTaxAmountFullAggregatorPlugin(),
        new PriceToPayAggregatorPlugin(),
        new TaxAmountAfterCancellationCalculatorPlugin(),
    ];
}
```

In general, `getFallbackQuoteCalculationPlugins()` and `getFallbackOrderCalculationPlugins()` methods should contain the tax calculation plugins, which are replaced by `VertexCalculationPlugin` in `\Pyz\Zed\Calculation\CalculationDependencyProvider`.
The code snippet above is an example of such configuration based on the Spryker default tax calculation plugins.
Tax calculation plugins moved:
- from `getQuoteCalculatorPluginStack` method: `TaxAmountCalculatorPlugin`, `ItemTaxAmountFullAggregatorPlugin`, `PriceToPayAggregatorPlugin`, `TaxRateAverageAggregatorPlugin`
- from `getOrderCalculatorPluginStack` method: `TaxAmountCalculatorPlugin`, `ItemTaxAmountFullAggregatorPlugin`, `PriceToPayAggregatorPlugin`, `TaxAmountAfterCancellationCalculatorPlugin`

{% info_block infoBox &quot;Fallback behavior&quot; %}

There are three different failure scenarios where `VertexCalculationPlugin` might need to use a fallback logic:

1. Vertex isn&apos;t connected: fallback plugins defined in `getFallbackQuoteCalculationPlugins()` and `getFallbackOrderCalculationPlugins()` will be used to calculate taxes.
2. Vertex is disabled: fallback plugins defined in `getFallbackQuoteCalculationPlugins()` and `getFallbackOrderCalculationPlugins()` will be used to calculate taxes.
3. Vertex is not responding or is responding with an error: tax value will be set to zero, and the customer will be able to proceed with the checkout.

{% endinfo_block %}

### Register CalculableObject and order expander plugins

Add order and CalculableObject expander plugins to `src/Pyz/Zed/Vertex/VertexDependencyProvider.php`. The proposed plugins are examples, you can select which ones to register based on your requirements or create custom ones if needed.

```php
use SprykerEco\Zed\Vertex\Communication\Plugin\Order\OrderCustomerWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Order\OrderExpensesWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Order\OrderItemProductOptionWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Order\OrderItemWithVertexSpecificFieldsExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Quote\CalculableObjectCustomerWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Quote\CalculableObjectExpensesWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Quote\CalculableObjectItemProductOptionWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Quote\CalculableObjectItemWithVertexSpecificFieldsExpanderPlugin;

protected function getCalculableObjectVertexExpanderPlugins(): array
{
    return [
        // ... other plugins
        new CalculableObjectCustomerWithVertexCodeExpanderPlugin(),
        new CalculableObjectExpensesWithVertexCodeExpanderPlugin(),
        new CalculableObjectItemProductOptionWithVertexCodeExpanderPlugin(),
        new CalculableObjectItemWithVertexSpecificFieldsExpanderPlugin(),
    ];
}

protected function getOrderVertexExpanderPlugins(): array
{
    return [
        // ... other plugins
        new OrderCustomerWithVertexCodeExpanderPlugin(),
        new OrderExpensesWithVertexCodeExpanderPlugin(),
        new OrderItemProductOptionWithVertexCodeExpanderPlugin(),
        new OrderItemWithVertexSpecificFieldsExpanderPlugin(),
    ];
}
```

## 7. Configure the Shop Application dependency provider

Add the following code to `src/Pyz/Yves/ShopApplication/ShopApplicationDependencyProvider.php`:

```php

namespace Pyz\Yves\ShopApplication;

use SprykerShop\Yves\ShopApplication\ShopApplicationDependencyProvider as SprykerShopApplicationDependencyProvider;
use SprykerShop\Yves\CartPage\Widget\CartSummaryHideTaxAmountWidget;

class ShopApplicationDependencyProvider extends SprykerShopApplicationDependencyProvider
{
    /**
     * @phpstan-return array&lt;class-string&lt;\Spryker\Yves\Kernel\Widget\AbstractWidget&gt;&gt;
     *
     * @return array&lt;string&gt;
     */
    protected function getGlobalWidgets(): array
    {
        return [
            //...

            # This widget is replacing Spryker default tax display in cart summary page with text stating that tax amount will be calculated during checkout process.
            CartSummaryHideTaxAmountWidget::class,
        ];
    }
}

```

If you have custom Yves templates or make your own Frontend, add `CartSummaryHideTaxAmountWidget` to your template. The core template is located at `SprykerShop/Yves/CartPage/Theme/default/components/molecules/cart-summary/cart-summary.twig`.

Here is an example with `CartSummaryHideTaxAmountWidget`:

```html
{% raw %}
&lt;li class=&quot;list__item spacing-y&quot;&gt;
    {{ &apos;cart.total.tax_total&apos; | trans }}
    {% widget &apos;CartSummaryHideTaxAmountWidget&apos; args [data.cart] only %}
    {% nowidget %}
        &lt;span class=&quot;float-right&quot;&gt;{{ data.cart.totals.taxTotal.amount | money(true, data.cart.currency.code) }}&lt;/span&gt;
    {% endwidget %}
&lt;/li&gt;
{% endraw %}
```

## 8. Optional: Sending tax invoices to Vertex and handling refunds

Configure payment `config/Zed/oms/{your_payment_oms}.xml`as in the following example:

```xml
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;statemachine
    xmlns=&quot;spryker:oms-01&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;spryker:oms-01 http://static.spryker.com/oms-01.xsd&quot;
&gt;

    &lt;process name=&quot;SomePaymentProcess&quot; main=&quot;true&quot;&gt;

        &lt;!-- other configurations --&gt;

        &lt;states&gt;

            &lt;!-- other states --&gt;

            &lt;state name=&quot;tax invoice submitted&quot; reserved=&quot;true&quot; display=&quot;oms.state.paid&quot;/&gt;

            &lt;!-- other states --&gt;

        &lt;/states&gt;

        &lt;transitions&gt;

            &lt;!-- other transitions --&gt;

            &lt;transition happy=&quot;true&quot;&gt;
                &lt;source&gt;paid&lt;/source&gt; &lt;!-- Suggested that paid transition should be the source, but it&apos;s up to you --&gt;
                &lt;target&gt;tax invoice submitted&lt;/target&gt;
                &lt;event&gt;submit tax invoice&lt;/event&gt;
            &lt;/transition&gt;

            &lt;!-- other transitions --&gt;

            &lt;transition happy=&quot;true&quot;&gt;
                &lt;source&gt;tax invoice submitted&lt;/source&gt;

                &lt;!-- Here are the contents of the target transition --&gt;

            &lt;/transition&gt;

            &lt;!-- other transitions --&gt;

        &lt;/transitions&gt;

        &lt;events&gt;

            &lt;!-- other events --&gt;

            &lt;event name=&quot;submit tax invoice&quot; onEnter=&quot;true&quot; command=&quot;Vertex/SubmitPaymentTaxInvoice&quot;/&gt;

            &lt;!-- other events --&gt;

        &lt;/events&gt;

    &lt;/process&gt;

&lt;/statemachine&gt;
```

### Register OMS plugins

{% info_block infoBox &quot;Optional&quot; %}

This step is required only if you want to use invoicing functionality. Make sure `isInvoicingEnabled()` is set to `true` in `VertexConfig.php`.

{% endinfo_block %}

Add OMS plugins to `src/Pyz/Zed/Oms/OmsDependencyProvider.php`:

```php
use SprykerEco\Zed\Vertex\Communication\Plugin\Oms\Command\VertexSubmitPaymentTaxInvoicePlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Oms\VertexOrderRefundedEventListenerPlugin;

# This configuration is necessary for Invoice functionality
protected function extendCommandPlugins(Container $container): Container
{
    $container-&gt;extend(self::COMMAND_PLUGINS, function (CommandCollectionInterface $commandCollection) {
        // ... other command plugins
        $commandCollection-&gt;add(new VertexSubmitPaymentTaxInvoicePlugin(), &apos;Vertex/SubmitPaymentTaxInvoice&apos;);

        return $commandCollection;
    });

    return $container;
}

# This configuration is necessary for Refund functionality
protected function getOmsEventTriggeredListenerPlugins(Container $container): array
{
    return [
        // ... other plugins
        new VertexOrderRefundedEventListenerPlugin(),
    ];
}
```

This configuration of `getOmsEventTriggeredListenerPlugins` method is required to ensure that the correct tax amount will be used during the refund process.

{% info_block infoBox &quot;OMS configuration requirement&quot; %}

The refund functionality will only work if the OMS event is called `refund`.

{% endinfo_block %}

## Next steps

- [Configure Vertex-specific metadata](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/configure-vertex-specific-metadata.html)
- [Migrate from the ACP Vertex app](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/migrate-from-acp-to-vertex.html)</description>
            <pubDate>Wed, 25 Mar 2026 12:21:38 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex.html</guid>
            
            
        </item>
        
        <item>
            <title>AI Foundation Audit Logs</title>
            <description>&lt;p&gt;This document describes how to use audit logging with the AiFoundation module to track and audit AI interactions in your Spryker application.&lt;/p&gt;
&lt;p&gt;The audit logging feature provides comprehensive tracking of all AI interactions, including prompts, responses, token usage, inference time, and metadata. This enables monitoring, compliance, cost tracking, and debugging of AI operations.&lt;/p&gt;
&lt;h2 id=&quot;back-office-audit-logs-page&quot;&gt;Back Office: Audit Logs page&lt;/h2&gt;
&lt;p&gt;After &lt;a href=&quot;#enable-audit-logging&quot;&gt;enabling audit logging&lt;/a&gt;, you can view and analyze AI interaction logs in the Back Office at &lt;strong&gt;Intelligence &amp;gt; Audit Logs&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The Audit Logs page provides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Summary statistics cards&lt;/strong&gt;: Total requests, total tokens consumed, success rate, and average inference time for the filtered dataset.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filterable data table&lt;/strong&gt;: Filter logs by configuration name, status (success/failed), conversation reference, and date range.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Detail drawer&lt;/strong&gt;: Click a row’s prompt to view complete prompt and response text, token breakdown, metadata, and error details.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;navigation-setup&quot;&gt;Navigation setup&lt;/h3&gt;
&lt;p&gt;The AiFoundation module registers its navigation under the &lt;strong&gt;Intelligence&lt;/strong&gt; menu. To include the Audit Logs entry in your project navigation, add the following to &lt;code&gt;config/Zed/navigation.xml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;ai-foundation&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;label&amp;gt;&lt;/span&gt;Intelligence&lt;span class=&quot;nt&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Intelligence&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;icon&amp;gt;&lt;/span&gt;network_intel_node&lt;span class=&quot;nt&quot;&gt;&amp;lt;/icon&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;pages&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;ai-interaction-log&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;label&amp;gt;&lt;/span&gt;Audit Logs&lt;span class=&quot;nt&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Audit Logs&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;bundle&amp;gt;&lt;/span&gt;ai-foundation&lt;span class=&quot;nt&quot;&gt;&amp;lt;/bundle&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;controller&amp;gt;&lt;/span&gt;ai-interaction-log&lt;span class=&quot;nt&quot;&gt;&amp;lt;/controller&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;action&amp;gt;&lt;/span&gt;index&lt;span class=&quot;nt&quot;&gt;&amp;lt;/action&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ai-interaction-log&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/pages&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/ai-foundation&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After updating the navigation XML, rebuild the navigation cache:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;console navigation:cache:remove
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;/h2&gt;
&lt;p&gt;The AiFoundation audit logging system automatically captures detailed information about each AI interaction:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Configuration and Provider Information&lt;/strong&gt;: The AI configuration name, provider, and model used&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prompt and Response Data&lt;/strong&gt;: The user prompt and AI response messages&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Token Usage&lt;/strong&gt;: Input and output token counts for cost tracking&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance Metrics&lt;/strong&gt;: Inference time in milliseconds&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Metadata&lt;/strong&gt;: Tool invocations, errors, and structured schema information&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conversation Tracking&lt;/strong&gt;: Links to conversation references for multi-turn conversations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Status&lt;/strong&gt;: Success or failure status of each interaction&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timestamps&lt;/strong&gt;: Creation timestamps for each logged interaction&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All AI interactions are persisted to the &lt;code&gt;spy_ai_interaction_log&lt;/code&gt; database table and can be queried, analyzed, and audited.&lt;/p&gt;
&lt;h2 id=&quot;architecture&quot;&gt;Architecture&lt;/h2&gt;
&lt;p&gt;The audit logging system uses post-prompt plugins to capture AI interaction data and integrates with the Spryker logging infrastructure. For detailed architecture information, see &lt;a href=&quot;/docs/dg/dev/ai/ai-foundation/ai-foundation-module.html&quot;&gt;AiFoundation module Overview&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;enable-audit-logging&quot;&gt;Enable audit logging&lt;/h2&gt;
&lt;h3 id=&quot;register-the-audit-logger-plugins&quot;&gt;1. Register the audit logger plugins&lt;/h3&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Zed\AiFoundation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Spryker\Zed\AiFoundation\AiFoundationDependencyProvider&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerAiFoundationDependencyProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Spryker\Zed\AiFoundation\Communication\Plugin\AuditLogPostPromptPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Spryker\Zed\AiFoundation\Communication\Plugin\AuditLogPostToolCallPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Spryker\Zed\AiFoundation\Communication\Plugin\Log\AiInteractionHandlerPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiFoundationDependencyProvider&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerAiFoundationDependencyProvider&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * @return array&amp;lt;\Spryker\Zed\AiFoundation\Dependency\Plugin\PostPromptPluginInterface&amp;gt;
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getPostPromptPlugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;array&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AuditLogPostPromptPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;cd&quot;&gt;/**
     * @return array&amp;lt;\Spryker\Zed\AiFoundation\Dependency\Plugin\PostToolCallPluginInterface&amp;gt;
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getPostToolCallPlugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;array&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AuditLogPostToolCallPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * @return array&amp;lt;\Spryker\Shared\Log\Dependency\Plugin\LogHandlerPluginInterface&amp;gt;
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getAiInteractionLogHandlerPlugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;array&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiInteractionHandlerPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;configure-the-audit-logger-in-your-config&quot;&gt;2. Configure the audit logger in your config&lt;/h3&gt;
&lt;p&gt;In your configuration file (for example, &lt;code&gt;config/Shared/config_default.php&lt;/code&gt;), add the &lt;code&gt;AiInteractionAuditLoggerConfigPlugin&lt;/code&gt; to the audit logger plugins:&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Spryker\Shared\Log\LogConstants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Spryker\Zed\AiFoundation\Communication\Plugin\Log\AiInteractionAuditLoggerConfigPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;LogConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;AUDIT_LOGGER_CONFIG_PLUGINS_ZED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// existing plugins...&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;AiInteractionAuditLoggerConfigPlugin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;LogConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;AUDIT_LOGGER_CONFIG_PLUGINS_MERCHANT_PORTAL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// existing plugins...&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;AiInteractionAuditLoggerConfigPlugin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;generate-transfers&quot;&gt;3. Generate transfers&lt;/h3&gt;
&lt;p&gt;Generate the transfer objects for audit logging:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;console transfer:generate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;run-database-migrations&quot;&gt;4. Run database migrations&lt;/h3&gt;
&lt;p&gt;Run the database migrations to create the &lt;code&gt;spy_ai_interaction_log&lt;/code&gt; table:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;console propel:install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;understanding-ai-interaction-log-data&quot;&gt;Understanding AI interaction log data&lt;/h2&gt;
&lt;h3 id=&quot;aiinteractionlog-transfer-properties&quot;&gt;AiInteractionLog transfer properties&lt;/h3&gt;
&lt;p&gt;Each logged AI interaction contains the following information:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;idAiInteractionLog&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;int&lt;/td&gt;
&lt;td&gt;Unique identifier for the log record&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;configurationName&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;AI configuration name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;provider&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;AI provider name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;model&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;AI model name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;prompt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;User prompt sent to the AI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;response&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;AI response message&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputTokens&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;int&lt;/td&gt;
&lt;td&gt;Input token count&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputTokens&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;int&lt;/td&gt;
&lt;td&gt;Output token count&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;conversationReference&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;Conversation reference for multi-turn conversations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inferenceTimeMs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;int&lt;/td&gt;
&lt;td&gt;Inference time in milliseconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isSuccessful&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;bool&lt;/td&gt;
&lt;td&gt;Interaction success status&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;metadata&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;JSON-encoded metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;createdAt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;Timestamp (ISO 8601 format)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;best-practices&quot;&gt;Best practices&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Regular cleanup&lt;/strong&gt;: Implement a periodic cleanup process to archive or delete old audit logs if required by your retention policies&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost tracking&lt;/strong&gt;: Use token counts to monitor and optimize AI usage costs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance monitoring&lt;/strong&gt;: Track inference times to identify slow interactions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error analysis&lt;/strong&gt;: Review failed interactions to improve prompts and error handling&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Metadata inspection&lt;/strong&gt;: Store and analyze metadata to understand tool invocations and structured responses&lt;/li&gt;
&lt;/ol&gt;
</description>
            <pubDate>Wed, 25 Mar 2026 08:44:45 +0000</pubDate>
            <link>https://docs.spryker.com/docs/dg/dev/ai/ai-foundation/ai-foundation-audit-logs.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/dg/dev/ai/ai-foundation/ai-foundation-audit-logs.html</guid>
            
            
        </item>
        
        <item>
            <title>AiFoundation module Overview</title>
            <description>&lt;p&gt;This document describes how to integrate and use the AiFoundation module to interact with various AI providers in your Spryker application. The AiFoundation module provides a unified interface for working with multiple AI providers, such as OpenAI, Anthropic Claude, AWS Bedrock, and others.&lt;/p&gt;
&lt;p&gt;The AiFoundation module uses a Zed-backed architecture where the client provides a simple interface that delegates all processing to the Zed facade. This design enables centralized management of AI configurations, conversation history persistence, and tool execution.&lt;/p&gt;
&lt;h2 id=&quot;architecture&quot;&gt;Architecture&lt;/h2&gt;
&lt;p&gt;The AiFoundation module uses a two-layer architecture:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Client Layer&lt;/strong&gt;: Provides a simple &lt;code&gt;AiFoundationClientInterface&lt;/code&gt; that serves as the entry point for AI interactions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zed Layer&lt;/strong&gt;: Contains the &lt;code&gt;AiFoundationFacade&lt;/code&gt; that handles all business logic including:
&lt;ul&gt;
&lt;li&gt;AI configuration resolution&lt;/li&gt;
&lt;li&gt;Vendor adapter plugin delegation&lt;/li&gt;
&lt;li&gt;Conversation history persistence and retrieval&lt;/li&gt;
&lt;li&gt;Tool execution and invocation tracking&lt;/li&gt;
&lt;li&gt;Structured response validation and mapping&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The client delegates all processing to the Zed facade through a request stub, ensuring centralized management of AI operations and database persistence.&lt;/p&gt;
&lt;h2 id=&quot;install-the-aifoundation-module&quot;&gt;Install the AiFoundation module&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Require the package:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;composer require spryker/ai-foundation
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Generate transfers:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;console transfer:generate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;configure-ai-providers&quot;&gt;Configure AI providers&lt;/h2&gt;
&lt;p&gt;Configure AI providers in a dedicated configuration file. The module uses the &lt;code&gt;AI_CONFIGURATIONS&lt;/code&gt; constant to define one or more AI configurations.&lt;/p&gt;
&lt;section class=&apos;info-block &apos;&gt;&lt;i class=&apos;info-block__icon icon-info&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Best practice&lt;/div&gt;
&lt;p&gt;Create a separate configuration file for AI settings to keep your configuration organized and maintainable.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;section class=&apos;info-block info-block--warning&apos;&gt;&lt;i class=&apos;info-block__icon icon-warning&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Security&lt;/div&gt;
&lt;p&gt;Store API keys as environment variables, not in configuration files. For Spryker Cloud, use the parameter store to manage sensitive credentials. For details, see &lt;a href=&quot;/docs/ca/dev/add-variables-in-the-parameter-store.html&quot;&gt;Add variables in the parameter store&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a new configuration file &lt;code&gt;config/Shared/config_ai.php&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Spryker\Shared\AiFoundation\AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// AI provider configurations&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;AI_CONFIGURATIONS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Your AI configurations will be defined here&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Include the AI configuration file in your main configuration file (for example, &lt;code&gt;config/Shared/config_default.php&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;config_ai.php&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Alternatively, you can define AI configurations directly in &lt;code&gt;config/Shared/config_default.php&lt;/code&gt; if you prefer a single configuration file approach.&lt;/p&gt;
&lt;h3 id=&quot;configuration-structure&quot;&gt;Configuration structure&lt;/h3&gt;
&lt;p&gt;Each AI configuration requires:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;provider_name&lt;/code&gt;: The AI provider identifier (required)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;provider_config&lt;/code&gt;: Provider-specific configuration (required)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;system_prompt&lt;/code&gt;: Default system prompt for the AI provider&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;default-configuration&quot;&gt;Default configuration&lt;/h3&gt;
&lt;p&gt;The module automatically uses the configuration named &lt;code&gt;AI_CONFIGURATION_DEFAULT&lt;/code&gt; when you do not specify a configuration in the &lt;code&gt;PromptRequest&lt;/code&gt;. Define at least one default configuration:&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Spryker\Shared\AiFoundation\AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;AI_CONFIGURATIONS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;AI_CONFIGURATION_DEFAULT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;provider_name&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PROVIDER_OPENAI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;provider_config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;key&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;OPENAI_API_KEY&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;model&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;gpt-4o&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Resolved at runtime from Configuration Management&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;system_prompt&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;CONFIGURATION_REFERENCE_PREFIX&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;ai_commerce:backoffice_assistant:general:system_prompt&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Any string value prefixed with &lt;code&gt;configuration::&lt;/code&gt; (&lt;code&gt;AiFoundationConstants::CONFIGURATION_REFERENCE_PREFIX&lt;/code&gt;) is resolved at runtime via the &lt;a href=&quot;/docs/dg/dev/backend-development/configuration-management.html&quot;&gt;Configuration Management&lt;/a&gt; module.
This lets admin users update AI settings—model, API key, system prompt—from the Back Office without a code deployment.&lt;/p&gt;
&lt;h2 id=&quot;provider-configuration-examples&quot;&gt;Provider configuration examples&lt;/h2&gt;
&lt;h3 id=&quot;openai&quot;&gt;OpenAI&lt;/h3&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s1&quot;&gt;&apos;openai-config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_name&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PROVIDER_OPENAI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;key&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;OPENAI_API_KEY&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;model&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;gpt-4o&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;parameters&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// optional&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;httpOptions&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// optional&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;timeout&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;connectTimeout&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;headers&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;system_prompt&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;You are a helpful assistant.&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// optional&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;anthropic-claude&quot;&gt;Anthropic Claude&lt;/h3&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s1&quot;&gt;&apos;anthropic-config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_name&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PROVIDER_ANTHROPIC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;key&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;ANTHROPIC_API_KEY&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;model&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;claude-sonnet-4-20250514&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;version&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;2023-06-01&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// optional&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;max_tokens&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8192&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// optional&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;parameters&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// optional&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;httpOptions&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// optional&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;timeout&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;aws-bedrock&quot;&gt;AWS Bedrock&lt;/h3&gt;
&lt;p&gt;AWS Bedrock requires a &lt;code&gt;system_prompt&lt;/code&gt; configuration. AWS credentials are automatically loaded from environment variables: &lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt;, &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt;, and &lt;code&gt;AWS_SESSION_TOKEN&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s1&quot;&gt;&apos;bedrock-config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_name&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PROVIDER_BEDROCK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;model&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;eu.anthropic.claude-sonnet-4-20250514-v1:0&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;bedrockRuntimeClient&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;region&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;eu-west-1&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;version&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;latest&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// optional&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;system_prompt&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;You are a helpful assistant.&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required for Bedrock&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;ollama-localself-hosted&quot;&gt;Ollama (local/self-hosted)&lt;/h3&gt;
&lt;p&gt;If Ollama runs outside the Docker SDK on macOS, use &lt;code&gt;http://host.docker.internal:11434/api&lt;/code&gt; as the URL to access the host machine from within Docker containers.&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s1&quot;&gt;&apos;ollama-config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_name&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PROVIDER_OLLAMA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;url&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;http://host.docker.internal:11434/api&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required - use host.docker.internal for Mac when Ollama runs outside Docker&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;model&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;llama3.2&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;parameters&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// optional&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;httpOptions&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// optional&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;timeout&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;connectTimeout&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h4 id=&quot;run-ollama-with-docker-sdk&quot;&gt;Run Ollama with Docker SDK&lt;/h4&gt;
&lt;p&gt;To run Ollama as a service within the Spryker Docker SDK:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create an &lt;code&gt;ollama.yml&lt;/code&gt; file in your project root:&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;3.8&apos;&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ollama&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ollama/ollama:latest&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;OLLAMA_HOST&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;0.0.0.0:11435&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./data/tmp/ollama_data:/root/.ollama&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;private&lt;/span&gt;
            &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;public&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reference the Ollama compose file in your &lt;code&gt;deploy.dev.yml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;compose&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;yamls&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;./ollama.yml&apos;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update your AI configuration to use the Ollama service URL:&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s1&quot;&gt;&apos;ollama-config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_name&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PROVIDER_OLLAMA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;url&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;http://ollama:11435/api&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// use service name when running inside Docker SDK&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;model&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;llama3.2&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the changes:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker/sdk boot deploy.dev.yml
docker/sdk up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pull the required Ollama model:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker/sdk cli &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; ollama ollama pull llama3.2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The Ollama data is stored in the &lt;code&gt;./data/tmp/ollama_data&lt;/code&gt; directory, which you should exclude from version control (.gitignore or .dockerignore).&lt;/p&gt;
&lt;h3 id=&quot;google-gemini&quot;&gt;Google Gemini&lt;/h3&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s1&quot;&gt;&apos;gemini-config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_name&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PROVIDER_GEMINI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;key&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;GEMINI_API_KEY&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;model&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;gemini-2.0-flash&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;parameters&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// optional&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;deepseek&quot;&gt;Deepseek&lt;/h3&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s1&quot;&gt;&apos;deepseek-config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_name&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PROVIDER_DEEPSEEK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;key&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;DEEPSEEK_API_KEY&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;model&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;deepseek-chat&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;parameters&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// optional&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;huggingface&quot;&gt;HuggingFace&lt;/h3&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s1&quot;&gt;&apos;huggingface-config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_name&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PROVIDER_HUGGINGFACE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;key&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;HUGGINGFACE_API_KEY&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;model&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;meta-llama/Llama-3.3-70B-Instruct&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;parameters&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// optional&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;mistral-ai&quot;&gt;Mistral AI&lt;/h3&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s1&quot;&gt;&apos;mistral-config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_name&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PROVIDER_MISTRAL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;key&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;MISTRAL_API_KEY&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;model&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;mistral-large-latest&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;parameters&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// optional&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;xai-grok&quot;&gt;xAI Grok&lt;/h3&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s1&quot;&gt;&apos;grok-config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_name&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PROVIDER_GROK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;key&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;XAI_API_KEY&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;model&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;grok-2-latest&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;parameters&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// optional&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;azure-openai&quot;&gt;Azure OpenAI&lt;/h3&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s1&quot;&gt;&apos;azure-openai-config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_name&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PROVIDER_AZURE_OPEN_AI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;provider_config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;key&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;AZURE_OPENAI_API_KEY&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;endpoint&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;https://your-resource.openai.azure.com&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;model&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;your-deployment-name&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;version&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;2024-02-01&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// optional&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;parameters&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// optional&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;use-the-aifoundation-facade&quot;&gt;Use the AiFoundation facade&lt;/h2&gt;
&lt;h3 id=&quot;basic-usage&quot;&gt;Basic usage&lt;/h3&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Zed\YourModule\Business&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Generated\Shared\Transfer\PromptMessageTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Generated\Shared\Transfer\PromptRequestTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Spryker\Zed\AiFoundation\Business\AiFoundationFacadeInterface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;YourBusinessModel&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;AiFoundationFacadeInterface&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$aiFoundationFacade&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;generateContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$userMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$promptRequest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PromptRequestTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setPromptMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PromptMessageTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$userMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aiFoundationFacade&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;prompt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$promptRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;using-a-specific-configuration&quot;&gt;Using a specific configuration&lt;/h3&gt;
&lt;p&gt;Specify a configuration name to use a configuration other than the default:&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$promptRequest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PromptRequestTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setAiConfigurationName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;anthropic-config&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setPromptMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PromptMessageTransfer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Explain Spryker modules&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aiFoundationFacade&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;prompt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$promptRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;multiple-configurations-example&quot;&gt;Multiple configurations example&lt;/h3&gt;
&lt;p&gt;Configure multiple AI providers for different use cases in your application:&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Spryker\Shared\AiFoundation\AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;AI_CONFIGURATIONS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;AI_CONFIGURATION_DEFAULT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;provider_name&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PROVIDER_OPENAI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;provider_config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;key&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;OPENAI_API_KEY&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;model&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;gpt-4o&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;fast-responses&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;provider_name&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiFoundationConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PROVIDER_OPENAI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;provider_config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;key&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;OPENAI_API_KEY&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;model&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;gpt-4o-mini&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;system_prompt&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Provide concise, brief responses.&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;available-provider-constants&quot;&gt;Available provider constants&lt;/h2&gt;
&lt;p&gt;The module provides the following provider constants in &lt;code&gt;AiFoundationConstants&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PROVIDER_OPENAI&lt;/code&gt; - OpenAI (ChatGPT)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PROVIDER_ANTHROPIC&lt;/code&gt; - Anthropic Claude&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PROVIDER_BEDROCK&lt;/code&gt; - AWS Bedrock Runtime&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PROVIDER_GEMINI&lt;/code&gt; - Google Gemini&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PROVIDER_DEEPSEEK&lt;/code&gt; - Deepseek AI&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PROVIDER_HUGGINGFACE&lt;/code&gt; - HuggingFace&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PROVIDER_MISTRAL&lt;/code&gt; - Mistral AI&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PROVIDER_OLLAMA&lt;/code&gt; - Ollama (local/self-hosted)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PROVIDER_GROK&lt;/code&gt; - xAI Grok&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PROVIDER_AZURE_OPEN_AI&lt;/code&gt; - Azure OpenAI&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;transfer-objects&quot;&gt;Transfer objects&lt;/h2&gt;
&lt;h3 id=&quot;promptrequest&quot;&gt;PromptRequest&lt;/h3&gt;
&lt;p&gt;This transfer contains the request data for AI interaction:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;promptMessage&lt;/code&gt; (PromptMessage, required): The message to send to the AI&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aiConfigurationName&lt;/code&gt; (string, optional): The configuration name to use. If not provided, uses &lt;code&gt;AI_CONFIGURATION_DEFAULT&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;structuredMessage&lt;/code&gt; (object, optional): A Transfer object that defines the expected response structure for structured responses&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toolSetName&lt;/code&gt; (string[], optional): Array of tool set names to make available to the AI. For details, see &lt;a href=&quot;/docs/dg/dev/ai/ai-foundation/ai-foundation-tool-support.html&quot;&gt;Use AI tools with the AiFoundation module&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;conversationReference&lt;/code&gt; (string, optional): Unique identifier for multi-turn conversations. When provided, the message is persisted in conversation history and previous messages are automatically included in the request context. For details, see &lt;a href=&quot;/docs/dg/dev/ai/ai-foundation/ai-foundation-conversation-history.html&quot;&gt;Manage conversation history with the AiFoundation module&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maxRetries&lt;/code&gt; (int, optional): Maximum number of retry attempts for failed requests. Default is 0&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;promptmessage&quot;&gt;PromptMessage&lt;/h3&gt;
&lt;p&gt;This transfer represents a message in the conversation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;content&lt;/code&gt; (string): The text content of the message&lt;/li&gt;
&lt;li&gt;&lt;code&gt;contentData&lt;/code&gt; (array, optional): Additional structured data&lt;/li&gt;
&lt;li&gt;&lt;code&gt;attachments&lt;/code&gt; (Attachment[], optional): File or image attachments&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;promptresponse&quot;&gt;PromptResponse&lt;/h3&gt;
&lt;p&gt;This transfer contains the AI response:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;message&lt;/code&gt; (PromptMessage): The AI’s response message&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isSuccessful&lt;/code&gt; (bool): Whether the request was successful&lt;/li&gt;
&lt;li&gt;&lt;code&gt;errors&lt;/code&gt; (array, optional): Array of error messages if the request failed&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toolInvocations&lt;/code&gt; (ToolInvocation[], optional): Array of tool invocations made by the AI during response generation&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;attachment&quot;&gt;Attachment&lt;/h3&gt;
&lt;p&gt;This transfer represents a file or image attachment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;type&lt;/code&gt; (string): Type of attachment (use &lt;code&gt;AiFoundationConstants::ATTACHMENT_TYPE_IMAGE&lt;/code&gt; or &lt;code&gt;ATTACHMENT_TYPE_DOCUMENT&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;content&lt;/code&gt; (string): The content (URL or Base64-encoded data)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;contentType&lt;/code&gt; (string): Content type format (use &lt;code&gt;AiFoundationConstants::ATTACHMENT_CONTENT_TYPE_URL&lt;/code&gt; or &lt;code&gt;ATTACHMENT_CONTENT_TYPE_BASE64&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mediaType&lt;/code&gt; (string): MIME type (for example, &lt;code&gt;image/png&lt;/code&gt;, &lt;code&gt;application/pdf&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;toolinvocation&quot;&gt;ToolInvocation&lt;/h3&gt;
&lt;p&gt;This transfer contains information about a tool invocation made by the AI:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt; (string): The name of the tool that was invoked&lt;/li&gt;
&lt;li&gt;&lt;code&gt;arguments&lt;/code&gt; (array): The arguments passed to the tool&lt;/li&gt;
&lt;li&gt;&lt;code&gt;result&lt;/code&gt; (string): The result returned by the tool execution&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;structuredmessage&quot;&gt;StructuredMessage&lt;/h3&gt;
&lt;p&gt;Define the expected structure (&lt;code&gt;structuredMessage&lt;/code&gt; property) of the AI response for structured responses. This is a Spryker Transfer object that you can customize based on your requirements.&lt;/p&gt;
&lt;h3 id=&quot;conversation-history&quot;&gt;Conversation History&lt;/h3&gt;
&lt;p&gt;Conversation history is created by &lt;code&gt;conversationReference&lt;/code&gt; and persisted in the database using the &lt;code&gt;spy_ai_conversation_history&lt;/code&gt; table. When you provide a &lt;code&gt;conversationReference&lt;/code&gt; in a prompt request, all messages are automatically stored and previous messages are retrieved to maintain conversation context. For complete details, see &lt;a href=&quot;/docs/dg/dev/ai/ai-foundation/ai-foundation-conversation-history.html&quot;&gt;Manage conversation history with the AiFoundation module&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;about-neuronai-framework&quot;&gt;About NeuronAI framework&lt;/h2&gt;
&lt;p&gt;The AiFoundation module uses the &lt;a href=&quot;https://docs.neuron-ai.dev/&quot;&gt;NeuronAI PHP agentic framework&lt;/a&gt; under the hood. NeuronAI provides the foundational infrastructure for AI provider integrations.&lt;/p&gt;
&lt;p&gt;The Spryker AiFoundation client is designed for simple use cases where you need to send prompts to AI providers and receive responses. This covers most common AI integration scenarios in e-commerce applications.&lt;/p&gt;
&lt;p&gt;For advanced agentic solutions that require complex workflows, multi-agent systems, or custom AI behaviors, you can use the &lt;a href=&quot;https://docs.neuron-ai.dev/&quot;&gt;NeuronAI framework&lt;/a&gt; directly in your project code. However, note that Spryker does not officially support direct usage of NeuronAI APIs outside of the AiFoundation module. If you choose to use NeuronAI directly, you are responsible for maintenance and compatibility with future versions.&lt;/p&gt;
</description>
            <pubDate>Wed, 25 Mar 2026 08:31:12 +0000</pubDate>
            <link>https://docs.spryker.com/docs/dg/dev/ai/ai-foundation/ai-foundation-module.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/dg/dev/ai/ai-foundation/ai-foundation-module.html</guid>
            
            
        </item>
        
        <item>
            <title>Warehouse Management System</title>
            <description>The *Warehouse Management System* capability lets you create and manage warehouses and their stock.

The capability consists of the Demo Shop and additional features. The Demo Shop includes warehouse and inventory
management for running a regular shop, as well as marketplace functionality for creating virtual warehouses per 
merchant and managing their stock. The additional features support omnichannel fulfillment operations.

## Demo shop

The Demo Shop provides the core warehouse and inventory management features, including marketplace functionality for managing merchant-specific stock:

- [Inventory Management feature overview](/docs/pbc/all/warehouse-management-system/latest/base-shop/inventory-management-feature-overview.html) - manage warehouses, stock quantities, and product availability across stores.
- [Availability Notification feature overview](/docs/pbc/all/warehouse-management-system/latest/base-shop/availability-notification-feature-overview.html) - let customers subscribe to back-in-stock notifications for out-of-stock products.
- [Product Availability Display feature overview](/docs/pbc/all/warehouse-management-system/latest/base-shop/product-availability-display-feature-overview.html) - show stock quantities and availability status on product pages and in carts.
- [Manage in the Back Office](/docs/pbc/all/warehouse-management-system/latest/base-shop/manage-in-the-back-office/manage-warehouses-in-the-back-office.html) - create and edit warehouses, check product availability, and manage stock.
- [Import and export data](/docs/pbc/all/warehouse-management-system/latest/base-shop/import-and-export-data/warehouse-management-system-data-import.html) - import warehouses, warehouse addresses, store assignments, and product stock.
- [Marketplace Inventory Management feature overview](/docs/pbc/all/warehouse-management-system/latest/marketplace/marketplace-inventory-management-feature-overview.html) - create virtual warehouses per merchant and manage merchant product offer stock.

## Additional features

Unified Commerce features support omnichannel fulfillment operations:

- [Fulfillment App overview](/docs/pbc/all/warehouse-management-system/latest/unified-commerce/fulfillment-app-overview.html) - pick and pack orders using the Fulfillment App.
- [Warehouse Picking feature overview](/docs/pbc/all/warehouse-management-system/latest/unified-commerce/warehouse-picking-feature-overview.html) - generate pick lists to streamline warehouse order fulfillment.
- [Warehouse User Management feature overview](/docs/pbc/all/warehouse-management-system/latest/unified-commerce/warehouse-user-management-feature-overview.html) - assign warehouse users to specific warehouses for picking operations.

</description>
            <pubDate>Mon, 23 Mar 2026 16:09:31 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/warehouse-management-system/latest/warehouse-management-system.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/warehouse-management-system/latest/warehouse-management-system.html</guid>
            
            
        </item>
        
    </channel>
</rss>
