<?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>Fri, 06 Feb 2026 18:04:17 +0000</lastBuildDate>
        <generator>Jekyll v4.2.2</generator>
        
        
        <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;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;Access the CLI using &lt;code&gt;docker/sdk cli&lt;/code&gt;, then 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;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;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;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 current deploy file, for example &lt;code&gt;deploy.dev.yml&lt;/code&gt;, under the &lt;code&gt;docker&lt;/code&gt; section:&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;docker&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&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;p&gt;The container name is composed of the Docker deploy file namespace and the service name.
Example: &lt;code&gt;spryker_b2b_marketplace_ollama_1&lt;/code&gt;&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 &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;spryker_b2b_marketplace_ollama_1 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;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;Local override of LLM settings&lt;/div&gt;
&lt;p&gt;To set up your local development settings and override the API key of your chosen provider:&lt;/p&gt;
&lt;p&gt;Copy your provider’s configuration into a git-ignored local configuration file, such as &lt;code&gt;config/Shared/config_local.php&lt;/code&gt;, and define your modifications.&lt;/p&gt;
&lt;p&gt;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;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;s1&quot;&gt;&apos;my-secret-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;/div&gt;&lt;/section&gt;
&lt;h2 id=&quot;use-the-aifoundation-client&quot;&gt;Use the AiFoundation client&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\Client\AiFoundation\AiFoundationClientInterface&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;AiFoundationClientInterface&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$aiFoundationClient&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;aiFoundationClient&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;aiFoundationClient&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;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;h2 id=&quot;roadmap&quot;&gt;Roadmap&lt;/h2&gt;
&lt;p&gt;The following capabilities are planned for future releases of the AiFoundation module:&lt;/p&gt;
&lt;h3 id=&quot;chat-history-capabilities&quot;&gt;Chat history capabilities&lt;/h3&gt;
&lt;p&gt;Support for maintaining conversation context across multiple interactions. This will enable multi-turn conversations where the AI can reference previous messages, maintain state, and provide more contextually relevant responses throughout an extended dialogue.&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>Fri, 06 Feb 2026 18:03:08 +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>Release notes for spryker-php image</title>
            <description>This document describes the changes that have been recently released.
For additional support with this content, contact our support.
If you found a new security vulnerability, contact us at **security@spryker.com**.

## Release notes for spryker-php 20260206.0

### Improvements

- Added support for Alpine 3.23
- Upgraded Composer to 2.9.3
- Upgraded Tideways to 5.32.0
- Upgraded NewRelic to the latest

## Security fixes by image

This section details security vulnerabilities that have been addressed in specific Docker images.

### spryker/php:8.4-alpine3.22

- **CVE-2025-15468**: If an application using the SSL_CIPHER_find() function in a QUIC protocol client or server receives an unknown cipher suite from the peer, a NULL dereference occurs.

- **CVE-2025-69421**: Processing a malformed PKCS#12 file can trigger a NULL pointer dereference in the PKCS12_item_decrypt_d2i_ex() function.

- **CVE-2026-22796**: A type confusion vulnerability exists in the signature verification of signed PKCS#7 data where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing malformed PKCS#7 data.

- **CVE-2026-15467**: Parsing CMS AuthEnvelopedData message with maliciously crafted AEAD parameters can trigger a stack buffer overflow.

- **CVE-2025-69420**: A type confusion vulnerability exists in the TimeStamp Response verification code where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing a malformed TimeStamp Response file.

- **CVE-2025-69418**: When using the low-level OCB API directly with AES-NI or other hardware-accelerated code paths, inputs whose length is not a multiple of 16 bytes can leave the final partial block unencrypted and unauthenticated.

- **CVE-2026-22801**: LIBPNG is a reference library for use in applications that read, create, and manipulate PNG (Portable Network Graphics) raster image files. From 1.6.26 to 1.6.53, there is an integer truncation in the libpng simplified write API functions png_write_image_16bit and png_write_image_8bit causes heap buffer over-read when the caller provides a negative row stride (for bottom-up image layouts) or a stride exceeding 65535 bytes. The bug was introduced in libpng 1.6.26 (October 2016) by casts added to silence compiler warnings on 16-bit systems. This vulnerability is fixed in 1.6.54.

- **CVE-2026-22695**: A flaw was found in Podman. In a Containerfile or Podman, data written to RUN --mount=type=bind mounts during the podman build is not discarded. This issue can lead to files created within the container appearing in the temporary build context directory on the host, leaving the created files accessible.

- **CVE-2025-66199**: A TLS 1.3 connection using certificate compression can be forced to allocate a large buffer before decompression without checking against the configured certificate size limit.

- **CVE-2025-68160**: Writing large, newline-free data into a BIO chain using the line-buffering filter where the next BIO performs short writes can trigger a heap-based out-of-bounds write.

- **CVE-2025-69419**: Calling PKCS12_get_friendlyname() function on a maliciously crafted PKCS#12 file with a BMPString (UTF-16BE) friendly name containing non-ASCII BMP code point can trigger a one byte write before the allocated buffer.

- **CVE-2026-22795**: An invalid or NULL pointer dereference can happen in an application processing a malformed PKCS#12 file.

- **CVE-2025-61730**: During the TLS 1.3 handshake if multiple messages are sent in records that span encryption level boundaries (for instance the Client Hello and Encrypted Extensions messages), the subsequent messages may be processed before the encryption level changes. This can cause some minor information disclosure if a network-local attacker can inject messages during the handshake.

- **CVE-2025-11187**: PBMAC1 parameters in PKCS#12 files are missing validation which can trigger a stack-based buffer overflow, invalid pointer or NULL pointer dereference during MAC verification.

- **CVE-2025-15469**: The &apos;openssl dgst&apos; command-line tool silently truncates input data to 16MB when using one-shot signing algorithms and reports success instead of an error.

- **CVE-2026-24515**: In libexpat before 2.7.4, XML_ExternalEntityParserCreate does not copy unknown encoding handler user data.

### spryker/php:8.3-alpine3.22

- **CVE-2025-15468**: If an application using the SSL_CIPHER_find() function in a QUIC protocol client or server receives an unknown cipher suite from the peer, a NULL dereference occurs.

- **CVE-2026-24515**: In libexpat before 2.7.4, XML_ExternalEntityParserCreate does not copy unknown encoding handler user data.

- **CVE-2025-69421**: Processing a malformed PKCS#12 file can trigger a NULL pointer dereference in the PKCS12_item_decrypt_d2i_ex() function.

- **CVE-2026-22796**: A type confusion vulnerability exists in the signature verification of signed PKCS#7 data where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing malformed PKCS#7 data.

- **CVE-2026-15467**: Parsing CMS AuthEnvelopedData message with maliciously crafted AEAD parameters can trigger a stack buffer overflow.

- **CVE-2025-69420**: A type confusion vulnerability exists in the TimeStamp Response verification code where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing a malformed TimeStamp Response file.

- **CVE-2025-69418**: When using the low-level OCB API directly with AES-NI or other hardware-accelerated code paths, inputs whose length is not a multiple of 16 bytes can leave the final partial block unencrypted and unauthenticated.

- **CVE-2026-22801**: LIBPNG is a reference library for use in applications that read, create, and manipulate PNG (Portable Network Graphics) raster image files. From 1.6.26 to 1.6.53, there is an integer truncation in the libpng simplified write API functions png_write_image_16bit and png_write_image_8bit causes heap buffer over-read when the caller provides a negative row stride (for bottom-up image layouts) or a stride exceeding 65535 bytes. The bug was introduced in libpng 1.6.26 (October 2016) by casts added to silence compiler warnings on 16-bit systems. This vulnerability is fixed in 1.6.54.

- **CVE-2026-22695**: A flaw was found in Podman. In a Containerfile or Podman, data written to RUN --mount=type=bind mounts during the podman build is not discarded. This issue can lead to files created within the container appearing in the temporary build context directory on the host, leaving the created files accessible.

- **CVE-2025-66199**: A TLS 1.3 connection using certificate compression can be forced to allocate a large buffer before decompression without checking against the configured certificate size limit.

- **CVE-2025-68160**: Writing large, newline-free data into a BIO chain using the line-buffering filter where the next BIO performs short writes can trigger a heap-based out-of-bounds write.

- **CVE-2025-69419**: Calling PKCS12_get_friendlyname() function on a maliciously crafted PKCS#12 file with a BMPString (UTF-16BE) friendly name containing non-ASCII BMP code point can trigger a one byte write before the allocated buffer.

- **CVE-2026-22795**: An invalid or NULL pointer dereference can happen in an application processing a malformed PKCS#12 file.

- **CVE-2025-61730**: During the TLS 1.3 handshake if multiple messages are sent in records that span encryption level boundaries (for instance the Client Hello and Encrypted Extensions messages), the subsequent messages may be processed before the encryption level changes. This can cause some minor information disclosure if a network-local attacker can inject messages during the handshake.

- **CVE-2025-11187**: PBMAC1 parameters in PKCS#12 files are missing validation which can trigger a stack-based buffer overflow, invalid pointer or NULL pointer dereference during MAC verification.

- **CVE-2025-15469**: The &apos;openssl dgst&apos; command-line tool silently truncates input data to 16MB when using one-shot signing algorithms and reports success instead of an error.

### spryker/php:8.2-alpine3.22

- **CVE-2025-15468**: If an application using the SSL_CIPHER_find() function in a QUIC protocol client or server receives an unknown cipher suite from the peer, a NULL dereference occurs.

- **CVE-2025-69421**: Processing a malformed PKCS#12 file can trigger a NULL pointer dereference in the PKCS12_item_decrypt_d2i_ex() function.

- **CVE-2026-22796**: A type confusion vulnerability exists in the signature verification of signed PKCS#7 data where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing malformed PKCS#7 data.

- **CVE-2026-15467**: Parsing CMS AuthEnvelopedData message with maliciously crafted AEAD parameters can trigger a stack buffer overflow.

- **CVE-2025-69420**: A type confusion vulnerability exists in the TimeStamp Response verification code where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing a malformed TimeStamp Response file.

- **CVE-2025-69418**: When using the low-level OCB API directly with AES-NI or other hardware-accelerated code paths, inputs whose length is not a multiple of 16 bytes can leave the final partial block unencrypted and unauthenticated.

- **CVE-2026-22801**: LIBPNG is a reference library for use in applications that read, create, and manipulate PNG (Portable Network Graphics) raster image files. From 1.6.26 to 1.6.53, there is an integer truncation in the libpng simplified write API functions png_write_image_16bit and png_write_image_8bit causes heap buffer over-read when the caller provides a negative row stride (for bottom-up image layouts) or a stride exceeding 65535 bytes. The bug was introduced in libpng 1.6.26 (October 2016) by casts added to silence compiler warnings on 16-bit systems. This vulnerability is fixed in 1.6.54.

- **CVE-2026-22695**: A flaw was found in Podman. In a Containerfile or Podman, data written to RUN --mount=type=bind mounts during the podman build is not discarded. This issue can lead to files created within the container appearing in the temporary build context directory on the host, leaving the created files accessible.

- **CVE-2025-66199**: A TLS 1.3 connection using certificate compression can be forced to allocate a large buffer before decompression without checking against the configured certificate size limit.

- **CVE-2025-68160**: Writing large, newline-free data into a BIO chain using the line-buffering filter where the next BIO performs short writes can trigger a heap-based out-of-bounds write.

- **CVE-2025-69419**: Calling PKCS12_get_friendlyname() function on a maliciously crafted PKCS#12 file with a BMPString (UTF-16BE) friendly name containing non-ASCII BMP code point can trigger a one byte write before the allocated buffer.

- **CVE-2026-22795**: An invalid or NULL pointer dereference can happen in an application processing a malformed PKCS#12 file.

- **CVE-2025-11187**: PBMAC1 parameters in PKCS#12 files are missing validation which can trigger a stack-based buffer overflow, invalid pointer or NULL pointer dereference during MAC verification.

- **CVE-2025-15469**: The &apos;openssl dgst&apos; command-line tool silently truncates input data to 16MB when using one-shot signing algorithms and reports success instead of an error.

### spryker/php:8.4-alpine3.21

- **CVE-2025-15468**: If an application using the SSL_CIPHER_find() function in a QUIC protocol client or server receives an unknown cipher suite from the peer, a NULL dereference occurs.

- **CVE-2025-69421**: Processing a malformed PKCS#12 file can trigger a NULL pointer dereference in the PKCS12_item_decrypt_d2i_ex() function.

- **CVE-2026-22796**: A type confusion vulnerability exists in the signature verification of signed PKCS#7 data where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing malformed PKCS#7 data.

- **CVE-2026-15467**: Parsing CMS AuthEnvelopedData message with maliciously crafted AEAD parameters can trigger a stack buffer overflow.

- **CVE-2025-69420**: A type confusion vulnerability exists in the TimeStamp Response verification code where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing a malformed TimeStamp Response file.

- **CVE-2025-69418**: When using the low-level OCB API directly with AES-NI or other hardware-accelerated code paths, inputs whose length is not a multiple of 16 bytes can leave the final partial block unencrypted and unauthenticated.

- **CVE-2026-22801**: LIBPNG is a reference library for use in applications that read, create, and manipulate PNG (Portable Network Graphics) raster image files. From 1.6.26 to 1.6.53, there is an integer truncation in the libpng simplified write API functions png_write_image_16bit and png_write_image_8bit causes heap buffer over-read when the caller provides a negative row stride (for bottom-up image layouts) or a stride exceeding 65535 bytes. The bug was introduced in libpng 1.6.26 (October 2016) by casts added to silence compiler warnings on 16-bit systems. This vulnerability is fixed in 1.6.54.

- **CVE-2026-22695**: A flaw was found in Podman. In a Containerfile or Podman, data written to RUN --mount=type=bind mounts during the podman build is not discarded. This issue can lead to files created within the container appearing in the temporary build context directory on the host, leaving the created files accessible.

- **CVE-2025-66199**: A TLS 1.3 connection using certificate compression can be forced to allocate a large buffer before decompression without checking against the configured certificate size limit.

- **CVE-2025-14178**: A heap buffer overflow occurs in array_merge() when the total element count of packed arrays exceeds 32-bit limits or HT_MAX_SIZE, due to an integer overflow in the precomputation of element counts using zend_hash_num_elements(). This may lead to memory corruption or crashes and affect the integrity and availability of the target server.

- **CVE-2025-68160**: Writing large, newline-free data into a BIO chain using the line-buffering filter where the next BIO performs short writes can trigger a heap-based out-of-bounds write.

- **CVE-2025-61726**: The net/url package does not set a limit on the number of query parameters in a query. While the maximum size of query parameters in URLs is generally limited by the maximum request header size, the net/http.Request.ParseForm method can parse large URL-encoded forms. Parsing a large form containing many unique query parameters can cause excessive memory consumption.

- **CVE-2025-69419**: Calling PKCS12_get_friendlyname() function on a maliciously crafted PKCS#12 file with a BMPString (UTF-16BE) friendly name containing non-ASCII BMP code point can trigger a one byte write before the allocated buffer.

- **CVE-2026-22795**: An invalid or NULL pointer dereference can happen in an application processing a malformed PKCS#12 file.

- **CVE-2025-14177**: The getimagesize() function may leak uninitialized heap memory into the APPn segments (for example, APP1) when reading images in multi-chunk mode (such as via php://filter). This occurs due to a bug in php_read_stream_all_chunks() that overwrites the buffer without advancing the pointer, leaving tail bytes uninitialized. This may lead to information disclosure of sensitive heap data and affect the confidentiality of the target server.

- **CVE-2025-14180**: Apport 2.13 through 2.20.7 does not properly handle crashes originating from a PID namespace allowing local users to create certain files as root which an attacker could leverage to perform a denial of service via resource exhaustion or possibly gain root privileges

### spryker/php:8.3-alpine3.21

- **CVE-2025-15468**: If an application using the SSL_CIPHER_find() function in a QUIC protocol client or server receives an unknown cipher suite from the peer, a NULL dereference occurs.

- **CVE-2025-69421**: Processing a malformed PKCS#12 file can trigger a NULL pointer dereference in the PKCS12_item_decrypt_d2i_ex() function.

- **CVE-2026-22796**: A type confusion vulnerability exists in the signature verification of signed PKCS#7 data where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing malformed PKCS#7 data.

- **CVE-2026-15467**: Parsing CMS AuthEnvelopedData message with maliciously crafted AEAD parameters can trigger a stack buffer overflow.

- **CVE-2025-69420**: A type confusion vulnerability exists in the TimeStamp Response verification code where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing a malformed TimeStamp Response file.

- **CVE-2025-69418**: When using the low-level OCB API directly with AES-NI or other hardware-accelerated code paths, inputs whose length is not a multiple of 16 bytes can leave the final partial block unencrypted and unauthenticated.

- **CVE-2026-22801**: LIBPNG is a reference library for use in applications that read, create, and manipulate PNG (Portable Network Graphics) raster image files. From 1.6.26 to 1.6.53, there is an integer truncation in the libpng simplified write API functions png_write_image_16bit and png_write_image_8bit causes heap buffer over-read when the caller provides a negative row stride (for bottom-up image layouts) or a stride exceeding 65535 bytes. The bug was introduced in libpng 1.6.26 (October 2016) by casts added to silence compiler warnings on 16-bit systems. This vulnerability is fixed in 1.6.54.

- **CVE-2026-22695**: A flaw was found in Podman. In a Containerfile or Podman, data written to RUN --mount=type=bind mounts during the podman build is not discarded. This issue can lead to files created within the container appearing in the temporary build context directory on the host, leaving the created files accessible.

- **CVE-2025-66199**: A TLS 1.3 connection using certificate compression can be forced to allocate a large buffer before decompression without checking against the configured certificate size limit.

- **CVE-2025-68160**: Writing large, newline-free data into a BIO chain using the line-buffering filter where the next BIO performs short writes can trigger a heap-based out-of-bounds write.

- **CVE-2025-69419**: Calling PKCS12_get_friendlyname() function on a maliciously crafted PKCS#12 file with a BMPString (UTF-16BE) friendly name containing non-ASCII BMP code point can trigger a one byte write before the allocated buffer.

- **CVE-2026-22795**: An invalid or NULL pointer dereference can happen in an application processing a malformed PKCS#12 file.

### spryker/php:8.2-alpine3.21

- **CVE-2025-15468**: If an application using the SSL_CIPHER_find() function in a QUIC protocol client or server receives an unknown cipher suite from the peer, a NULL dereference occurs.

- **CVE-2025-69421**: Processing a malformed PKCS#12 file can trigger a NULL pointer dereference in the PKCS12_item_decrypt_d2i_ex() function.

- **CVE-2026-22796**: A type confusion vulnerability exists in the signature verification of signed PKCS#7 data where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing malformed PKCS#7 data.

- **CVE-2026-15467**: Parsing CMS AuthEnvelopedData message with maliciously crafted AEAD parameters can trigger a stack buffer overflow.

- **CVE-2025-61728**: archive/zip uses a super-linear file name indexing algorithm that is invoked the first time a file in an archive is opened. This can lead to a denial of service when consuming a maliciously constructed ZIP archive.

- **CVE-2025-69420**: A type confusion vulnerability exists in the TimeStamp Response verification code where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing a malformed TimeStamp Response file.

- **CVE-2025-69418**: When using the low-level OCB API directly with AES-NI or other hardware-accelerated code paths, inputs whose length is not a multiple of 16 bytes can leave the final partial block unencrypted and unauthenticated.

- **CVE-2026-22801**: LIBPNG is a reference library for use in applications that read, create, and manipulate PNG (Portable Network Graphics) raster image files. From 1.6.26 to 1.6.53, there is an integer truncation in the libpng simplified write API functions png_write_image_16bit and png_write_image_8bit causes heap buffer over-read when the caller provides a negative row stride (for bottom-up image layouts) or a stride exceeding 65535 bytes. The bug was introduced in libpng 1.6.26 (October 2016) by casts added to silence compiler warnings on 16-bit systems. This vulnerability is fixed in 1.6.54.

- **CVE-2026-22695**: A flaw was found in Podman. In a Containerfile or Podman, data written to RUN --mount=type=bind mounts during the podman build is not discarded. This issue can lead to files created within the container appearing in the temporary build context directory on the host, leaving the created files accessible.

- **CVE-2025-66199**: A TLS 1.3 connection using certificate compression can be forced to allocate a large buffer before decompression without checking against the configured certificate size limit.

- **CVE-2025-14178**: A heap buffer overflow occurs in array_merge() when the total element count of packed arrays exceeds 32-bit limits or HT_MAX_SIZE, due to an integer overflow in the precomputation of element counts using zend_hash_num_elements(). This may lead to memory corruption or crashes and affect the integrity and availability of the target server.

- **CVE-2025-68160**: Writing large, newline-free data into a BIO chain using the line-buffering filter where the next BIO performs short writes can trigger a heap-based out-of-bounds write.

- **CVE-2025-61726**: The net/url package does not set a limit on the number of query parameters in a query. While the maximum size of query parameters in URLs is generally limited by the maximum request header size, the net/http.Request.ParseForm method can parse large URL-encoded forms. Parsing a large form containing many unique query parameters can cause excessive memory consumption.

- **CVE-2025-69419**: Calling PKCS12_get_friendlyname() function on a maliciously crafted PKCS#12 file with a BMPString (UTF-16BE) friendly name containing non-ASCII BMP code point can trigger a one byte write before the allocated buffer.

- **CVE-2026-22795**: An invalid or NULL pointer dereference can happen in an application processing a malformed PKCS#12 file.

- **CVE-2025-61730**: During the TLS 1.3 handshake if multiple messages are sent in records that span encryption level boundaries (for instance the Client Hello and Encrypted Extensions messages), the subsequent messages may be processed before the encryption level changes. This can cause some minor information disclosure if a network-local attacker can inject messages during the handshake.

- **CVE-2025-14177**: The getimagesize() function may leak uninitialized heap memory into the APPn segments (for example, APP1) when reading images in multi-chunk mode (such as via php://filter). This occurs due to a bug in php_read_stream_all_chunks() that overwrites the buffer without advancing the pointer, leaving tail bytes uninitialized. This may lead to information disclosure of sensitive heap data and affect the confidentiality of the target server.

### spryker/php:8.4-alpine3.20

- **CVE-2025-15468**: If an application using the SSL_CIPHER_find() function in a QUIC protocol client or server receives an unknown cipher suite from the peer, a NULL dereference occurs.

- **CVE-2025-69421**: Processing a malformed PKCS#12 file can trigger a NULL pointer dereference in the PKCS12_item_decrypt_d2i_ex() function.

- **CVE-2026-22796**: A type confusion vulnerability exists in the signature verification of signed PKCS#7 data where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing malformed PKCS#7 data.

- **CVE-2026-15467**: Parsing CMS AuthEnvelopedData message with maliciously crafted AEAD parameters can trigger a stack buffer overflow.

- **CVE-2025-61728**: archive/zip uses a super-linear file name indexing algorithm that is invoked the first time a file in an archive is opened. This can lead to a denial of service when consuming a maliciously constructed ZIP archive.

- **CVE-2025-69420**: A type confusion vulnerability exists in the TimeStamp Response verification code where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing a malformed TimeStamp Response file.

- **CVE-2025-69418**: When using the low-level OCB API directly with AES-NI or other hardware-accelerated code paths, inputs whose length is not a multiple of 16 bytes can leave the final partial block unencrypted and unauthenticated.

- **CVE-2025-6491**: When parsing XML data in SOAP extensions, overly large (&gt;2Gb) XML namespace prefix may lead to null pointer dereference. This may lead to crashes and affect the availability of the target server.

- **CVE-2026-22801**: LIBPNG is a reference library for use in applications that read, create, and manipulate PNG (Portable Network Graphics) raster image files. From 1.6.26 to 1.6.53, there is an integer truncation in the libpng simplified write API functions png_write_image_16bit and png_write_image_8bit causes heap buffer over-read when the caller provides a negative row stride (for bottom-up image layouts) or a stride exceeding 65535 bytes. The bug was introduced in libpng 1.6.26 (October 2016) by casts added to silence compiler warnings on 16-bit systems. This vulnerability is fixed in 1.6.54.

- **CVE-2025-1220**: NetSarang Xmanager Enterprise 5.0 Build 1232, Xmanager 5.0 Build 1045, Xshell 5.0 Build 1322, Xftp 5.0 Build 1218, and Xlpd 5.0 Build 1220 contain a malicious nssock2.dll that implements a multi-stage, DNS-based backdoor. The dormant library contacts a C2 DNS server via a specially crafted TXT record for a month‑generated domain. After receiving a decryption key, it then downloads and executes arbitrary code, creates an encrypted virtual file system (VFS) in the registry, and grants the attacker full remote code execution, data exfiltration, and persistence. NetSarang released builds for each product line that remediated the compromise: Xmanager Enterprise Build 1236, Xmanager Build 1049, Xshell Build 1326, Xftp Build 1222, and Xlpd Build 1224. Kaspersky Lab identified an instance of exploitation in the wild in August 2017.

- **CVE-2026-22695**: A flaw was found in Podman. In a Containerfile or Podman, data written to RUN --mount=type=bind mounts during the podman build is not discarded. This issue can lead to files created within the container appearing in the temporary build context directory on the host, leaving the created files accessible.

- **CVE-2025-66199**: A TLS 1.3 connection using certificate compression can be forced to allocate a large buffer before decompression without checking against the configured certificate size limit.

- **CVE-2025-68160**: Writing large, newline-free data into a BIO chain using the line-buffering filter where the next BIO performs short writes can trigger a heap-based out-of-bounds write.

- **CVE-2025-69419**: Calling PKCS12_get_friendlyname() function on a maliciously crafted PKCS#12 file with a BMPString (UTF-16BE) friendly name containing non-ASCII BMP code point can trigger a one byte write before the allocated buffer.

- **CVE-2026-22795**: An invalid or NULL pointer dereference can happen in an application processing a malformed PKCS#12 file.

- **CVE-2025-1735**: A vulnerability in Palantir&apos;s Aries service allowed unauthenticated access to log viewing and management functionality on Apollo instances using default configuration. The defect resulted in both authentication and authorization checks being bypassed, potentially allowing any network-accessible client to view system logs and perform operations without valid credentials. No evidence of exploitation was identified during the vulnerability window.

- **CVE-2025-14177**: The getimagesize() function may leak uninitialized heap memory into the APPn segments (for example, APP1) when reading images in multi-chunk mode (such as via php://filter). This occurs due to a bug in php_read_stream_all_chunks() that overwrites the buffer without advancing the pointer, leaving tail bytes uninitialized. This may lead to information disclosure of sensitive heap data and affect the confidentiality of the target server.

### spryker/php:8.3-alpine3.20

- **CVE-2025-14178**: A heap buffer overflow occurs in array_merge() when the total element count of packed arrays exceeds 32-bit limits or HT_MAX_SIZE, due to an integer overflow in the precomputation of element counts using zend_hash_num_elements(). This may lead to memory corruption or crashes and affect the integrity and availability of the target server.

- **CVE-2025-15468**: If an application using the SSL_CIPHER_find() function in a QUIC protocol client or server receives an unknown cipher suite from the peer, a NULL dereference occurs.

- **CVE-2025-69421**: Processing a malformed PKCS#12 file can trigger a NULL pointer dereference in the PKCS12_item_decrypt_d2i_ex() function.

- **CVE-2026-22796**: A type confusion vulnerability exists in the signature verification of signed PKCS#7 data where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing malformed PKCS#7 data.

- **CVE-2026-15467**: Parsing CMS AuthEnvelopedData message with maliciously crafted AEAD parameters can trigger a stack buffer overflow.

- **CVE-2025-61726**: The net/url package does not set a limit on the number of query parameters in a query. While the maximum size of query parameters in URLs is generally limited by the maximum request header size, the net/http.Request.ParseForm method can parse large URL-encoded forms. Parsing a large form containing many unique query parameters can cause excessive memory consumption.

- **CVE-2025-61730**: During the TLS 1.3 handshake if multiple messages are sent in records that span encryption level boundaries (for instance the Client Hello and Encrypted Extensions messages), the subsequent messages may be processed before the encryption level changes. This can cause some minor information disclosure if a network-local attacker can inject messages during the handshake.

- **CVE-2025-14180**: Apport 2.13 through 2.20.7 does not properly handle crashes originating from a PID namespace allowing local users to create certain files as root which an attacker could leverage to perform a denial of service via resource exhaustion or possibly gain root privileges

- **CVE-2025-69420**: A type confusion vulnerability exists in the TimeStamp Response verification code where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing a malformed TimeStamp Response file.

- **CVE-2025-69418**: When using the low-level OCB API directly with AES-NI or other hardware-accelerated code paths, inputs whose length is not a multiple of 16 bytes can leave the final partial block unencrypted and unauthenticated.

- **CVE-2026-22801**: LIBPNG is a reference library for use in applications that read, create, and manipulate PNG (Portable Network Graphics) raster image files. From 1.6.26 to 1.6.53, there is an integer truncation in the libpng simplified write API functions png_write_image_16bit and png_write_image_8bit causes heap buffer over-read when the caller provides a negative row stride (for bottom-up image layouts) or a stride exceeding 65535 bytes. The bug was introduced in libpng 1.6.26 (October 2016) by casts added to silence compiler warnings on 16-bit systems. This vulnerability is fixed in 1.6.54.

- **CVE-2025-1220**: NetSarang Xmanager Enterprise 5.0 Build 1232, Xmanager 5.0 Build 1045, Xshell 5.0 Build 1322, Xftp 5.0 Build 1218, and Xlpd 5.0 Build 1220 contain a malicious nssock2.dll that implements a multi-stage, DNS-based backdoor. The dormant library contacts a C2 DNS server via a specially crafted TXT record for a month‑generated domain. After receiving a decryption key, it then downloads and executes arbitrary code, creates an encrypted virtual file system (VFS) in the registry, and grants the attacker full remote code execution, data exfiltration, and persistence. NetSarang released builds for each product line that remediated the compromise: Xmanager Enterprise Build 1236, Xmanager Build 1049, Xshell Build 1326, Xftp Build 1222, and Xlpd Build 1224. Kaspersky Lab identified an instance of exploitation in the wild in August 2017.

- **CVE-2026-22695**: A flaw was found in Podman. In a Containerfile or Podman, data written to RUN --mount=type=bind mounts during the podman build is not discarded. This issue can lead to files created within the container appearing in the temporary build context directory on the host, leaving the created files accessible.

- **CVE-2025-66199**: A TLS 1.3 connection using certificate compression can be forced to allocate a large buffer before decompression without checking against the configured certificate size limit.

- **CVE-2025-68160**: Writing large, newline-free data into a BIO chain using the line-buffering filter where the next BIO performs short writes can trigger a heap-based out-of-bounds write.

- **CVE-2025-1734**: In the Linux kernel, the following vulnerability has been resolved: HID: appleir: Fix potential NULL dereference at raw event handle.

- **CVE-2025-1861**: When parsing HTTP redirect in the response to an HTTP request, there is currently limit on the location value size caused by limited size of the location buffer to 1024. However as per RFC9110, the limit is recommended to be 8000. This may lead to incorrect URL truncation and redirecting to a wrong location.

- **CVE-2025-1219**: When requesting a HTTP resource using the DOM or SimpleXML extensions, the wrong content-type header is used to determine the charset when the requested resource performs a redirect. This may cause the resulting document to be parsed incorrectly or bypass validations.

- **CVE-2025-69419**: Calling PKCS12_get_friendlyname() function on a maliciously crafted PKCS#12 file with a BMPString (UTF-16BE) friendly name containing non-ASCII BMP code point can trigger a one byte write before the allocated buffer.

- **CVE-2026-22795**: An invalid or NULL pointer dereference can happen in an application processing a malformed PKCS#12 file.

- **CVE-2025-1217**: When http request module parses HTTP response obtained from a server, folded headers are parsed incorrectly, which may lead to misinterpreting the response and using incorrect headers, MIME types, etc.

- **CVE-2025-1735**: A vulnerability in Palantir&apos;s Aries service allowed unauthenticated access to log viewing and management functionality on Apollo instances using default configuration. The defect resulted in both authentication and authorization checks being bypassed, potentially allowing any network-accessible client to view system logs and perform operations without valid credentials. No evidence of exploitation was identified during the vulnerability window.

- **CVE-2025-14177**: The getimagesize() function may leak uninitialized heap memory into the APPn segments (for example, APP1) when reading images in multi-chunk mode (such as via php://filter). This occurs due to a bug in php_read_stream_all_chunks() that overwrites the buffer without advancing the pointer, leaving tail bytes uninitialized. This may lead to information disclosure of sensitive heap data and affect the confidentiality of the target server.

### spryker/php:8.2-alpine3.20

- **CVE-2025-14178**: A heap buffer overflow occurs in array_merge() when the total element count of packed arrays exceeds 32-bit limits or HT_MAX_SIZE, due to an integer overflow in the precomputation of element counts using zend_hash_num_elements(). This may lead to memory corruption or crashes and affect the integrity and availability of the target server.

- **CVE-2025-15468**: If an application using the SSL_CIPHER_find() function in a QUIC protocol client or server receives an unknown cipher suite from the peer, a NULL dereference occurs.

- **CVE-2025-69421**: Processing a malformed PKCS#12 file can trigger a NULL pointer dereference in the PKCS12_item_decrypt_d2i_ex() function.

- **CVE-2026-22796**: A type confusion vulnerability exists in the signature verification of signed PKCS#7 data where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing malformed PKCS#7 data.

- **CVE-2026-15467**: Parsing CMS AuthEnvelopedData message with maliciously crafted AEAD parameters can trigger a stack buffer overflow.

- **CVE-2025-61726**: The net/url package does not set a limit on the number of query parameters in a query. While the maximum size of query parameters in URLs is generally limited by the maximum request header size, the net/http.Request.ParseForm method can parse large URL-encoded forms. Parsing a large form containing many unique query parameters can cause excessive memory consumption.

- **CVE-2025-61730**: During the TLS 1.3 handshake if multiple messages are sent in records that span encryption level boundaries (for instance the Client Hello and Encrypted Extensions messages), the subsequent messages may be processed before the encryption level changes. This can cause some minor information disclosure if a network-local attacker can inject messages during the handshake.

- **CVE-2025-14180**: Apport 2.13 through 2.20.7 does not properly handle crashes originating from a PID namespace allowing local users to create certain files as root which an attacker could leverage to perform a denial of service via resource exhaustion or possibly gain root privileges

- **CVE-2025-61728**: archive/zip uses a super-linear file name indexing algorithm that is invoked the first time a file in an archive is opened. This can lead to a denial of service when consuming a maliciously constructed ZIP archive.

- **CVE-2025-69420**: A type confusion vulnerability exists in the TimeStamp Response verification code where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing a malformed TimeStamp Response file.

- **CVE-2025-69418**: When using the low-level OCB API directly with AES-NI or other hardware-accelerated code paths, inputs whose length is not a multiple of 16 bytes can leave the final partial block unencrypted and unauthenticated.

- **CVE-2025-6491**: When parsing XML data in SOAP extensions, overly large (&gt;2Gb) XML namespace prefix may lead to null pointer dereference. This may lead to crashes and affect the availability of the target server.

- **CVE-2026-22801**: LIBPNG is a reference library for use in applications that read, create, and manipulate PNG (Portable Network Graphics) raster image files. From 1.6.26 to 1.6.53, there is an integer truncation in the libpng simplified write API functions png_write_image_16bit and png_write_image_8bit causes heap buffer over-read when the caller provides a negative row stride (for bottom-up image layouts) or a stride exceeding 65535 bytes. The bug was introduced in libpng 1.6.26 (October 2016) by casts added to silence compiler warnings on 16-bit systems. This vulnerability is fixed in 1.6.54.

- **CVE-2025-1220**: NetSarang Xmanager Enterprise 5.0 Build 1232, Xmanager 5.0 Build 1045, Xshell 5.0 Build 1322, Xftp 5.0 Build 1218, and Xlpd 5.0 Build 1220 contain a malicious nssock2.dll that implements a multi-stage, DNS-based backdoor. The dormant library contacts a C2 DNS server via a specially crafted TXT record for a month‑generated domain. After receiving a decryption key, it then downloads and executes arbitrary code, creates an encrypted virtual file system (VFS) in the registry, and grants the attacker full remote code execution, data exfiltration, and persistence. NetSarang released builds for each product line that remediated the compromise: Xmanager Enterprise Build 1236, Xmanager Build 1049, Xshell Build 1326, Xftp Build 1222, and Xlpd Build 1224. Kaspersky Lab identified an instance of exploitation in the wild in August 2017.

- **CVE-2026-22695**: A flaw was found in Podman. In a Containerfile or Podman, data written to RUN --mount=type=bind mounts during the podman build is not discarded. This issue can lead to files created within the container appearing in the temporary build context directory on the host, leaving the created files accessible.

- **CVE-2025-66199**: A TLS 1.3 connection using certificate compression can be forced to allocate a large buffer before decompression without checking against the configured certificate size limit.

- **CVE-2025-68160**: Writing large, newline-free data into a BIO chain using the line-buffering filter where the next BIO performs short writes can trigger a heap-based out-of-bounds write.

- **CVE-2025-69419**: Calling PKCS12_get_friendlyname() function on a maliciously crafted PKCS#12 file with a BMPString (UTF-16BE) friendly name containing non-ASCII BMP code point can trigger a one byte write before the allocated buffer.

- **CVE-2026-22795**: An invalid or NULL pointer dereference can happen in an application processing a malformed PKCS#12 file.

- **CVE-2025-1735**: A vulnerability in Palantir&apos;s Aries service allowed unauthenticated access to log viewing and management functionality on Apollo instances using default configuration. The defect resulted in both authentication and authorization checks being bypassed, potentially allowing any network-accessible client to view system logs and perform operations without valid credentials. No evidence of exploitation was identified during the vulnerability window.

- **CVE-2025-14177**: The getimagesize() function may leak uninitialized heap memory into the APPn segments (for example, APP1) when reading images in multi-chunk mode (such as via php://filter). This occurs due to a bug in php_read_stream_all_chunks() that overwrites the buffer without advancing the pointer, leaving tail bytes uninitialized. This may lead to information disclosure of sensitive heap data and affect the confidentiality of the target server.

### spryker/php:8.1-alpine3.20

- **CVE-2025-14178**: A heap buffer overflow occurs in array_merge() when the total element count of packed arrays exceeds 32-bit limits or HT_MAX_SIZE, due to an integer overflow in the precomputation of element counts using zend_hash_num_elements(). This may lead to memory corruption or crashes and affect the integrity and availability of the target server.

- **CVE-2025-15468**: If an application using the SSL_CIPHER_find() function in a QUIC protocol client or server receives an unknown cipher suite from the peer, a NULL dereference occurs.

- **CVE-2025-69421**: Processing a malformed PKCS#12 file can trigger a NULL pointer dereference in the PKCS12_item_decrypt_d2i_ex() function.

- **CVE-2026-22796**: A type confusion vulnerability exists in the signature verification of signed PKCS#7 data where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing malformed PKCS#7 data.

- **CVE-2026-15467**: Parsing CMS AuthEnvelopedData message with maliciously crafted AEAD parameters can trigger a stack buffer overflow.

- **CVE-2025-61726**: The net/url package does not set a limit on the number of query parameters in a query. While the maximum size of query parameters in URLs is generally limited by the maximum request header size, the net/http.Request.ParseForm method can parse large URL-encoded forms. Parsing a large form containing many unique query parameters can cause excessive memory consumption.

- **CVE-2025-61730**: During the TLS 1.3 handshake if multiple messages are sent in records that span encryption level boundaries (for instance the Client Hello and Encrypted Extensions messages), the subsequent messages may be processed before the encryption level changes. This can cause some minor information disclosure if a network-local attacker can inject messages during the handshake.

- **CVE-2025-14180**: Apport 2.13 through 2.20.7 does not properly handle crashes originating from a PID namespace allowing local users to create certain files as root which an attacker could leverage to perform a denial of service via resource exhaustion or possibly gain root privileges

- **CVE-2025-61728**: archive/zip uses a super-linear file name indexing algorithm that is invoked the first time a file in an archive is opened. This can lead to a denial of service when consuming a maliciously constructed ZIP archive.

- **CVE-2025-69420**: A type confusion vulnerability exists in the TimeStamp Response verification code where an ASN1_TYPE union member is accessed without first validating the type, causing an invalid or NULL pointer dereference when processing a malformed TimeStamp Response file.

- **CVE-2025-69418**: When using the low-level OCB API directly with AES-NI or other hardware-accelerated code paths, inputs whose length is not a multiple of 16 bytes can leave the final partial block unencrypted and unauthenticated.

- **CVE-2025-6491**: When parsing XML data in SOAP extensions, overly large (&gt;2Gb) XML namespace prefix may lead to null pointer dereference. This may lead to crashes and affect the availability of the target server.

- **CVE-2026-22801**: LIBPNG is a reference library for use in applications that read, create, and manipulate PNG (Portable Network Graphics) raster image files. From 1.6.26 to 1.6.53, there is an integer truncation in the libpng simplified write API functions png_write_image_16bit and png_write_image_8bit causes heap buffer over-read when the caller provides a negative row stride (for bottom-up image layouts) or a stride exceeding 65535 bytes. The bug was introduced in libpng 1.6.26 (October 2016) by casts added to silence compiler warnings on 16-bit systems. This vulnerability is fixed in 1.6.54.

- **CVE-2025-1220**: NetSarang Xmanager Enterprise 5.0 Build 1232, Xmanager 5.0 Build 1045, Xshell 5.0 Build 1322, Xftp 5.0 Build 1218, and Xlpd 5.0 Build 1220 contain a malicious nssock2.dll that implements a multi-stage, DNS-based backdoor. The dormant library contacts a C2 DNS server via a specially crafted TXT record for a month‑generated domain. After receiving a decryption key, it then downloads and executes arbitrary code, creates an encrypted virtual file system (VFS) in the registry, and grants the attacker full remote code execution, data exfiltration, and persistence. NetSarang released builds for each product line that remediated the compromise: Xmanager Enterprise Build 1236, Xmanager Build 1049, Xshell Build 1326, Xftp Build 1222, and Xlpd Build 1224. Kaspersky Lab identified an instance of exploitation in the wild in August 2017.

- **CVE-2026-22695**: A flaw was found in Podman. In a Containerfile or Podman, data written to RUN --mount=type=bind mounts during the podman build is not discarded. This issue can lead to files created within the container appearing in the temporary build context directory on the host, leaving the created files accessible.

- **CVE-2025-66199**: A TLS 1.3 connection using certificate compression can be forced to allocate a large buffer before decompression without checking against the configured certificate size limit.

- **CVE-2025-68160**: Writing large, newline-free data into a BIO chain using the line-buffering filter where the next BIO performs short writes can trigger a heap-based out-of-bounds write.

- **CVE-2025-69419**: Calling PKCS12_get_friendlyname() function on a maliciously crafted PKCS#12 file with a BMPString (UTF-16BE) friendly name containing non-ASCII BMP code point can trigger a one byte write before the allocated buffer.

- **CVE-2026-22795**: An invalid or NULL pointer dereference can happen in an application processing a malformed PKCS#12 file.</description>
            <pubDate>Fri, 06 Feb 2026 15:12:52 +0000</pubDate>
            <link>https://docs.spryker.com/docs/about/all/releases/image-releases/spryker-php/release-notes-spryker-php-20260206.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/about/all/releases/image-releases/spryker-php/release-notes-spryker-php-20260206.html</guid>
            
            
        </item>
        
        <item>
            <title>Configure Elasticsearch</title>
            <description>&lt;p&gt;Elasticsearch is a NoSQL data store that lets you predefine the structure of the data you store in it.&lt;/p&gt;
&lt;p&gt;Because the data structure is static, you need to define it in advance. The definitions of the indexes and mappings are written in JSON. For more information, see the &lt;a href=&quot;https://www.elastic.co/guide/index.html&quot;&gt;official Elasticsearch documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The content of the configuration files must follow the conventions listed in the &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html&quot;&gt;Create index API&lt;/a&gt; document of the official Elasticsearch documentation.&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;Note&lt;/div&gt;
&lt;p&gt;The current search installer supports only settings and mappings. However, if you need more, you can extend it on the project level.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Schema example&lt;/strong&gt;: For the main index called &lt;code&gt;page&lt;/code&gt;, you can find the default schema configuration in &lt;code&gt;vendor/spryker/search-elasticsearch/src/Spryker/Shared/SearchElasticsearch/Schema/page.json&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;&lt;/section&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;OpenSearch compatibility&lt;/div&gt;
&lt;p&gt;Spryker PaaS uses OpenSearch, an AWS-maintained fork of Elasticsearch. The configuration principles in this guide apply to both. For OpenSearch-specific features and version information, see the &lt;a href=&quot;https://opensearch.org/docs/latest/&quot;&gt;OpenSearch documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;h2 id=&quot;index-naming-convention&quot;&gt;Index naming convention&lt;/h2&gt;
&lt;p&gt;Each configured store has its index, which is installed automatically. An index name consists of the following parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An optional prefix, which is defined by the &lt;code&gt;SearchElasticsearchConstants::INDEX_PREFIX&lt;/code&gt; configuration option.&lt;/li&gt;
&lt;li&gt;A store name.&lt;/li&gt;
&lt;li&gt;A configuration file name.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Index name components are delimited with an underscore—for example, &lt;code&gt;spryker_de_page&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;schema-configuration-approaches&quot;&gt;Schema configuration approaches&lt;/h2&gt;
&lt;p&gt;Spryker supports two approaches for defining Elasticsearch index schemas. Understanding the difference helps you choose the right approach for your project.&lt;/p&gt;
&lt;h3 id=&quot;modern-approach-schema-directory-recommended&quot;&gt;Modern approach: Schema directory (Recommended)&lt;/h3&gt;
&lt;p&gt;The modern and recommended approach uses JSON files in the &lt;code&gt;Schema&lt;/code&gt; directory:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Location&lt;/strong&gt;: &lt;code&gt;*/Shared/*/Schema/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;File naming&lt;/strong&gt;: &lt;code&gt;{index-name}.json&lt;/code&gt; (for example, &lt;code&gt;page.json&lt;/code&gt;, &lt;code&gt;myindex.json&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configuration method&lt;/strong&gt;: &lt;code&gt;SearchElasticsearchConfig::getJsonSchemaDefinitionDirectories()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use case&lt;/strong&gt;: Creating new indexes or extending existing ones&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Core schema: &lt;code&gt;vendor/spryker/search-elasticsearch/src/Spryker/Shared/SearchElasticsearch/Schema/page.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Project-level customization: &lt;code&gt;src/Pyz/Shared/Search/Schema/page.json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This approach offers flexibility through modular schema definitions. Files can contain complete index definitions or only the parts you want to extend or override.&lt;/p&gt;
&lt;h3 id=&quot;legacy-approach-indexmap-directory-deprecated&quot;&gt;Legacy approach: IndexMap directory (Deprecated)&lt;/h3&gt;
&lt;p&gt;The older approach uses JSON files in the &lt;code&gt;IndexMap&lt;/code&gt; directory:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Location&lt;/strong&gt;: &lt;code&gt;*/Shared/*/IndexMap/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;File naming&lt;/strong&gt;: &lt;code&gt;search.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configuration method&lt;/strong&gt;: &lt;code&gt;SearchConfig::getJsonIndexDefinitionDirectories()&lt;/code&gt; (deprecated)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Status&lt;/strong&gt;: Maintained for backward compatibility but not recommended for new implementations&lt;/li&gt;
&lt;/ul&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;Deprecation notice&lt;/div&gt;
&lt;p&gt;The IndexMap approach is deprecated. For new projects or when extending existing schemas, use the modern Schema directory approach instead.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;h2 id=&quot;schema-merging-and-customization&quot;&gt;Schema merging and customization&lt;/h2&gt;
&lt;p&gt;Spryker automatically merges all JSON files with the same name across different modules, enabling you to customize schemas without modifying core files.&lt;/p&gt;
&lt;h3 id=&quot;how-merging-works&quot;&gt;How merging works&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;SchemaDefinitionFinder&lt;/code&gt; locates all JSON files in configured Schema directories&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;IndexDefinitionLoader&lt;/code&gt; loads each file&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;IndexDefinitionMerger&lt;/code&gt; merges files with matching names using &lt;code&gt;array_replace_recursive()&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Merging order&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Core vendor schemas (from &lt;code&gt;vendor/spryker/*/src/*/Shared/*/Schema/&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Project-level schemas (from &lt;code&gt;src/*/Shared/*/Schema/&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Project-level definitions override core definitions for matching keys.&lt;/p&gt;
&lt;h3 id=&quot;merging-example&quot;&gt;Merging example&lt;/h3&gt;
&lt;p&gt;Core schema (&lt;code&gt;vendor/spryker/search-elasticsearch/src/Spryker/Shared/SearchElasticsearch/Schema/page.json&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;language-json 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;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;settings&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;analysis&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;suggestion_analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tokenizer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;standard&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;filter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;lowercase&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mappings&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;page&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;full-text&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Project-level schema (&lt;code&gt;src/Pyz/Shared/Search/Schema/page.json&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;language-json 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;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;settings&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;analysis&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fulltext_index_analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tokenizer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;keyword&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;filter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;lowercase&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;fulltext_index_ngram_filter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mappings&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;page&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;full-text&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;fulltext_index_analyzer&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Resulting merged schema:&lt;/p&gt;
&lt;div class=&quot;language-json 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;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;settings&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;analysis&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;suggestion_analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tokenizer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;standard&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;filter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;lowercase&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fulltext_index_analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tokenizer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;keyword&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;filter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;lowercase&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;fulltext_index_ngram_filter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mappings&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;page&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;full-text&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;fulltext_index_analyzer&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;store-specific-schemas&quot;&gt;Store-specific schemas&lt;/h3&gt;
&lt;p&gt;To create store-specific schema overrides, prefix the filename with the store code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;de_page.json&lt;/code&gt; - Applies only to the DE store&lt;/li&gt;
&lt;li&gt;&lt;code&gt;us_page.json&lt;/code&gt; - Applies only to the US store&lt;/li&gt;
&lt;li&gt;&lt;code&gt;page.json&lt;/code&gt; - Applies to all stores (unless overridden by store-specific files)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is useful when different stores require different analyzers, language-specific tokenizers, or other locale-specific configurations.&lt;/p&gt;
&lt;h2 id=&quot;source-identifier-management&quot;&gt;Source identifier management&lt;/h2&gt;
&lt;p&gt;Spryker uses an allowlist mechanism to control which index schema files are processed during installation. This prevents accidental or unauthorized index creation.&lt;/p&gt;
&lt;h3 id=&quot;how-source-identifiers-work&quot;&gt;How source identifiers work&lt;/h3&gt;
&lt;p&gt;The source identifier is derived from the JSON filename:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;page.json&lt;/code&gt; → source identifier: &lt;code&gt;page&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;product-review.json&lt;/code&gt; → source identifier: &lt;code&gt;product-review&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;myindex.json&lt;/code&gt; → source identifier: &lt;code&gt;myindex&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Spryker loads and installs only files whose source identifiers are listed in &lt;code&gt;SearchElasticsearchConfig::getSupportedSourceIdentifiers()&lt;/code&gt;. Files with unlisted source identifiers are skipped.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Code reference&lt;/strong&gt;: The filtering happens in &lt;code&gt;IndexDefinitionLoader::load()&lt;/code&gt; at &lt;code&gt;src/Spryker/SearchElasticsearch/src/Spryker/Zed/SearchElasticsearch/Business/Definition/Loader/IndexDefinitionLoader.php:60-62&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;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;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sourceIdentifier&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isSupported&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$sourceIdentifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$storeName&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;configure-supported-source-identifiers&quot;&gt;Configure supported source identifiers&lt;/h3&gt;
&lt;p&gt;To add support for new indexes, override &lt;code&gt;SUPPORTED_SOURCE_IDENTIFIERS&lt;/code&gt; in your project-level configuration:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;src/Pyz/Shared/SearchElasticsearch/SearchElasticsearchConfig.php&lt;/strong&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;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Shared\SearchElasticsearch&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\Shared\SearchElasticsearch\SearchElasticsearchConfig&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerSearchElasticsearchConfig&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;SearchElasticsearchConfig&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerSearchElasticsearchConfig&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;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SUPPORTED_SOURCE_IDENTIFIERS&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;s1&quot;&gt;&apos;page&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;product-review&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;return_reason&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;merchant&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;myindex&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Add your custom index here&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;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 consideration&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;SUPPORTED_SOURCE_IDENTIFIERS&lt;/code&gt; configuration acts as a security allowlist. Always review and explicitly add source identifiers rather than allowing all indexes. This prevents unauthorized or test indexes from being created in production environments.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;h3 id=&quot;example-workflow&quot;&gt;Example workflow&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a new schema file: &lt;code&gt;src/Pyz/Shared/MyModule/Schema/myindex.json&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the source identifier to the configuration: &lt;code&gt;&apos;myindex&apos;&lt;/code&gt; in &lt;code&gt;SUPPORTED_SOURCE_IDENTIFIERS&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the installation commands:&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;vendor/bin/console search:setup:sources
vendor/bin/console search:setup:source-map
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The new index is created and a &lt;code&gt;MyindexIndexMap&lt;/code&gt; helper class is generated&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Without step 2, the &lt;code&gt;myindex.json&lt;/code&gt; file is discovered but skipped during installation, and no index is created.&lt;/p&gt;
&lt;h3 id=&quot;store-prefixed-source-identifiers&quot;&gt;Store-prefixed source identifiers&lt;/h3&gt;
&lt;p&gt;Store-prefixed files like &lt;code&gt;de_page.json&lt;/code&gt; work with the base source identifier &lt;code&gt;page&lt;/code&gt;. You do not need to add &lt;code&gt;de_page&lt;/code&gt; to &lt;code&gt;SUPPORTED_SOURCE_IDENTIFIERS&lt;/code&gt;. The system automatically recognizes &lt;code&gt;de_page&lt;/code&gt; as a store-specific variant of the &lt;code&gt;page&lt;/code&gt; source identifier.&lt;/p&gt;
&lt;h2 id=&quot;working-with-indexes-and-mappings&quot;&gt;Working with indexes and mappings&lt;/h2&gt;
&lt;h3 id=&quot;create-new-indexes&quot;&gt;Create new indexes&lt;/h3&gt;
&lt;p&gt;To define new indexes and mappings, under the &lt;code&gt;Shared&lt;/code&gt; namespace of any module, create new configuration files—for example, &lt;code&gt;src/Pyz/Shared/MyModuleName/Schema/myindex.json&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The file can contain a complete index definition with settings and mappings. When the search installer runs, it reads all available configuration files and merges them by index name per store.&lt;/p&gt;
&lt;h3 id=&quot;modify-existing-indexes&quot;&gt;Modify existing indexes&lt;/h3&gt;
&lt;p&gt;To extend or overwrite existing configurations, create a new file with the same name you want to modify and provide only the differences compared to the original one. The merging process automatically combines your changes with the core schema.&lt;/p&gt;
&lt;p&gt;For store-specific modifications, create a configuration file with the store’s name prefix—for example, &lt;code&gt;de_page.json&lt;/code&gt;. This is useful when you have different analyzing strategies for different stores.&lt;/p&gt;
&lt;h3 id=&quot;example-custom-tokenizer-configuration&quot;&gt;Example: Custom tokenizer configuration&lt;/h3&gt;
&lt;p&gt;The following example shows how to modify the default schema configuration for the main index &lt;code&gt;page&lt;/code&gt; to allow searching for keywords containing the special character &lt;em&gt;&amp;amp;&lt;/em&gt; (ampersand). The configuration switches from a &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-standard-tokenizer.html&quot;&gt;&lt;code&gt;standard&lt;/code&gt;&lt;/a&gt; tokenizer to a combination of &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-keyword-tokenizer.html&quot;&gt;&lt;code&gt;keyword&lt;/code&gt;&lt;/a&gt; tokenizer and token filter of the &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/reference/8.2/analysis-word-delimiter-graph-tokenfilter.html&quot;&gt;&lt;code&gt;word_delimiter_graph&lt;/code&gt;&lt;/a&gt; type.&lt;/p&gt;
&lt;details&gt;&lt;summary&gt;src/Pyz/Shared/Search/Schema/page.json&lt;/summary&gt;
&lt;div class=&quot;language-json 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;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;settings&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;analysis&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fulltext_index_analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tokenizer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;keyword&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;filter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;my_custom_word_delimiter_graph_filter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;lowercase&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;fulltext_index_ngram_filter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fulltext_search_analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tokenizer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;keyword&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;filter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;custom_word_delimiter_graph_filter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;lowercase&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;filter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fulltext_index_ngram_filter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;edge_ngram&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;min_gram&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;max_gram&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;custom_word_delimiter_graph_filter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;word_delimiter_graph&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type_table&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;amp; =&amp;gt; ALPHA&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;split_on_case_change&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;split_on_numerics&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mappings&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;page&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;full-text&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;fulltext_index_analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;search_analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;fulltext_search_analyzer&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;full-text-boosted&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;fulltext_index_analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;search_analyzer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;fulltext_search_analyzer&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;After creating or modifying schema files, follow the installation steps in the &lt;a href=&quot;#install-indexes-and-mappings&quot;&gt;Install indexes and mappings&lt;/a&gt; section.&lt;/p&gt;
&lt;h2 id=&quot;install-indexes-and-mappings&quot;&gt;Install indexes and mappings&lt;/h2&gt;
&lt;p&gt;To install or update indexes and mappings, run the following commands:&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;n&quot;&gt;vendor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;console&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sources&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;vendor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;console&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The first command installs indexes that do not exist and &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html&quot;&gt;updates the mappings&lt;/a&gt; based on the JSON configurations.&lt;/p&gt;
&lt;p&gt;If an index is created with the given settings, those settings cannot be changed by running this process again, but the mapping can be modified.&lt;/p&gt;
&lt;p&gt;In the development environment, to create new analyzers or change the index settings, you must delete the index and run the installation process again.&lt;/p&gt;
&lt;h3 id=&quot;populate-indexes-with-data&quot;&gt;Populate indexes with data&lt;/h3&gt;
&lt;p&gt;After installation, populate the newly created index with 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;n&quot;&gt;vendor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;console&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;publish&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;events&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;generated-helper-classes&quot;&gt;Generated helper classes&lt;/h3&gt;
&lt;p&gt;After running the &lt;code&gt;search:setup:source-map&lt;/code&gt; command, a helper class is autogenerated for every installed index. You can find these classes under the &lt;code&gt;\Generated\Shared\Search&lt;/code&gt; namespace. The name of the generated class starts with the name of the index and is followed by the suffix &lt;code&gt;IndexMap&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For the default page index, the class is &lt;code&gt;\Generated\Shared\Search\PageIndexMap&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These classes provide information from the mapping, such as fields and metadata. Use these classes for references to program against something related to that mapping schema.&lt;/p&gt;
&lt;p&gt;If you change the mapping and run the installer, autogenerated classes change accordingly.&lt;/p&gt;
&lt;h2 id=&quot;update-indexes-with-existing-data&quot;&gt;Update indexes with existing data&lt;/h2&gt;
&lt;p&gt;Elasticsearch has limitations when updating indexes that contain data. If any issues occur, the errors provided by Elasticsearch can be confusing.&lt;/p&gt;
&lt;p&gt;To ensure an index is correct when updating schemas, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drop and recreate the index:&lt;/li&gt;
&lt;/ol&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;&lt;span class=&quot;nv&quot;&gt;APPLICATION_STORE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;DE console search:index:delete
&lt;span class=&quot;nv&quot;&gt;APPLICATION_STORE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;DE console search:setup:sources
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;If the previous command introduced or may have introduced any changes to searchable data, rewrite the data:&lt;/li&gt;
&lt;/ol&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;&lt;span class=&quot;nv&quot;&gt;APPLICATION_STORE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;DE console publish:trigger-events
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Sync the data to Elasticsearch:&lt;/li&gt;
&lt;/ol&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;&lt;span class=&quot;nv&quot;&gt;APPLICATION_STORE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;DE console &lt;span class=&quot;nb&quot;&gt;sync&lt;/span&gt;:data
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For help with more specific cases, engage with the &lt;a href=&quot;https://commercequest.space/&quot;&gt;Spryker community&lt;/a&gt; or &lt;a href=&quot;https://support.spryker.com&quot;&gt;contact support&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;advanced-configuration&quot;&gt;Advanced configuration&lt;/h2&gt;
&lt;h3 id=&quot;disable-default-mapping-installation&quot;&gt;Disable default mapping installation&lt;/h3&gt;
&lt;p&gt;To disable the default mapping installation, override the core configuration defined in &lt;code&gt;Spryker\Zed\SearchElasticsearch\SearchElasticsearchConfig::getJsonSchemaDefinitionDirectories()&lt;/code&gt; by implementing it on the project level—for example, in &lt;code&gt;Pyz\Zed\SearchElasticsearch\SearchElasticsearchConfig&lt;/code&gt;.&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;Warning&lt;/div&gt;
&lt;p&gt;Disabling default mappings means you must provide all necessary schema configurations at the project level. This is an advanced configuration option and should only be used when you have specific requirements that cannot be met by extending the default schemas.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
</description>
            <pubDate>Thu, 05 Feb 2026 14:24:44 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/search/latest/base-shop/tutorials-and-howtos/configure-elasticsearch.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/search/latest/base-shop/tutorials-and-howtos/configure-elasticsearch.html</guid>
            
            
        </item>
        
        <item>
            <title>Enable the Zero State Component for Empty Data</title>
            <description>&lt;p&gt;This guide explains how to enable the &lt;strong&gt;Zero State component&lt;/strong&gt; in Spryker Cloud Commerce OS Yves so you can display user-friendly messages and visuals when no data is available.&lt;/p&gt;
&lt;p&gt;To add the Zero State component to your project, include the &lt;code&gt;molecule(&apos;empty-state&apos;)&lt;/code&gt; in the relevant Twig file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;vendor/spryker-shop/shop-ui/src/SprykerShop/Yves/ShopUi/Theme/default/components/molecules/empty-state/empty-state.twig&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;div class=&quot;language-twig 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;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;molecule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;empty-state&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;title.glossary.key&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;trans&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;description.glossary.key&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;trans&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;iconName&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;icon-name&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;actionButton&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;button.glossary.key&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;trans&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;url-key&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;qa&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;qa-key&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;icon-name&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;only&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;steps-to-enable-the-zero-state-component&quot;&gt;Steps to Enable the Zero State Component&lt;/h2&gt;
&lt;h3 id=&quot;update-codesprykershopcode-modules&quot;&gt;1. Update &lt;code&gt;SprykerShop&lt;/code&gt; modules&lt;/h3&gt;
&lt;p&gt;Update the following modules to the specified versions or higher:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;spryker-shop/shop-ui&lt;/code&gt;: 1.101.0&lt;/li&gt;
&lt;li&gt;&lt;code&gt;spryker-shop/customer-page&lt;/code&gt;: 2.73.0&lt;/li&gt;
&lt;li&gt;&lt;code&gt;spryker-shop/sales-return-page&lt;/code&gt;: 1.11.0&lt;/li&gt;
&lt;/ul&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-shop/shop-ui:&lt;span class=&quot;s2&quot;&gt;&quot;^1.101.0&quot;&lt;/span&gt; spryker-shop/customer-page:&lt;span class=&quot;s2&quot;&gt;&quot;^2.73.0&quot;&lt;/span&gt; spryker-shop/sales-return-page:&lt;span class=&quot;s2&quot;&gt;&quot;^1.11.0&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;hr /&gt;
&lt;h3 id=&quot;add-icons-to-the-icon-sprite&quot;&gt;2. Add icons to the icon sprite&lt;/h3&gt;
&lt;p&gt;Add new icons into &lt;code&gt;icon-sprite&lt;/code&gt; atom:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;src/Pyz/Yves/ShopUi/Theme/default/components/atoms/icon-sprite/icon-sprite.twig&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-twig 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;symbol&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;:flash-message-alert&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;viewBox=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0 -960 960 960&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;fill=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;currentColor&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;path&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;d=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q54 0 104-17.5t92-50.5L228-676q-33 42-50.5 92T160-480q0 134 93 227t227 93Zm252-124q33-42 50.5-92T800-480q0-134-93-227t-227-93q-54 0-104 17.5T284-732l448 448Z&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&amp;lt;/symbol&amp;gt;&lt;/span&gt;   
&lt;span class=&quot;nt&quot;&gt;&amp;lt;symbol&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;:local-mall&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;viewBox=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0 -960 960 960&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;fill=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;currentColor&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;:local-mall&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Local Mall&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;path&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;d=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;M200-80q-33 0-56.5-23.5T120-160v-480q0-33 23.5-56.5T200-720h80q0-83 58.5-141.5T480-920q83 0 141.5 58.5T680-720h80q33 0 56.5 23.5T840-640v480q0 33-23.5 56.5T760-80H200Zm0-80h560v-480H200v480Zm280-240q83 0 141.5-58.5T680-600h-80q0 50-35 85t-85 35q-50 0-85-35t-35-85h-80q0 83 58.5 141.5T480-400ZM360-720h240q0-50-35-85t-85-35q-50 0-85 35t-35 85ZM200-160v-480 480Z&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/symbol&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;symbol&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;:globe-location-pin&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;viewBox=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0 -960 960 960&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;fill=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;currentColor&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;:globe-location-pin&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Globe Location Pin&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;path&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;d=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q152 0 263.5 98T876-538q-20-10-41.5-15.5T790-560q-19-73-68.5-130T600-776v16q0 33-23.5 56.5T520-680h-80v80q0 17-11.5 28.5T400-560h-80v80h240q11 0 20.5 5.5T595-459q-17 27-26 57t-9 62q0 63 32.5 117T659-122q-41 20-86 31t-93 11Zm-40-82v-78q-33 0-56.5-23.5T360-320v-40L168-552q-3 18-5.5 36t-2.5 36q0 121 79.5 212T440-162Zm340 82q-7 0-12-4t-7-10q-11-35-31-65t-43-59q-21-26-34-57t-13-65q0-58 41-99t99-41q58 0 99 41t41 99q0 34-13.5 64.5T873-218q-23 29-43 59t-31 65q-2 6-7 10t-12 4Zm0-113q10-17 22-31.5t23-29.5q14-19 24.5-40.5T860-340q0-33-23.5-56.5T780-420q-33 0-56.5 23.5T700-340q0 24 10.5 45.5T735-254q12 15 23.5 29.5T780-193Zm0-97q-21 0-35.5-14.5T730-340q0-21 14.5-35.5T780-390q21 0 35.5 14.5T830-340q0 21-14.5 35.5T780-290Z&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/symbol&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;symbol&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;:add&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;viewBox=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0 -960 960 960&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;fill=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;currentColor&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;:add&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Add&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;path&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;d=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;M440-440H200v-80h240v-240h80v240h240v80H520v240h-80v-240Z&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/symbol&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;symbol&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;:shopping-bag-speed&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;viewBox=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0 -960 960 960&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;fill=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;currentColor&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;:shopping-bag-speed&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Shopping Bag Speed&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;path&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;d=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;m40-240 20-80h220l-20 80H40Zm80-160 20-80h260l-20 80H120Zm623 240 20-160 29-240 10-79-59 479ZM240-80q-33 0-56.5-23.5T160-160h583l59-479H692l-11 85q-2 17-15 26.5t-30 7.5q-17-2-26.5-14.5T602-564l9-75H452l-11 84q-2 17-15 27t-30 8q-17-2-27-15t-8-30l9-74H220q4-34 26-57.5t54-23.5h80q8-75 51.5-117.5T550-880q64 0 106.5 47.5T698-720h102q36 1 60 28t19 63l-60 480q-4 30-26.5 49.5T740-80H240Zm220-640h159q1-33-22.5-56.5T540-800q-35 0-55.5 21.5T460-720Z&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/symbol&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;hr /&gt;
&lt;h3 id=&quot;glossary-keys&quot;&gt;3. Glossary keys&lt;/h3&gt;
&lt;p&gt;Add glossary keys for the empty state component (for example, Customer pages – Addresses, Order History, and Returns):&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;data/import/common/common/glossary.csv&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csv&quot;&gt;&gt;customer.account.address.no-addresses,Noch keine Adressen hinzugefügt!,de_DE
customer.account.address.no-addresses-description,&amp;quot;This is where you&apos;ll find and manage addresses once it&apos;s available.&amp;quot;,en_US
customer.account.address.no-addresses-description,&amp;quot;Hier können Sie Ihre Adressen sehen und verwalten, sobald sie verfügbar sind.&amp;quot;,de_DE
customer.order.no_orders,No order history available!,en_US
customer.order.no_orders,Keine Bestellungen gefunden!,de_DE
customer.order.no_orders_description,&amp;quot;This is where you&apos;ll find and manage order history once it&apos;s available.&amp;quot;,en_US
customer.order.no_orders_description,&amp;quot;Hier können Sie Ihre Bestellhistorie sehen und verwalten, sobald sie verfügbar ist.&amp;quot;,de_DE
return_page.account.no_return,No returns found!,en_US
return_page.account.no_return,Keine Retouren gefunden!,de_DE
return_page.account.no_return_description,&amp;quot;This is where you&apos;ll find and manage returns once it&apos;s available.&amp;quot;,en_US
return_page.account.no_return_description,&amp;quot;Hier können Sie Ihre Retouren sehen und verwalten, sobald sie verfügbar sind.&amp;quot;,de_DE
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3 id=&quot;update-twig-files-to-enable-the-new-codezero-statecode-component&quot;&gt;4. Update Twig files to enable the new &lt;code&gt;Zero State&lt;/code&gt; component&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;src/Pyz/Yves/CustomerPage/Theme/default/components/molecules/order-table/order-table.twig&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-twig 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;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;data.orders&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;empty&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;noOrder&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
        &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endblock&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;src/Pyz/Yves/CustomerPage/Theme/default/views/address/address.twig&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-twig 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;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;data.addresses&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
    ...
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;emptyState&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
        &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;molecule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;empty-state&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;customer.account.address.no-addresses&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;trans&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;customer.account.address.no-addresses-description&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;trans&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;iconName&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;globe-location-pin&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;actionButton&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;nv&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;customer.account.button.add_new_address&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;trans&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;nv&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;customer/address/new&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                    &lt;span class=&quot;nv&quot;&gt;qa&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;customer-add-new-address&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;nv&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;add&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;only&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endblock&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;hr /&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;Tip&lt;/div&gt;
To prevent the newly created `Zero State` component from rendering on the `Customer/Overview` page, adjust the `order-table` molecule include by replacing the content of the `noOrder` block.
&lt;p&gt;&lt;strong&gt;src/Pyz/Yves/CustomerPage/Theme/default/views/overview/overview.twig&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-twig 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;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;embed&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;molecule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;order-table&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;CustomerPage&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;orders&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;data.orders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;ordersAggregatedItemStateDisplayNames&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;data.ordersAggregatedItemStateDisplayNames&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;only&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;noOrder&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;customer.account.no_order&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;trans&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endblock&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endembed&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;hr /&gt;
</description>
            <pubDate>Tue, 03 Feb 2026 13:23:35 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/yves/install-and-upgrade/enable-zero-state-component-for-empty-data.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/yves/install-and-upgrade/enable-zero-state-component-for-empty-data.html</guid>
            
            
        </item>
        
        <item>
            <title>Upgrade to Angular 20</title>
            <description>This document explains how you can upgrade Angular to version 20 in your Spryker project.

Spryker currently uses Angular version 18. According to the [Angular Support policy and schedule](https://angular.dev/reference/releases#actively-supported-versions), Angular 18 is deprecated.
The current stable Angular version is 20.

We recommend that you upgrade to the latest major Angular version to receive the most recent bug fixes, security updates, and improvements to runtime performance and tooling.

Upgrading to Angular v20 introduces incompatibilities with earlier Angular versions. As a result, the following modules require a major release:

- `AgentDashboardMerchantPortalGui`
- `AgentSecurityMerchantPortalGui`
- `CommentMerchantPortalGui`
- `DashboardMerchantPortalGui`
- `DataImportMerchantPortalGui`
- `GuiTable`
- `MerchantAppMerchantPortalGui`
- `MerchantProfileMerchantPortalGui`
- `MerchantRelationRequestMerchantPortalGui`
- `MerchantRelationshipMerchantPortalGui`
- `MultiFactorAuthMerchantPortal`
- `PriceProductMerchantRelationshipMerchantPortalGui`
- `ProductMerchantPortalGui`
- `ProductOfferMerchantPortalGui`
- `ProductOfferServicePointMerchantPortalGui`
- `ProductOfferShipmentTypeMerchantPortalGui`
- `SalesMerchantPortalGui`
- `SecurityMerchantPortalGui`
- `UserMerchantPortalGui`
- `ZedUi`

*Estimated migration time: 2h*

To upgrade to Angular v20, follow these steps.


## 1) Update modules

1. Check if the following Marketplace modules in your project have the new versions:

| NAME                                             | VERSION   |
|--------------------------------------------------|-----------|
| AgentDashboardMerchantPortalGui                  | &gt;= 2.0.0  |
| AgentSecurityMerchantPortalGui                   | &gt;= 2.0.0  |
| CommentMerchantPortalGui                         | &gt;= 2.0.0  |
| DashboardMerchantPortalGui                       | &gt;= 4.0.0  |
| DataImportMerchantPortalGui                      | &gt;= 2.0.0  |
| GuiTable                                         | &gt;= 4.0.0  |
| MerchantAppMerchantPortalGui                     | &gt;= 2.0.0  |
| MerchantProfileMerchantPortalGui                  | &gt;= 4.0.0  |
| MerchantRelationRequestMerchantPortalGui         | &gt;= 2.0.0  |
| MerchantRelationshipMerchantPortalGui            | &gt;= 2.0.0  |
| MultiFactorAuthMerchantPortal                    | &gt;= 2.0.0  |
| PriceProductMerchantRelationshipMerchantPortalGui| &gt;= 3.0.0  |
| ProductMerchantPortalGui                         | &gt;= 5.0.0  |
| ProductOfferMerchantPortalGui                    | &gt;= 4.0.0  |
| ProductOfferServicePointMerchantPortalGui        | &gt;= 3.0.0  |
| ProductOfferShipmentTypeMerchantPortalGui        | &gt;= 3.0.0  |
| SalesMerchantPortalGui                           | &gt;= 4.0.0  |
| SecurityMerchantPortalGui                        | &gt;= 4.0.0  |
| UserMerchantPortalGui                            | &gt;= 4.0.0  |
| ZedUi                                            | &gt;= 4.0.0  |

If they don&apos;t, update the module versions manually or by using the following command:

```bash
composer require spryker-feature/marketplace-comments spryker-feature/marketplace-merchant-contract-requests spryker-feature/marketplace-merchant-contracts spryker-feature/marketplace-merchant-custom-prices spryker-feature/marketplace-merchant-portal-product-management spryker-feature/marketplace-merchant-portal-product-offer-management spryker-feature/marketplace-merchant-portal-product-offer-service-points spryker-feature/marketplace-merchantportal-core spryker-feature/merchant-portal-data-import spryker/agent-dashboard-merchant-portal-gui:&quot;^2.0.0&quot; spryker/agent-security-merchant-portal-gui:&quot;^2.0.0&quot; spryker/dashboard-merchant-portal-gui:&quot;^4.0.0&quot; spryker/merchant-app-merchant-portal-gui:&quot;^2.0.0&quot; spryker/merchant-profile-merchant-portal-gui:&quot;^4.0.0&quot; spryker/sales-merchant-portal-gui:&quot;^4.0.0&quot; --update-with-dependencies
```

2. Regenerate the data transfer object:

```bash
console transfer:generate
```

## 2) Update npm dependencies

In `package.json`, do the following:

1. Adjust the npm scripts and engines:

    ```json
    {
        &quot;scripts&quot;: {
            &quot;mp:build&quot;: &quot;ng build&quot;,
            &quot;mp:build:watch&quot;: &quot;ng build --watch&quot;,
            &quot;mp:build:production&quot;: &quot;ng build --configuration production&quot;,
            &quot;mp:stylelint&quot;: &quot;node ./frontend/merchant-portal/stylelint.mjs&quot;,
            &quot;mp:lint&quot;: &quot;ng lint&quot;,
            &quot;mp:test&quot;: &quot;ng test&quot;,
        },

        &quot;engines&quot;: {
            &quot;node&quot;: &quot;&gt;=20.19.0&quot;,
            &quot;npm&quot;: &quot;&gt;=10.0.0&quot;
        },
    }
    ```

2. Update or add the following dependencies:

```json
{
    &quot;dependencies&quot;: {
        &quot;@angular/animations&quot;: &quot;~20.3.16&quot;,
        &quot;@angular/cdk&quot;: &quot;~20.2.14&quot;,
        &quot;@angular/common&quot;: &quot;~20.3.16&quot;,
        &quot;@angular/compiler&quot;: &quot;~20.3.16&quot;,
        &quot;@angular/core&quot;: &quot;~20.3.16&quot;,
        &quot;@angular/elements&quot;: &quot;~20.3.16&quot;,
        &quot;@angular/forms&quot;: &quot;~20.3.16&quot;,
        &quot;@angular/platform-browser&quot;: &quot;~20.3.16&quot;,
        &quot;@angular/platform-browser-dynamic&quot;: &quot;~20.3.16&quot;,
        &quot;@angular/router&quot;: &quot;~20.3.16&quot;,
        &quot;ng-zorro-antd&quot;: &quot;~20.4.4&quot;,
        &quot;rxjs&quot;: &quot;~7.8.2&quot;,
        &quot;zone.js&quot;: &quot;~0.15.1&quot;
    }
}
```

3. Update or add the following dev dependencies:

    ```json
    {
        &quot;devDependencies&quot;: {
            &quot;@angular-builders/custom-webpack&quot;: &quot;~20.0.0&quot;,
            &quot;@angular-builders/jest&quot;: &quot;~20.0.0&quot;,
            &quot;@angular-devkit/build-angular&quot;: &quot;~20.3.14&quot;,
            &quot;@angular-eslint/builder&quot;: &quot;~20.7.0&quot;,
            &quot;@angular-eslint/eslint-plugin&quot;: &quot;~20.7.0&quot;,
            &quot;@angular-eslint/eslint-plugin-template&quot;: &quot;~20.7.0&quot;,
            &quot;@angular-eslint/template-parser&quot;: &quot;~20.7.0&quot;,
            &quot;@angular/cli&quot;: &quot;~20.3.14&quot;,
            &quot;@angular/compiler-cli&quot;: &quot;~20.3.16&quot;,
            &quot;@angular/language-service&quot;: &quot;~20.3.16&quot;,
            &quot;@babel/plugin-transform-class-properties&quot;: &quot;~7.25.9&quot;,
            &quot;@babel/plugin-transform-runtime&quot;: &quot;~7.28.5&quot;,
            &quot;@babel/preset-env&quot;: &quot;~7.28.6&quot;,
            &quot;@babel/preset-typescript&quot;: &quot;~7.28.5&quot;,
            &quot;@eslint/js&quot;: &quot;^9.39.2&quot;,
            &quot;@types/jest&quot;: &quot;~30.0.0&quot;,
            &quot;@types/node&quot;: &quot;~25.0.9&quot;,
            &quot;@types/webpack&quot;: &quot;~5.28.5&quot;,
            &quot;@typescript-eslint/eslint-plugin&quot;: &quot;~8.53.0&quot;,
            &quot;@typescript-eslint/parser&quot;: &quot;~8.53.0&quot;,
            &quot;angular-eslint&quot;: &quot;^21.1.0&quot;,
            &quot;eslint&quot;: &quot;~9.39.2&quot;,
            &quot;eslint-plugin-deprecation&quot;: &quot;^3.0.0&quot;,
            &quot;fast-glob&quot;: &quot;~3.3.3&quot;,
            &quot;jest&quot;: &quot;~30.2.0&quot;,
            &quot;jest-environment-jsdom&quot;: &quot;~30.2.0&quot;,
            &quot;jest-preset-angular&quot;: &quot;~16.0.0&quot;,
            &quot;typescript&quot;: &quot;~5.9.3&quot;,
            &quot;typescript-eslint&quot;: &quot;^8.53.0&quot;,
        }
    }
    ```

4. Remove the following dependencies:

    ```json
    {
        &quot;devDependencies&quot;: {
            &quot;@nx/angular&quot;: &quot;~18.1.1&quot;,
            &quot;@nx/eslint&quot;: &quot;~18.1.2&quot;,
            &quot;@nx/eslint-plugin&quot;: &quot;~18.1.2&quot;,
            &quot;@nx/jest&quot;: &quot;~18.1.2&quot;,
        }
    }
    ```

5. Update and install the package dependencies:

```bash
rm -rf node_modules
npm install
```

{% info_block warningBox &quot;Verification&quot; %}

Ensure that you update both the `package-lock.json` file and the `node_modules` directory.

{% endinfo_block %}

## 3) Update the Angular configuration

1. In the `frontend/merchant-portal` folder, do the following:

   1. In `jest.config.ts`, change the paths for configuration:

        ```ts
           export default {
                displayName: &apos;merchant-portal&apos;,
                preset: &apos;jest-preset-angular&apos;,
                setupFilesAfterEnv: [&apos;&lt;rootDir&gt;/frontend/merchant-portal/test-setup.ts&apos;],
                roots: [&apos;&lt;rootDir&gt;/src/Pyz&apos;],
                testMatch: [&apos;**/+(*.)+(spec|test).+(ts|js)?(x)&apos;],
                moduleFileExtensions: [&apos;ts&apos;, &apos;js&apos;, &apos;html&apos;],
                passWithNoTests: true,
                globals: {
                    &apos;ts-jest&apos;: {
                        tsconfig: &apos;&lt;rootDir&gt;/frontend/merchant-portal/tsconfig.spec.json&apos;,
                        stringifyContentPathRegex: &apos;\\.(html|svg)$&apos;,
                    },
                },
            } 
        ```

   2. In `test-setup.ts`, replace `jest-preset-angular/setup-jest` import to `jest-preset-angular/setup-env/zone`:

        ```ts
            import &apos;jest-preset-angular/setup-env/zone&apos;;
            import &apos;reflect-metadata/lite&apos;;
        ```

2. In the root of the project, do the following:

   1. Add `**/.angular/` to `.gitignore` and `.prettierignore`.

    ```text
        **/.angular/
    ```

   2. Delete `project.json`, `nx.json`, `eslintrc.mp.json`.
   3. Add the `eslint.config.mjs` with the following configuration:

   ```js
    import typescriptEslint from &apos;@typescript-eslint/eslint-plugin&apos;;
    import typescriptParser from &apos;@typescript-eslint/parser&apos;;
    import deprecationPlugin from &apos;eslint-plugin-deprecation&apos;;
    import angularEslint from &apos;angular-eslint&apos;;
    import { createRequire } from &apos;module&apos;;

    const require = createRequire(import.meta.url);
    const sprykerConfig = require(&apos;@spryker/frontend-config.eslint/.eslintrc.js&apos;);

    export default [
        {
            ignores: [
                &apos;docker/&apos;,
                &apos;public/*/assets/&apos;,
                &apos;**/dist/&apos;,
                &apos;**/node_modules/&apos;,
                &apos;vendor/&apos;,
                &apos;**/.angular/&apos;,
            ],
        },
        // Configuration for regular JS files
        {
            files: [&apos;**/*.js&apos;],
            languageOptions: {
                ecmaVersion: 2020,
                sourceType: &apos;module&apos;,
                globals: {
                    ...sprykerConfig.globals,
                },
            },
            rules: {
                ...sprykerConfig.rules,
                &apos;accessor-pairs&apos;: [
                    &apos;error&apos;,
                    {
                        setWithoutGet: true,
                        enforceForClassMembers: false,
                    },
                ],
            },
        },
        // Configuration for Yves TypeScript files
        {
            files: [&apos;src/{Pyz,SprykerShop,SprykerFeature}/*/src/{Pyz,SprykerShop,SprykerFeature}/Yves/**/*.ts&apos;],
            languageOptions: {
                parser: typescriptParser,
                parserOptions: {
                    ecmaVersion: 2020,
                    sourceType: &apos;module&apos;,
                    project: [&apos;./tsconfig.yves.json&apos;],
                },
                globals: {
                    ...sprykerConfig.globals,
                },
            },
            plugins: {
                &apos;@typescript-eslint&apos;: typescriptEslint,
                deprecation: deprecationPlugin,
            },
            rules: {
                ...sprykerConfig.rules,
                &apos;no-undef&apos;: &apos;off&apos;,
                &apos;no-unused-vars&apos;: &apos;off&apos;,
                &apos;accessor-pairs&apos;: [
                    &apos;error&apos;,
                    {
                        setWithoutGet: true,
                        enforceForClassMembers: false,
                    },
                ],
                &apos;@typescript-eslint/no-unused-vars&apos;: [
                    &apos;error&apos;,
                    {
                        args: &apos;none&apos;,
                        ignoreRestSiblings: true,
                    },
                ],
                &apos;@typescript-eslint/no-empty-function&apos;: [
                    &apos;error&apos;,
                    {
                        allow: [&apos;methods&apos;],
                    },
                ],
                &apos;@typescript-eslint/no-magic-numbers&apos;: [
                    &apos;error&apos;,
                    {
                        ignore: [-1, 0, 1],
                        ignoreDefaultValues: true,
                        ignoreClassFieldInitialValues: true,
                        ignoreArrayIndexes: true,
                        ignoreEnums: true,
                        ignoreReadonlyClassProperties: true,
                    },
                ],
            },
        },
        // Configuration for Merchant Portal TypeScript files
        {
            files: [&apos;src/Pyz/Zed/*/Presentation/Components/**/*.ts&apos;],
            languageOptions: {
                parser: typescriptParser,
                parserOptions: {
                    ecmaVersion: 2020,
                    sourceType: &apos;module&apos;,
                    project: [&apos;./tsconfig.mp.json&apos;],
                },
            },
            plugins: {
                &apos;@typescript-eslint&apos;: typescriptEslint,
                &apos;@angular-eslint&apos;: angularEslint.tsPlugin,
            },
            processor: angularEslint.processInlineTemplates,
            rules: {
                ...sprykerConfig.rules,
                &apos;no-undef&apos;: &apos;off&apos;,
                &apos;no-unused-vars&apos;: &apos;off&apos;,
                &apos;no-console&apos;: [
                    &apos;warn&apos;,
                    {
                        allow: [&apos;warn&apos;, &apos;error&apos;],
                    },
                ],
                &apos;no-empty&apos;: &apos;error&apos;,
                &apos;no-use-before-define&apos;: &apos;off&apos;,
                &apos;max-classes-per-file&apos;: &apos;off&apos;,
                &apos;max-lines&apos;: &apos;off&apos;,
                &apos;handle-callback-err&apos;: &apos;off&apos;,
                &apos;@typescript-eslint/array-type&apos;: &apos;off&apos;,
                &apos;@typescript-eslint/no-restricted-imports&apos;: [&apos;error&apos;, &apos;rxjs/Rx&apos;],
                &apos;@typescript-eslint/no-unused-vars&apos;: &apos;error&apos;,
                &apos;@typescript-eslint/no-inferrable-types&apos;: [
                    &apos;error&apos;,
                    {
                        ignoreParameters: true,
                    },
                ],
                &apos;@typescript-eslint/no-non-null-assertion&apos;: &apos;error&apos;,
                &apos;@typescript-eslint/no-var-requires&apos;: &apos;off&apos;,
                &apos;@typescript-eslint/no-explicit-any&apos;: &apos;error&apos;,
                &apos;@typescript-eslint/member-ordering&apos;: [
                    &apos;error&apos;,
                    {
                        default: [&apos;instance-field&apos;, &apos;instance-method&apos;, &apos;static-field&apos;, &apos;static-method&apos;],
                    },
                ],
                &apos;@angular-eslint/directive-selector&apos;: [
                    &apos;error&apos;,
                    {
                        type: &apos;attribute&apos;,
                        prefix: &apos;mp&apos;,
                        style: &apos;camelCase&apos;,
                    },
                ],
                &apos;@angular-eslint/component-selector&apos;: [
                    &apos;error&apos;,
                    {
                        type: &apos;element&apos;,
                        prefix: &apos;mp&apos;,
                        style: &apos;kebab-case&apos;,
                    },
                ],
                &apos;@angular-eslint/no-host-metadata-property&apos;: &apos;off&apos;,
            },
        },
        // Configuration for Merchant Portal HTML templates
        {
            files: [&apos;src/Pyz/Zed/*/Presentation/Components/**/*.html&apos;],
            languageOptions: {
                parser: angularEslint.templateParser,
            },
            plugins: {
                &apos;@angular-eslint&apos;: angularEslint.templatePlugin,
            },
            rules: {
                &apos;@typescript-eslint/ban-types&apos;: &apos;off&apos;,
                &apos;@typescript-eslint/ban-ts-comment&apos;: &apos;off&apos;,
                &apos;@typescript-eslint/no-empty-interface&apos;: &apos;off&apos;,
                &apos;@typescript-eslint/no-explicit-any&apos;: &apos;off&apos;,
                &apos;@typescript-eslint/no-unused-vars&apos;: &apos;off&apos;,
                &apos;@angular-eslint/no-host-metadata-property&apos;: &apos;off&apos;,
                &apos;@angular-eslint/directive-class-suffix&apos;: &apos;off&apos;,
                &apos;no-prototype-builtins&apos;: &apos;off&apos;,
            },
        },
    ];
   ```

   4. Add `angular.json`, with the following configuration:

   ```json
    {
        &quot;$schema&quot;: &quot;./node_modules/@angular/cli/lib/config/schema.json&quot;,
        &quot;version&quot;: 1,
        &quot;newProjectRoot&quot;: &quot;src&quot;,
        &quot;projects&quot;: {
            &quot;merchant-portal&quot;: {
                &quot;projectType&quot;: &quot;application&quot;,
                &quot;schematics&quot;: {},
                &quot;root&quot;: &quot;&quot;,
                &quot;sourceRoot&quot;: &quot;.&quot;,
                &quot;prefix&quot;: &quot;mp&quot;,
                &quot;architect&quot;: {
                    &quot;build&quot;: {
                        &quot;builder&quot;: &quot;@angular-builders/custom-webpack:browser&quot;,
                        &quot;options&quot;: {
                            &quot;customWebpackConfig&quot;: {
                                &quot;path&quot;: &quot;./frontend/merchant-portal/webpack.config.ts&quot;,
                                &quot;mergeRules&quot;: {}
                            },
                            &quot;indexTransform&quot;: &quot;./frontend/merchant-portal/html-transform.js&quot;,
                            &quot;outputPath&quot;: &quot;public/MerchantPortal/assets/js&quot;,
                            &quot;baseHref&quot;: &quot;/assets/js/&quot;,
                            &quot;index&quot;: &quot;src/Pyz/Zed/ZedUi/Presentation/Components/index.html&quot;,
                            &quot;main&quot;: &quot;src/Pyz/Zed/ZedUi/Presentation/Components/main.ts&quot;,
                            &quot;polyfills&quot;: &quot;src/Pyz/Zed/ZedUi/Presentation/Components/polyfills.ts&quot;,
                            &quot;tsConfig&quot;: &quot;tsconfig.mp.json&quot;,
                            &quot;assets&quot;: [
                                {
                                    &quot;glob&quot;: &quot;*/src/Spryker/Zed/*/Presentation/Components/assets/**/*&quot;,
                                    &quot;input&quot;: &quot;vendor/spryker&quot;,
                                    &quot;output&quot;: &quot;/assets/&quot;,
                                    &quot;ignore&quot;: [&quot;**/.gitkeep&quot;]
                                },
                                {
                                    &quot;glob&quot;: &quot;*/Presentation/Components/assets/**/*&quot;,
                                    &quot;input&quot;: &quot;src/Pyz/Zed&quot;,
                                    &quot;output&quot;: &quot;/assets/&quot;,
                                    &quot;ignore&quot;: [&quot;**/.gitkeep&quot;]
                                },
                                {
                                    &quot;glob&quot;: &quot;*/data/files/**/*&quot;,
                                    &quot;input&quot;: &quot;vendor/spryker&quot;,
                                    &quot;output&quot;: &quot;/static/&quot;,
                                    &quot;ignore&quot;: [&quot;**/.gitkeep&quot;]
                                },
                                {
                                    &quot;glob&quot;: &quot;*/data/files/**/*&quot;,
                                    &quot;input&quot;: &quot;src/Pyz/Zed&quot;,
                                    &quot;output&quot;: &quot;/static/&quot;,
                                    &quot;ignore&quot;: [&quot;**/.gitkeep&quot;]
                                }
                            ],
                            &quot;styles&quot;: [
                                &quot;vendor/spryker/zed-ui/src/Spryker/Zed/ZedUi/Presentation/Components/styles.less&quot;,
                                &quot;src/Pyz/Zed/ZedUi/Presentation/Components/styles.less&quot;
                            ],
                            &quot;scripts&quot;: []
                        },
                        &quot;configurations&quot;: {
                            &quot;development&quot;: {
                                &quot;buildOptimizer&quot;: false,
                                &quot;optimization&quot;: false,
                                &quot;vendorChunk&quot;: true,
                                &quot;extractLicenses&quot;: false,
                                &quot;sourceMap&quot;: true,
                                &quot;namedChunks&quot;: true
                            },
                            &quot;production&quot;: {
                                &quot;fileReplacements&quot;: [
                                    {
                                        &quot;replace&quot;: &quot;src/Pyz/Zed/ZedUi/Presentation/Components/environments/environment.ts&quot;,
                                        &quot;with&quot;: &quot;src/Pyz/Zed/ZedUi/Presentation/Components/environments/environment.prod.ts&quot;
                                    }
                                ],
                                &quot;optimization&quot;: {
                                    &quot;scripts&quot;: true,
                                    &quot;styles&quot;: {
                                        &quot;minify&quot;: true,
                                        &quot;inlineCritical&quot;: false
                                    }
                                },
                                &quot;outputHashing&quot;: &quot;none&quot;,
                                &quot;sourceMap&quot;: false,
                                &quot;namedChunks&quot;: false,
                                &quot;extractLicenses&quot;: true,
                                &quot;vendorChunk&quot;: true,
                                &quot;buildOptimizer&quot;: true,
                                &quot;budgets&quot;: [
                                    {
                                        &quot;type&quot;: &quot;bundle&quot;,
                                        &quot;maximumWarning&quot;: &quot;2mb&quot;,
                                        &quot;maximumError&quot;: &quot;5mb&quot;
                                    }
                                ]
                            }
                        },
                        &quot;defaultConfiguration&quot;: &quot;development&quot;
                    },
                    &quot;lint&quot;: {
                        &quot;builder&quot;: &quot;@angular-eslint/builder:lint&quot;,
                        &quot;options&quot;: {
                            &quot;lintFilePatterns&quot;: [
                                &quot;src/Pyz/Zed/*/Presentation/Components/**/*.ts&quot;,
                                &quot;src/Pyz/Zed/*/Presentation/Components/**/*.html&quot;
                            ]
                        }
                    },
                    &quot;test&quot;: {
                        &quot;builder&quot;: &quot;@angular-builders/jest:run&quot;,
                        &quot;options&quot;: {
                            &quot;tsConfig&quot;: &quot;frontend/merchant-portal/tsconfig.spec.json&quot;,
                            &quot;configPath&quot;: &quot;frontend/merchant-portal/jest.config.ts&quot;
                        }
                    }
                }
            }
        },
        &quot;cli&quot;: {
            &quot;analytics&quot;: false
        }
    }
   ```

   5. Update the `node` and `npm` versions in all deploy YAML files.

   ```yaml
   ...
    node:
        version: 20
        npm: 10
   ...
   ```

## 4) Component breaking changes

Below is a checklist of component-related breaking changes to review when upgrading from Angular 18 to Angular 20 in a Spryker Merchant Portal (NgModule-based architecture).

1. **Explicitly set `standalone: false` for NgModule-based components**
   - **What to do:** For all `@Component()`, `@Directive()`, and `@Pipe()` declarations that are registered via `NgModule.declarations`, explicitly add `standalone: false`.
   - **Why:** Starting with newer Angular major versions v19+, Angular shifts toward standalone-first behavior. Without an explicit flag, components may be treated as standalone, resulting in build errors.

2. **Ensure standalone components do not implicitly require `imports`**
   - **What to do:** If any component unintentionally becomes standalone, verify that it does not break template features such as `*ngIf`, `*ngFor`, or `*ngSwitch` due to missing `CommonModule`.
   - **Why:** Standalone components must explicitly declare dependencies via `imports`. In the Merchant Portal setup, it is safer to keep components NgModule-based and enforce `standalone: false`.

3. **Review `NgModule` metadata (declarations, imports, exports)**
   - **What to do:** Verify that:
     - All externally used components are listed in `exports`.
     - All required modules are included in `imports`.
     - No standalone components are incorrectly declared.
   - **Why:** Angular v20 applies stricter validation to module metadata, and previously tolerated misconfigurations may now fail at build time.

4. **Validate dynamic component creation**
   - **What to do:** For components created dynamically (for example via `createComponent`, `NgComponentOutlet`, CDK portals, or legacy `ComponentFactoryResolver` usage), ensure:
     - A valid `Injector` or `EnvironmentInjector` is provided
     - Required providers are available in the component context
   - **Why:** Angular enforces stricter DI and runtime checks, and misconfigured dynamic rendering can cause runtime errors.

5. **Enforce migration to the new template control flow syntax**
   - **What to do:** Actively migrate all templates to the new Angular control flow syntax (`@if`, `@for`, `@switch`) and avoid mixing it with legacy structural directives (`*ngIf`, `*ngFor`, `*ngSwitch`). New or modified templates must use the new syntax only.
   - **Why:** Legacy structural directives are considered deprecated. Mixing old and new syntaxes within the same module increases cognitive load, complicates reviews, and leads to subtle and hard-to-debug template regressions. Enforcing a single, modern control flow standard improves consistency, readability, and long-term maintainability.

## Reference Pull Request

As a practical example of upgrading Angular to v20 in a real project, you can review the following Pull Request:

&lt;https://github.com/spryker-shop/b2b-demo-marketplace/pull/857&gt;

{% info_block warningBox &quot;Important&quot; %}

This Pull Request contains **additional changes that are not required for the Angular upgrade**, including:
- Stylelint configuration updates
- Prettier configuration changes
- Other formatting and linting-related adjustments

When using this Pull Request as a reference, **do not blindly apply all changes**.  
Focus only on the Angular-related modifications. The Stylelint and Prettier updates are optional and can be safely ignored for the purpose of upgrading Angular to v20.

{% endinfo_block %}
</description>
            <pubDate>Fri, 30 Jan 2026 15:15:25 +0000</pubDate>
            <link>https://docs.spryker.com/docs/dg/dev/upgrade-and-migrate/upgrade-to-angular-20.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/dg/dev/upgrade-and-migrate/upgrade-to-angular-20.html</guid>
            
            
        </item>
        
        <item>
            <title>Preparation for going live</title>
            <description>{% info_block warningBox &quot;Don&apos;t risk your go-live&quot; %}

The preparation steps listed here are mandatory because they&apos;re crucial for the success of your go-live. We strongly encourage you, customer or partner, to complete these steps where applicable because we won&apos;t be able to resolve issues related to steps not completed in time. Make sure that your project plan contains the tasks related to the go-live checklist and allocates enough time for their completion.

{% endinfo_block %}


This document describes how to prepare a Spryker project for going live.

We&apos;ve divided the preparation into approximate timeframes. Feel free to copy this to your project management software and adjust to your needs. Make sure that all of the following tasks are completed at least one week before going live.

## Eight weeks before go-live

| ID     | CATEGORY                                                 | NAME                                                         | DESCRIPTION                                                                                                                                                                                                                                                                                                                                                  | NOTE                                                                                                                                                                                                                                                                        |
|--------|----------------------------------------------------------|--------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| GEN-01 | General         | Share go-live plan                       | Inform your Partner or Customer Success Manager about your go-live date and time. &lt;br&gt; Create a Go Live Announcement case in [Support Portal](https://support.spryker.com/s/). &lt;br&gt; Update them if plans change.  | This is critical for Domain Name System (DNS) switching and the hypercare phase we provide before and after go-live.   |
| CLO-01 | Cloud | Ensure a network diagram  | Ensure a network diagram is available for quick reference to explain the setup if needed.   | Sample of the [diagram](https://docs.spryker.com/docs/dg/dev/sdks/the-docker-sdk/docker-environment-infrastructure.html).                  |
| CLO-02 | Cloud                          | Third-party systems integration                              | Double-check that all Virtual Private Cloud (VPC) peering and Site-to-Site Virtual Private Network (VPN) connections are monitored and secure.                | We don&apos;t monitor connections with external parties. For more details, see [site-to-site VPN](/docs/ca/dev/environment-provisioning.html#optional-site-to-site-vpn).                   |
| CLO-03 | Cloud                          | Third-party systems integration                              | Make sure that routing works as expected and no internal resources are accidentally exposed via the site-to-site VPN or VPC peering setup.                                                                                                                                                                                                                  |               |
| CLO-04 | Cloud                          | Evaluate DOS and DDOS prevention (frontend)                  | Check your concepts for denial-of-service (DOS) and distributed denial-of-service (DDOS) prevention or mitigation, and check with relevant vendors for products that fit your needs and are compatible with SCCOS.               |                |
| CLO-05 | Cloud                          | Evaluate DOS and DDOS prevention (backend / Merchant Portal) | Check your concepts for DOS and DDOS prevention in the Back office and Merchant portal. Add basic auth if applicable.                              | For instructions on implementing basic auth, see [Configure basic .htaccess authentication](/docs/pbc/all/identity-access-management/{{site.version}}/configure-basic-htaccess-authentication.html)       |
| CLO-06 | Cloud                          | Define a DNS strategy                                          | Define how you want to handle the DNS of the shop&apos;s domain.                | If you delegate DNS to Spryker, let us know the date on which to point the domain to your project.         |
| CLO-07 | Cloud                          | Set up whitelisting (security)                               | IPs of Web Application Firewalls (WAF), proxies, and other security and traffic filtering systems used to route traffic to Spryker are whitelisted. | This prevents these systems to be accidentally blocked by Spryker&apos;s security systems. You can request IPs to be whitelisted via an Infrastructure Change Request on the [Support Portal](https://support.spryker.com/s/).             |
| APP-01 | Application                    | Activate IP tracking | [Activating IP tracking](https://github.com/spryker/docker-sdk/blob/master/docs/07-deploy-file/02-deploy.file.reference.v1.md#cloud-define-gateway-ip-addresses) significantly increases chances to mitigate or spot malicious activities such as DOS attacks. You might need to evaluate this from a data protection policy perspective. | |
| APP-02 | Application                    | Upgrade codebase                                                 | Upgrade the project&apos;s codebase to the [latest Demo Shop release](/docs/about/all/releases/product-and-code-releases.html) or at least to 202009.0 release.           | |
| APP-03 | Application                    | Upgrade Twig                                          | Update `spryker/twig` to version 3.15.2 or later. | This version introduces important stability improvements.              |
| APP-04 | Application                    | Migrate to MariaDB                                        | Migrate the project&apos;s database to MariaDB if applicable.                                                     | |
| APP-05 | Application                    | Migrate endpoints                                            | Split Zed endpoints as described in [Integrating separate endpoint bootstraps](/docs/dg/dev/integrate-and-configure/integrate-separate-endpoint-bootstraps.html) if applicable.                                                                                                                                                   |                           |
| APP-06 | Application                    | Check service naming                                           | Verify that the service naming scheme exactly matches the examples in the [sample deploy-spryker-b2c-staging.yml file](https://github.com/spryker-shop/b2c-demo-shop/blob/202204.0-p2/deploy.spryker-b2c-staging.yml).                                                                                                                            | |
| APP-07 | Application                    | Create a deploy file                                         | Create [deploy files](/docs/dg/dev/sdks/the-docker-sdk/deploy-file/deploy-file.html) for each of your environments. File names must follow the naming convention: `deploy.(project)-(environment).yml`. For example, `deploy.example-staging.yml`.                        | |
| APP-08 | Application                    | Define Docker SDK version                                    | [Define a Docker SDK version](/docs/dg/dev/sdks/the-docker-sdk/choosing-a-docker-sdk-version.html).              | |
| APP-09 | Application                    | Integrate FlySystem                                          | Configure the project to use S3 buckets for storage using [FlySystem](/docs/ca/dev/configure-data-import-from-an-s3-bucket.html).         |    |
| APP-10 | Application                    | Check S3 bucket import                                       | If you&apos;re using CSV imports, make sure they&apos;re imported from S3 buckets. |   |
| APP-11 | Application                   | Set up S3 bucket (staging)                                   | Connect Staging S3 bucket to the staging environment.                                       |    |
| APP-12 | Application                    | Set up S3 bucket (production)                                | Connect Production S3 bucket to the production environment.                                      |   |
| APP-13 | Application                    | Implement performance guidelines                     | Implement [performance guidelines](/docs/dg/dev/guidelines/performance-guidelines/performance-guidelines.html). |    |
| APP-14 | Application                    | Implement Jenkins guidelines                                 | Implement [Jenkins operational best practices](/docs/ca/dev/best-practices/jenkins-operational-best-practices.html). | |
| APP-15 | Application                    | Implement publish and sync guidelines                        | Implement applicable [Publish and Sync stability best practices](/docs/ca/dev/best-practices/best-practises-jenkins-stability.html). |   |
| APP-16 | Application                    | Implement general security guidelines                        | Apply [security guidelines](/docs/dg/dev/guidelines/security-guidelines.html).                    | |
| APP-17 | Application                    | Implement password security guidelines                       | Make sure that you don&apos;t have any plain-text passwords, private keys, or API secrets in config files or Git repositories. | |
| APP-18 | Application                    | Implement credentials security guidelines                    | Minimize the use of personal credentials and use separate work-specific accounts per envrironemnt. We highly recommend employing Centralized Credential Management to securely store and manage these credentials. |    |
| APP-19 | Application                    | Implement secrets rotations                                  | Secrets, like API tokens, should be rotated regularly. Outline and test rotation strategies to prevent issues during live operation. | |
| APP-20 | Application                    | Install internal security updates                | Install all the [security updates](/docs/about/all/releases/product-and-code-releases.html) from all Spryker packages. |  |
| APP-21 | Application                    | Install external security updates                | Install all the security updates from all the external packages.  | To check if your project modules require security updates, you can use the [security checker](/docs/dg/dev/guidelines/keeping-a-project-upgradable/upgradability-guidelines/spryker-security-checker.html). |
| APP-22 | Application                    | Perform compliance and legal checks.                      | To ensure the platform complies with relevant legal and regulatory requirements, especially for international operations, consult with your legal team. Make sure to check [guidelines for GDPR compliance](/docs/about/all/support/gdpr-compliance-guidelines.html). |   |
| APP-23 | Application                    | Set up Access Control List (ACL)                             | Prepare the Back Office ACL setup for users to be able to access and manage the shop during live operation.  | For instructions on how to configure ACL, see [Users and rights overview](/docs/pbc/all/user-management/{{site.version}}/base-shop/user-and-rights-overview.html). |
| APP-24 | Application                    | Set up DB logs strategy                                      | If the application is writing logs into the DB, develop a strategy on regularly rotating or [truncating](/docs/dg/dev/troubleshooting/troubleshooting-general-technical-issues/database-tables-take-up-too-much-space-or-have-id-overflow.html) these logs to avoid large table sizes that can affect the application&apos;s performance.           | `spy_oms_transition_log` is used to log state machine transitions by default. |
| APP-25 | Application                    | Evaluate and implement payment tips                          | Check if you can implement redundant payment options so that the payment system keeps working even if one of the options fail. |   |
| TES-01 | Testing                        | Test deployment                                     | Run deployment tests locally to ensure the application can be installed and configured as expected. For instructions on deploying locally, see [Simulating deployments locally](/docs/dg/dev/miscellaneous-guides/simulating-deployments-locally.html).  | Criteria: Deployment executes without errors, and the application operates as expected in a test environment. |
| TES-02 | Testing                        | Test payment                                   | Before deploying payment options, test payment end-to-end flows locally. For more information, see [HowTo: Debug payment integrations locally](/docs/pbc/all/payment-service-provider/{{site.version}}/base-shop/debug-payment-integrations-locally.html).  | Criteria: All payment methods process payments without errors. Test both positive and negative cases such as handling a rejected payment. |
| TES-03 | Testing                        | Perform UAT                                                  | Perform User Acceptance Testing (UAT) to validate the functionality and user experience from an end-user perspective. Collaborate with stakeholders to create UAT scenarios for main business flows, execute tests, and gather feedback. Verify that the platform application works properly on supported devices and browsers. |    |
| SEO-01 | SEO | Set up redirects                                             | If you&apos;re migrating from another shop or project to Spryker, and the domain is already point to a live shop, prepare a migration plan to phase out the old project and phase in the new one. Check with your SEO experts on the strategy for your content and search engine results. |   |
| SEO-02 | SEO | Implement SEO best practices                                 | Review and implement the best practices per [Basic SEO techniques to use in your project](/docs/dg/dev/best-practices/basic-seo-techniques-to-use-in-your-project.html). |     |
| TR-01 | Training | Prepare internal training                                    | Prepare role-specific enablement training for all internal users of the platform. | These may include: Back Office administrators, support assistants and agents, marketplace operators, merchant portal users. |
| TR-02 | Training | Prepare external training                                    | Prepare trainings for external users, such as those interacting with the platform via APIs and third-party systems. | These may include API documentation. |
| TR-03 | Training | Prepare customer training                                    | Make sure your customers are aware of the changes that are to be introduced. Besides striving for good user experience and transparency, consult with your legal team about any obligations in that regard. |    |

## Four weeks before go-live


| ID     | CATEGORY    | NAME                                                   | DESCRIPTION                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | NOTE                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
|--------|-------------|--------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| GEN-02 | General   | Prepare a rollback strategy                               | Prepare everything for recovering from unforeseen issues after deploying the project. | |
| CLO-08 | Cloud      | Set up APM                                             | We highly recommend setting up an Application Performance Monitoring (APM) system.             | APM tools help you identify performance bottlenecks in your application.     |
| CLO-09 | Cloud      | Establish a post-launch monitoring plan                  | To watch the system&apos;s performance and configure alerting mechanisms, establish a robust post-launch monitoring plan. To ensure effective investigation in case of security incidents, we recommend configuring logs to gather in a centralized SIEM system.    |      |
| CLO-10 | Cloud      | Set up deploy file                                     | Verify that your deploy file is set up correctly and aligns with your project needs. Verify that your project works and operates the production endpoints. You can set both testing and production endpoints in your deploy file. Your developers need to mock a &quot;live&quot; operation of the project with its production endpoints by adjusting their local host entries.                                         |      |
| CLO-11 | Cloud      | Deploy production environment                          | Deploy the production environment regularly. This lets you detect potential issues early enough to fix them before going live. For instructions, see [Deploying in a production environment](/docs/ca/dev/deploy-in-a-production-environment.html). Make sure to test all [recipes](/docs/dg/dev/sdks/the-docker-sdk/installation-recipes-of-deployment-pipelines.html#staging-and-production-environment-recipes).      |           |
| CLO-12 | Cloud       | Prepare a DNS strategy                                   | Decide how you want customers to access your shop and verify that you control access and can manage the DNS. For example, the domain of your shop is `spryker.com`, but you want customers to access the Storefront at `www.spryker.com`. For details on how to set up DNS, see [Set up DNS](/docs/ca/dev/set-up-dns.html).&lt;br&gt;- Optional: Delegate DNS to Spryker. &lt;br&gt;- Make sure Transport Layer security (TLS) certificates are provisioned. If you delegate DNS to Spryker, TLS certificates for your endpoints are created automatically. If you want us to create TLS certificates for your endpoints but don&apos;t want to delegate your DNS, request the verification of DNS records through the [Support Portal](https://support.spryker.com). |    |
| CLO-13 | Cloud       | Choose an email service                      | You can use Spryker&apos;s native mail service or integrate a third-party provider. If you choose the native service, provide the sender email address so we can lift sending restrictions and assist with DNS validation. For more information about the default email service and its restrictions, see [Email service](/docs/ca/dev/email-service/email-service.html).  |         |
| APP-26 | Application | Prepare and communicate technical debt mitigation plan | Develop a comprehensive plan to identify, address, and communicate strategies for managing technical debt before the system goes live. Make sure that all the stakeholders are aware of missing or incomplete features and agree on the mitigation plan.                                                                                          |                                                         |
| APP-27 | Application | Check environment variables                            | Make sure all the required environment variables and parameter store values are set up. |                                 |
| APP-28 | Application | Prepare DB creation in production                      | Prepare and implement database creation in production. For example, commit Propel migration for production and update the deploy file to install the database from the committed migration files.   |        |
| TES-04 | Testing | Test third-party integrations on production            | - Collect instructions and requirements from the third-party providers for using services in production mode. &lt;br&gt;- Update integrations and plugins to use production credentials. &lt;br&gt;- Test all functionalities of the integrations and plugins to ensure they work as expected. &lt;br&gt;- Conduct load testing: Simulate real-world traffic on your application to assess its performance under load. This helps identify any bottlenecks that could cause performance issues during peak traffic times.    | In some cases, you may need to comply with specific additional security measures, such as IP whitelisting or port configuration. |
| TES-05 | Testing | Conduct load tests                                     | Test how the platform performs under real-life circumstances. Define the performance acceptance criteria - the sample testing data should be comparable to the size and complexity of the production data. Monitor the application&apos;s performance metrics, such as response times or resource usage, during the tests. &lt;br&gt; *Inform us about your load and performance test plans via the [Support Portal](https://support.spryker.com/s/) at least three days in advance and share the results so that we can fine-tune the environment to your requirements.*   | Some options to define key metrics: &lt;br&gt;- Historical data: if you have existing traffic data–for example, from Google Analytics &lt;br&gt;- [Industry benchmarks](https://databox.com/website-traffic-benchmarks-by-industry): research typical traffic volumes for similar e-commerce sites in your industry &lt;br&gt;- Business goals: Consider target sales, conversion rates, and marketing campaigns to estimate expected traffic. |
| TES-06 | Testing | Conduct stress and performance tests                   | Test your production environment and assess its performance. Because production environments typically employ horizontal auto-scaling, it&apos;s essential to test under expected average and peak loads. These tests enable our team to optimize the environment&apos;s vertical scaling in advance, ensuring that it can seamlessly handle the expected loads from the get-go without any potential delays caused by auto-scaling mechanisms. This proactive approach eliminates the need for post-launch adjustments. For more information, see [Environment scaling](https://docs.spryker.com/docs/ca/dev/environment-scaling.html). &lt;br&gt; *Inform us about your load and performance test plans via the [Support Portal](https://support.spryker.com/s/) at least three days in advance and share the results so that we can fine-tune the environment to your requirements.*      | Maintain active communication with us. Inform us about your load and performance test plans and share the results so that we can fine-tune the environment to meet your  requirements. |
| TES-07 | Testing | Conduct penetration testing                              | We highly recommend having the project penetration-tested by an independent third-party provider and addressing the identified vulnerabilities. Before conducting a penetration test, inform us at least two weeks in advance by filling out [this form](https://docs.google.com/forms/d/e/1FAIpQLSfunn1HY-nsqueP6sRQSLmScUWlmmQyQJk9cscIVIP_5BmuOw/viewform?usp=sf_link). |    |
| TES-08 | Testing | Import real data                                       | After importing real data to production, double-check the completeness and accuracy of the migrated data, especially if transitioning from another platform.  | Start working with data of realistic size and quality as early as possible. At this point, you must be importing data regularly to all your environments. We recommend working with the same import data across all environments. This significantly simplifies troubleshooting and helps you estimate import performance, leading up to your go-live and helping us with environment sizing considerations. |
| TES-09 | Testing | Test checkout and OMS                                  | Validate the checkout and OMS process: general checkout steps, shipment, payment, OMS. Test all checkout steps, including adding different items to the cart, entering shipping and billing information, selecting a payment method, and placing an order. Also, test the order fulfillment process to ensure that orders are processed and shipped correctly. |    |
| TES-10 | Testing | Test payment                                           | WAF and firewall settings in production environments are different from those in non-production ones. Therefore, make sure that all your requests have valid headers. Also, test the functionality of payment integrations that use call-backs or depend on API calls to your application in your production environment.|  Criteria: &lt;br&gt;- Make sure the headers of all API requests contain the production mode information to avoid security issues. &lt;br&gt;- Thoroughly test payment integrations that rely on external systems, such as callbacks or APIs, specifically in production. |
| DAT-01 | Data   | Prepare a data migration plan                          | Include all the data that needs to be migrated. |  |
| SEO-03 | SEO    | Generate sitemap                                       | Generate a sitemap. |  |
| SEO-04 | SEO    | Prepare and set `robots.txt`                                       | Prepare and set the `robots.txt` file. |     |
| SEO-05 | SEO    | Prepare and set static content                         | Prepare and set all the CMS pages and other content, such as meta tags or links. |    |
| SEO-06 | SEO    | Set up favicon                                         | Set up [favicon](https://en.wikipedia.org/wiki/Favicon). |      |

## Two weeks before go-live

| ID     | CATEGORY | NAME                                              | DESCRIPTION                                   | NOTE                                                                         |
|--------|----------|---------------------------------------------------|-----------------------------------------------|------------------------------------------------------------------------------|
| CLO-14 | Cloud    | Set up DNS                                        | [Set up DNS](/docs/ca/dev/set-up-dns.html). | |
| CLO-15 | Cloud    | Configure email                                   | Configure email boxes and DMARC policy. | |
| GEN-03 | General  | Implement code freeze                             | We recommend having a code freeze at least two weeks before going live. | |
| GEN-04 | General  | Evaluate go-live date and preceding tasks         | If any of the preceding tasks aren&apos;t complete, postpone your go-live or discuss with us how to complete them in time. DNS changes are especially sensitive to deadlines. Because of the way the DNS system works, any DNS changes take time to take effect. | |
| GEN-05 | General  | Set up third-party systems in production mode     | Make sure that the third-party systems have been switched to production mode. Set up production configuration for all third-party systems (in environment variables). Make sure not to expose secrets in the codebase. | |
| GEN-06 | General  | Set up BI and analytics tools in production mode  | BI and analytics integrations should not be connected to your production database but rather to the provided read replica. Make sure no external system is interacting with your production database. | |
| GEN-07 | General  | Establish a go-live support team                  | Establish a team that can monitor your go-live process, react quickly to any issues, and work with the Spryker Support or Operations teams. | |
| GEN-08 | General  | Define the exact plan for the go-live day         | Define the time of deployment. Define the exact steps to be performed, including running Jenkins or other scripts if needed. Prepare a go-live communication plan to inform stakeholders, customers, and support teams about the launch date and any changes or updates. | |
| TES-11 | Testing  | Perform end-to-end testing on production          | Test the customer journey with all the third-party systems switched to production mode. Make sure to cover all important flows:&lt;br&gt;- Customer registration, account management&lt;br&gt;- Main e-commerce flow: search, navigation, checkout, and OMS process&lt;br&gt;- Back Office and Merchant user flows | |
| DAT-02 | Data     | Remove demo data                                  | Remove all demo data from the environment. The project should only use real data that will be used after go-live. Remove all demo data that comes with the Spryker repository, which includes demo and admin users. Demo users in a live shop pose a significant security risk. | |
| DAT-03 | Data     | Import real data                                  | Import real data to the production environment:&lt;br&gt;- Categories&lt;br&gt;- Product data, such as prices, offers, or attributes&lt;br&gt;- Customers, companies, users, merchants&lt;br&gt;- Taxes&lt;br&gt;- Discounts&lt;br&gt;- CMS pages: homepage, CMS blocks, terms &amp; conditions&lt;br&gt;- Custom data&lt;br&gt;- Other data | Criteria: user journeys run as expected. No blockers or unaddressed high-priority bugs. All prepared test cases and checklists pass or don&apos;t block release. |
| DAT-04 | Data     | Set up translations                               | Double-check that all the required languages are available. | |
| DAT-05 | Data     | Define a glossary update strategy                 | Define the glossary update strategy. For example, exclude glossary updates during normal deployment. | |
| DAT-06 | Data     | Check emails                                      | Make sure that all emails are correct. Double-check that all required data and translations are available. | |
| SEO-07 | SEO      | Optional: Set up redirects                        | Set up redirects. | |


## Go-live

| ID     | CATEGORY                                     | NAME                                         | DESCRIPTION                                                                    | NOTE                                                                         |
|--------|----------------------------------------------|----------------------------------------------|--------------------------------------------------------------------------------|------------------------------------------------------------------------------|
| TES-12 | Testing | Perform end-to-end testing on production | Perform smoke testing on production. Because its final the stage, test the main business flows and third-party integrations. |  |
| CLO-16 | Cloud    | Disable email sending restrictions           | Disable email sending restrictions. |   |
| CLO-17 | Cloud    | Remove basic auth                            | Remove basic authentication from the frontend part and deploy the change. |    |
| GEN-9  | General  | Run the go-live communication plan           | Run the go-live communication plan. |   |
| CLO-18 | Cloud    | Disable destructive pipeline                 | Disable the destructive pipeline after a successful go-live. |    |
| GEN-10 | General  | Disable old system after 72 hours            | After pointing the domain name to your Spryker project, some of your customers may still see your old project until the DNS propagation is completed. So, keep it live for at least 72 hours after the migration. |    |

{% info_block infoBox &quot;Don&apos;t hesitate to contact us&quot; %}

If your go-live date is near and you need help with any of the tasks described, contact us via your Customer Success Manager *right away*. If you&apos;re a Spryker partner and unsure who the Customer Success Manager is for our joint customer, reach out to Partner Success Management via the [Partner Portal](https://partners.spryker.com/). They will connect you with the right contact for your project.

{% endinfo_block %}

























</description>
            <pubDate>Fri, 30 Jan 2026 12:42:51 +0000</pubDate>
            <link>https://docs.spryker.com/docs/ca/dev/preparation-for-going-live.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/ca/dev/preparation-for-going-live.html</guid>
            
            
        </item>
        
        <item>
            <title>Twig performance best practices</title>
            <description>Twig is a popular templating engine for PHP projects. Spryker built a sophisticated library of components on top of it. But with rich features, it also sometimes leads to performance degradation, caused by inefficient practices.

It is important to follow best practices related to Twig performance optimisations.

## Activate Twig compiler

Twig files can be precompiled into PHP classes to speed the performance up. This behavior can be activated in the configuration. We highly recommend using the `FORCE_BYTECODE_INVALIDATION` option. Otherwise, Opcache may contain outdated content, as the files are modified during runtime.

```php
---//---
use Twig\Cache\FilesystemCache;
---//---
$currentStore = Store::getInstance()-&gt;getStoreName();

$config[TwigConstants::ZED_TWIG_OPTIONS] = [
    &apos;cache&apos; =&gt; new FilesystemCache(
        sprintf(
            &apos;%s/src/Generated/Zed/Twig/codeBucket%s&apos;,
            APPLICATION_ROOT_DIR,
            $currentStore,
        ),
        FilesystemCache::FORCE_BYTECODE_INVALIDATION,
    ),
];

$config[TwigConstants::YVES_TWIG_OPTIONS] = [
    &apos;cache&apos; =&gt; new FilesystemCache(
        sprintf(
            &apos;%s/src/Generated/Yves/Twig/codeBucket%s&apos;,
            APPLICATION_ROOT_DIR,
            $currentStore,
        ),
        FilesystemCache::FORCE_BYTECODE_INVALIDATION,
    ),
];
```

## Activate Twig path cache

Twig files can be in many places. To avoid time-consuming searches, we recommend activating the path cache (active by default). If you need to change this configuration, see `\Spryker\Yves\Twig\TwigConfig::getCacheFilePath()`.

## Twig template warmup during deployment

Precompiling Twig templates can improve the performance of the first request, especially in production environments. This is helpful when scaling across multiple containers, where the first request may be slow due to on-demand compilation of all Twig templates.

It compiles Twig template files to PHP code during deployment. Allows each Yves container to start in a ready-to-use state, without the need to compile those templates in the scope of web requests. It is important to ensure that this feature is enabled on a project level inside a build recipe.

To activate the warmup, follow the steps:

1. Add the following commands to your deployment script, such as `config/install/docker.yml`:

```yaml
    build-production:
        twig-template-warmup-zed:
            command: &apos;vendor/bin/console twig:template:warmer&apos;

        twig-template-warmup-yves:
            command: &apos;vendor/bin/yves twig:template:warmer&apos;
```

{% info_block warningBox &quot;&quot; %}
Make sure that the command is executed after the `vendor/bin/console twig:cache:warmer` command.
{% endinfo_block %}


2. Register the following classes for the Zed command:

**\Spryker\Zed\Console\ConsoleDependencyProvider**

```php
...
use Spryker\Zed\Form\Communication\Plugin\Application\FormApplicationPlugin;
use Spryker\Zed\Security\Communication\Plugin\Application\ConsoleSecurityApplicationPlugin;
use Spryker\Zed\Twig\Communication\Console\TwigTemplateWarmerConsole;
...

    protected function getConsoleCommands(Container $container): array
    {
        return [
            // other commands
            new TwigTemplateWarmerConsole(),
        ];
    }

    public function getApplicationPlugins(Container $container): array
    {
        // other application plugins
        $applicationPlugins[] = new ConsoleLocaleApplicationPlugin();
        $applicationPlugins[] = new ConsoleSecurityApplicationPlugin();
        $applicationPlugins[] = new TwigApplicationPlugin();
        $applicationPlugins[] = new FormApplicationPlugin();

        return $applicationPlugins;
    }
```

3. Register the following classes for the Yves console context to allow Twig properly compile templates.

**\Spryker\Yves\Console\ConsoleDependencyProvider**

```php
...
use Spryker\Yves\Form\Plugin\Application\FormApplicationPlugin;
use Spryker\Yves\Locale\Plugin\Application\ConsoleLocaleApplicationPlugin;
use Spryker\Yves\Security\Plugin\Application\ConsoleSecurityApplicationPlugin;
use Spryker\Yves\Session\Plugin\Application\ConsoleSessionApplicationPlugin;
use Spryker\Yves\Twig\Plugin\Application\TwigApplicationPlugin;
use Spryker\Yves\Twig\Plugin\Console\TwigTemplateWarmerConsole;
use Spryker\Yves\Twig\Plugin\Console\TwigTemplateWarmingModeEventSubscriberPlugin;

...

    protected function getConsoleCommands(Container $container): array
    {
        return [
            // other commands
            new TwigTemplateWarmerConsole(),
        ];
    }

    public function getApplicationPlugins(Container $container): array
    {
        // other application plugins
        $applicationPlugins[] = new ConsoleLocaleApplicationPlugin();
        $applicationPlugins[] = new ConsoleSecurityApplicationPlugin();
        $applicationPlugins[] = new ConsoleSessionApplicationPlugin();
        $applicationPlugins[] = new TwigApplicationPlugin();
        $applicationPlugins[] = new FormApplicationPlugin();

        return $applicationPlugins;
    }

    protected function getEventSubscriber(Container $container): array
    {
        return [
            // other event subscribers
            new TwigTemplateWarmingModeEventSubscriberPlugin(),
        ];
    }
```

### Twig templates compiled cache

Twig template engine Spryker uses for Yves and some other background features like PDF invoice generation and email rendering has multiple ways to load templates:

- **Templates from files** - regular and most popular option, Twig templates are loaded and referenced by file name, for example `add-to-cart-form.twig`, etc. Cache based on a file name.
- **Templates from strings** - in case a template content was compiled &quot;on the fly&quot; and retrieved from the external system or database, Twig has a standard string loader. Cache based on a string content, a hash from the content.
- **Custom loaders** - make it possible to implement retrieval and caching logic in accordance to a project&apos;s needs. Cache implemented based on custom logic.

Twig compiles (preprocesses) templates written in its language (`.twig` files) into PHP code (known as compiled templates) and stores it as a cache to improve performance, and only a template is compiled once.

**The problem:** When loading a template from a string - Twig will use template content (its hash) as a cache key, which means that each time content changes due to a change by a user, or a change due to dynamic nature of a template (for example template compiled from other pre-processed strings) - the hash will be different and a new version of the same template will be saved under the different hash key on disk.

Yves containers are running on AWS EC2 virtual nodes. Spryker configuration limits disk space per EC2 node to 50 GB (as of Mar 18, 2025), even in production environments.

Because of application customizations, those templates created with `createTemplate` change often, almost with each request or by integration with external CMS. As a result - EC2 space was depleted and all Yves containers running on it could not serve requests anymore, as those are trying to write more templates and there&apos;s no space left.

{% info_block warningBox &quot;Warning&quot; %}

There&apos;s no cache cleanup mechanism baked into Yves containers for Twig templates.

{% endinfo_block %}

#### Key factors that affect the problem

Those factors affect the frequency and likelihood of the problem:

- **Frequency of deployments**: Each deployment shuts down old Yves containers and spawns new, effectively removing all accumulated cache.
- **Frequency of auto-scaling events**: For similar reasons - containers replacement.
- **AWS or Spryker-led maintenance**: That leads to containers replacement - resets the accumulated cache.
- **Frequency of changes in the external CMS**: If any, the more changes - the higher the rate of cache growth.
- **Number of Yves containers per EC2 instance**: More instances per container - higher disk space consumption.
- **Structure and hierarchy of Twig blocks and templates**: If there&apos;s one small template that is used across all the pages and is changed frequently - it&apos;ll likely lead to all other templates (created from string using `createTemplate`) that use it - will also lead to a new cache file, because their hash will change.

#### Solution and recommendations

- Avoid using `\Twig\Environment::createTemplate`, instead - use templates from `.twig` files
- Avoid using dynamic content as a source for the Twig template (for `\Twig\Environment::createTemplate`), instead, use Twig originally supported constructs, such as:
  - [inheritance](https://twig.symfony.com/doc/3.x/tags/extends.html)
  - [blocks](https://twig.symfony.com/doc/3.x/tags/block.html)
  - [macros](https://twig.symfony.com/doc/3.x/tags/macro.html)

**Bad example:**
- A translation string that is passed to Twig using `createTemplate` to render a small piece of HTML
- Then it is translated and additionally pre-processed
- Then it is again passed to `createTemplate`

**Good example:**
- Use Twig `extends` functions for inheritance and `trans` (or custom) filter for translations

## SVG icons in Twig templates

Older versions of Spryker had SVG icons embedded into Twig templates, which led to each page having a **significant portion** (up to 50% of a page) of HTML that is static by nature, but couldn&apos;t be cached by browsers. The problem was fixed by moving SVG icons into separate files (allowing browser cache), and only referencing those in Twig and HTML.

For more information, see [Integrate automated SVG sprite extraction](/docs/dg/dev/integrate-and-configure/integrate-automated-svg-sprite-extraction.html).

## Dynamic templates

Avoid using `createTemplate`. This is a standard Twig feature that allows creating dynamic Twig templates from strings. The problem is - it creates a cached/compiled PHP template based on a string hash (content), in comparison to the standard file-based templates, which are cached based on the original `.twig` file name.

Using this feature in context with dynamically/frequently changing templates leads to fast disk consumption by compiled Twig templates. Neither Twig nor Spryker provides a solution for this OOTB, as this is an advanced technique and is up to the development team to implement in a project-specific way.

## Cache Twig blocks

For many cases, Atomic Frontend Twig can be a bottleneck for performance. The solution is to use [Twig block cache](https://twig.symfony.com/doc/3.x/tags/cache.html). Given the right key and TTL configuration, it can significantly improve the performance of the Yves application.

In practice, cached pages can take 20 ms (compared to 60-200 ms before caching), but there are important considerations.

### How it works

Twig cache makes a wrapper around the code and stores generated HTML. For example, if you add the full product details page to the cache, all product pages will be the same because you use one compiled HTML.

### Cache usage guidelines

When using cache, it is crucial to correctly understand and design two ideas:

#### Cache key

It should uniquely identify cached entity/object, but at the same time to be useful, so that subsequent requests would use it.

For cache usage, be very careful not to store any sensitive data, and use combined keys, like:

```twig
{% raw %}{% cache &quot;cache_key&quot; ~ product.id ttl(300) %}{% endraw %}
```

- **Good cache key** - `&quot;product_&quot; + id`, unique for a product, ID never changes, IDs are limited
- **Bad cache key** - `&quot;product_&quot; + id + time` (or some random string), the key is still unique, but it will be that each time, it&apos;ll be impossible to reuse such a key

#### Cache invalidation/expiration logic

Time-based, or condition/event-based, it is easy to fall into a trap of using outdated cache, because the logic of invalidation is not aligned with the logic of cached object update.

### Possible problems

- Cache some customer-related data
- Store CSRF token to the form (it will work for one user, but all other users will have a problem)
- Store some frequently changed data (prices, stock, etc.)

### How to install

1. Install the Twig cache extension:

```bash
composer require twig/cache-extra
```

2. Create `TwigCachePlugin` in `Pyz\Shared\Twig\Plugin`:

```php
&lt;?php
declare(strict_types=1);

namespace Pyz\Shared\Twig\Plugin;

use Spryker\Service\Container\ContainerInterface;
use Spryker\Shared\TwigExtension\Dependency\Plugin\TwigPluginInterface;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
use Twig\Environment;
use Twig\Extra\Cache\CacheExtension;
use Twig\Extra\Cache\CacheRuntime;
use Twig\RuntimeLoader\RuntimeLoaderInterface;

class TwigCachePlugin implements TwigPluginInterface
{
    public function extend(Environment $twig, ContainerInterface $container): Environment
    {
        $twig-&gt;addExtension(new CacheExtension());
        $twig-&gt;addRuntimeLoader(new class implements RuntimeLoaderInterface {
            public function load($class) {
                if (CacheRuntime::class === $class) {
                    return new CacheRuntime(new TagAwareAdapter(new FilesystemAdapter()));
                }
            }
        });

        return $twig;
    }
}
```

3. Add this plugin to `src/Pyz/Yves/Twig/TwigDependencyProvider::getTwigPlugins()`.

4. It&apos;s ready to use. For usage instructions, see [Twig cache documentation](https://twig.symfony.com/doc/3.x/tags/cache.html).

## Reduce the granularity of Twig templates

Reduce the granularity of Twig templates where possible: Twig is not efficient when there is a big nested tree of hundreds of components inheriting from each other. **Recommendations**:

- prefer fewer bigger components, instead of many small
- use fewer levels of inheritance (`extends`), organise templates in a flat structure (using `include`)

## General Twig optimizations

Twig, together with [Atomic Frontend](/docs/dg/dev/frontend-development/{{site.version}}/yves/atomic-frontend/atomic-frontend.html), is an extremely flexible approach but at the same time not the fastest one. Check if you can reduce or optimize things there.

For example, the `{% raw %}{{{% endraw %} data.foo.bar.firstName {% raw %}}}{% endraw %}` `{% raw %}{{{% endraw %} data.foo.bar.lastName {% raw %}}}{% endraw %}` trigger many calls to the `Template::getAttribute()` method which is very slow.

Making calculations on the PHP side can help here a lot, as well as using `{% raw %}{{{% endraw %} set customer = data.foo.bar {% raw %}}}{% endraw %}` + `{% raw %}{{{% endraw %} customer.firstName {% raw %}}}{% endraw %}` `{% raw %}{{{% endraw %} customer.lastName {% raw %}}}{% endraw %}`.

## Prepare data in PHP classes

Prepare data in PHP classes - controllers, data mappers, before Twig, to avoid moving application logic to Twig Widgets and functions if possible, as it makes rendering heavier and harder to troubleshoot or optimise.
</description>
            <pubDate>Fri, 30 Jan 2026 12:11:44 +0000</pubDate>
            <link>https://docs.spryker.com/docs/dg/dev/guidelines/performance-guidelines/twig-performance-best-practices.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/dg/dev/guidelines/performance-guidelines/twig-performance-best-practices.html</guid>
            
            
        </item>
        
        <item>
            <title>Create standalone modules</title>
            <description>&lt;p&gt;This document describes how to create standalone modules.&lt;/p&gt;
&lt;h2 id=&quot;enable-a-custom-namespace&quot;&gt;Enable a custom namespace&lt;/h2&gt;
&lt;p&gt;To enable a custom namespace, adjust &lt;strong&gt;config/Shared/config_default.php&lt;/strong&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;nv&quot;&gt;$config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;KernelConstants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;CORE_NAMESPACES&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;s1&quot;&gt;&apos;YourCompanyName&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;SprykerShop&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;SprykerEco&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Spryker&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;SprykerSdk&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;extend-spryker-functionality-from-a-module&quot;&gt;Extend Spryker functionality from a module&lt;/h2&gt;
&lt;p&gt;You can extend Spryker functionality from a module using one of the following options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Introduce an extension point in an existing module. For an example, see &lt;a href=&quot;/docs/dg/dev/backend-development/plugins/plugins.html&quot;&gt;How to use a plugin from another module&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Use an existing extension point in a module.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;extend-functionality-using-an-existing-extension-point&quot;&gt;Extend functionality using an existing extension point&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Extend the product table with a &lt;strong&gt;Categories&lt;/strong&gt; column that shows the list of categories, which a product is added to. For this, use the following extension points in the existing modules:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/spryker/product-management-extension/blob/master/src/Spryker/Zed/ProductManagementExtension/Dependency/Plugin/ProductTableConfigurationExpanderPluginInterface.php&quot;&gt;ProductTableConfigurationExpanderPluginInterface&lt;/a&gt;: to extend table headers with &lt;strong&gt;Categories&lt;/strong&gt; column.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/spryker/product-management-extension/blob/master/src/Spryker/Zed/ProductManagementExtension/Dependency/Plugin/ProductTableDataBulkExpanderPluginInterface.php&quot;&gt;ProductTableDataBulkExpanderPluginInterface&lt;/a&gt;: to extend table content with the corresponding column&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Create a module.
Spryker provides a development tool in the &lt;code&gt;spryker/development&lt;/code&gt; module as a console command &lt;code&gt;\Spryker\Zed\Development\Communication\Console\ModuleCreateConsole&lt;/code&gt;. When module is installed and command is enabled, run the following command:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vendor/bin/console dev:module:create your-company-name.product-category
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Alternatively, you can create default module structure yourself.&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;Verification&lt;/div&gt;
Make sure the `vendor/your-company-name/product-category` folder with module data has been created.
&lt;/div&gt;&lt;/section&gt;
&lt;p&gt;Validate and update, where necessary, created composer.json file and make sure that namespace is correct, for example if you pick YourCompanyName:&lt;/p&gt;
&lt;div class=&quot;language-json 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;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;autoload&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;psr-4&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;YourCompanyName\\&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;src/YourCompanyName/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;autoload-dev&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;psr-4&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;YourCompanyNameTest\\&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;tests/YourCompanyNameTest/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Update composer configuration on the project level update &lt;code&gt;repositories&lt;/code&gt; section adding:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;language-json 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;w&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./vendor/your-company-name/product-category&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Include the newly module into composer, execute inside docker cli container:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;composer require your-company-name/product-category
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now, your module is created and is ready for further development.
Let’s add some executable code as well.&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Create a plugin to extend the product table the with a &lt;strong&gt;Categories&lt;/strong&gt; column:&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
  &lt;summary&gt;vendor/your-company-name/product-category/src/YourCompanyName/Zed/ProductCategory/Communication/Plugin/ProductManagement/ProductCategoryProductTableConfigurationExpanderPlugin.php&lt;/summary&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;cd&quot;&gt;/**
 * Copyright © 2016-present Spryker Systems GmbH. All rights reserved.
 * Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file.
 */&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;YourCompanyName\Zed\ProductCategory\Communication\Plugin\ProductManagement&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\Gui\Communication\Table\TableConfiguration&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\Kernel\Communication\AbstractPlugin&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\ProductManagementExtension\Dependency\Plugin\ProductTableConfigurationExpanderPluginInterface&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;ProductCategoryProductTableConfigurationExpanderPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProductTableConfigurationExpanderPluginInterface&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * {@inheritDoc}
     * - Expands `ProductTable` configuration with categories column.
     *
     * @param \Spryker\Zed\Gui\Communication\Table\TableConfiguration $config
     *
     * @return \Spryker\Zed\Gui\Communication\Table\TableConfiguration
     */&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;expandTableConfiguration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;TableConfiguration&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;kt&quot;&gt;TableConfiguration&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
         &lt;span class=&quot;c1&quot;&gt;// Let&apos;s insert `Categories` column right after the first column header (product ID)&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$headers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$firstColumnHeader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;array_shift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;array_unshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Categories&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;array_unshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$firstColumnHeader&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;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$headers&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;$config&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;/details&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Wire the plugin in the &lt;code&gt;\Pyz\Zed\ProductManagement\ProductManagementDependencyProvider::getProductTableConfigurationExpanderPlugins()&lt;/code&gt; method.&lt;/li&gt;
&lt;/ol&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;Verification&lt;/div&gt;
In the Back Office, go to **Catalog**&gt;**Products**. Make sure the **Categories** column is displayed in the table.
&lt;/div&gt;&lt;/section&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Create a plugin to provide data for the &lt;strong&gt;Categories&lt;/strong&gt; column:&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
  &lt;summary&gt;vendor/your-company-name/product-category/src/YourCompanyName/Zed/ProductCategory/Communication/Plugin/ProductManagement/ProductCategoryProductTableDataBulkExpanderPlugin.php&lt;/summary&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;cd&quot;&gt;/**
 * Copyright © 2016-present Spryker Systems GmbH. All rights reserved.
 * Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file.
 */&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;YourCompanyName\Zed\ProductCategory\Communication\Plugin\ProductManagement&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\ProductCategoryConditionsTransfer&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\ProductCategoryCriteriaTransfer&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\Kernel\Communication\AbstractPlugin&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\ProductManagementExtension\Dependency\Plugin\ProductTableDataBulkExpanderPluginInterface&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;ProductCategoryProductTableDataBulkExpanderPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractPlugin&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProductTableDataBulkExpanderPluginInterface&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * {@inheritDoc}
     * - Expands product table items with abstract product approval status.
     *
     * @param array&amp;lt;array&amp;lt;string, mixed&amp;gt;&amp;gt; $items
     * @param array&amp;lt;array&amp;lt;string, mixed&amp;gt;&amp;gt; $productData
     *
     * @return array&amp;lt;array&amp;lt;string, mixed&amp;gt;&amp;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;expandTableData&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;$items&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;$productData&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;c1&quot;&gt;// The code below is code sample that just works. (Learn how to make it fancy in https://docs.spryker.com/docs/dg/dev/architecture/architectural-convention.html)&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$productAbstractIds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;array_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$item&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;$item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;id_product_abstract&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;$items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$productCategoryCollection&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;getFacade&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;getProductCategoryCollection&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;ProductCategoryCriteriaTransfer&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;setProductCategoryConditions&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;ProductCategoryConditionsTransfer&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;setProductAbstractIds&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;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;$items&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$item&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;$productCategoryNames&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;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$productCategoryCollection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getProductCategories&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&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;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;nv&quot;&gt;$productCategory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getFkProductAbstract&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;$item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;id_product_abstract&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;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;$productCategoryNames&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;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getCategory&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;getName&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;$items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;categories&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;nb&quot;&gt;implode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;, &apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$productCategoryNames&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;$items&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;/details&gt;
&lt;ol start=&quot;8&quot;&gt;
&lt;li&gt;Wire the plugin in the &lt;code&gt;\Pyz\Zed\ProductManagement\ProductManagementDependencyProvider::getProductTableDataBulkExpanderPlugins()&lt;/code&gt; method.&lt;/li&gt;
&lt;/ol&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;Verification&lt;/div&gt;
In the Back Office, go to **Catalog**&gt;**Products**. Make sure relevant data is displayed in **Categories** column.
&lt;/div&gt;&lt;/section&gt;
&lt;h2 id=&quot;next-step&quot;&gt;Next step&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;/docs/dg/dev/developing-standalone-modules/ensuring-quality-in-standalone-modules.html&quot;&gt;Ensuring quality in standalone modules&lt;/a&gt;&lt;/p&gt;
</description>
            <pubDate>Fri, 30 Jan 2026 08:07:16 +0000</pubDate>
            <link>https://docs.spryker.com/docs/dg/dev/developing-standalone-modules/create-standalone-modules.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/dg/dev/developing-standalone-modules/create-standalone-modules.html</guid>
            
            
        </item>
        
        <item>
            <title>Troubleshooting Dependency Injection</title>
            <description>This document describes common issues and solutions when working with Symfony&apos;s Dependency Injection component in Spryker.

## Container compilation failures

### Unknown classes from core

**Problem:**

The container compilation fails with an error about an unknown class from a Spryker core module.

**Example error:**

```php
The service &quot;Spryker\Zed\Product\Business\ProductFacade&quot; has a dependency on a non-existent service &quot;Spryker\Zed\Product\Business\SomeInternalService&quot;.
```

**Cause:**

You&apos;re trying to autowire a class from a core module that doesn&apos;t have a pre-compiled container or isn&apos;t configured in your `ApplicationServices.php`.

**Solution 1 - Register the service manually:**

Add the missing service to your `config/Zed/ApplicationServices.php`:

```php
&lt;?php

use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Spryker\Zed\Product\Business\ProductFacadeInterface;
use Spryker\Zed\Product\Business\ProductFacade;

return static function (ContainerConfigurator $configurator): void {
    $services = $configurator-&gt;services()
        -&gt;defaults()
        -&gt;autowire()
        -&gt;public()
        -&gt;autoconfigure();

    // Register the missing core service
    $services-&gt;set(ProductFacadeInterface::class, ProductFacade::class);
};
```

**Solution 2 - Create a project-level extension:**

Create your own class that extends the core service and register it:

```php
&lt;?php

namespace Pyz\Zed\Product\Business;

use Spryker\Zed\Product\Business\ProductFacade as SprykerProductFacade;

class ProductFacade extends SprykerProductFacade
{
}
```

Then ensure it&apos;s auto-discovered through your `ApplicationServices.php` service discovery.

### Missing core module container

**Problem:**

Core module doesn&apos;t have a pre-compiled container, and autowiring fails.

**Example error:**

```php
Could not find the &quot;Spryker\Zed\Customer\Business\CustomerFacade&quot; in any of the attached containers.
```

**Cause:**

The core module hasn&apos;t been updated to support DI compilation yet.

**Solution:**

Create a project-level extension of the service and configure its dependencies manually:

```php
&lt;?php

namespace Pyz\Zed\Customer\Business;

use Spryker\Zed\Customer\Business\CustomerFacade as SprykerCustomerFacade;

class CustomerFacade extends SprykerCustomerFacade
{
    // Your project extensions if needed
}
```

Then register it in `ApplicationServices.php`:

```php
$services-&gt;set(CustomerFacadeInterface::class, \Pyz\Zed\Customer\Business\CustomerFacade::class);
```

### Scalar constructor arguments

**Problem:**

Container compilation fails when a service constructor has scalar type hints (int, string, bool, float).

**Example error:**

```php
Cannot autowire service &quot;Pyz\Zed\MyModule\MyService&quot;: argument &quot;$timeout&quot; of method &quot;__construct()&quot; is type-hinted &quot;int&quot;, you should configure its value explicitly.
```

**Cause:**

Autowiring cannot determine what value to inject for scalar types. The container needs explicit configuration.

**Solution 1 - Configure the argument explicitly:**

```php
&lt;?php

use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Pyz\Zed\MyModule\MyService;

return static function (ContainerConfigurator $configurator): void {
    $services = $configurator-&gt;services()
        -&gt;defaults()
        -&gt;autowire()
        -&gt;public()
        -&gt;autoconfigure();

    $services-&gt;set(MyService::class)
        -&gt;arg(&apos;$timeout&apos;, 30);
};
```

**Solution 2 - Use a configuration object (recommended):**

Instead of scalar arguments, create a value object:

```php
&lt;?php

namespace Pyz\Zed\MyModule;

class MyServiceConfig
{
    public function __construct(
        public readonly int $timeout = 30
    ) {
    }
}

class MyService
{
    public function __construct(
        private MyServiceConfig $config
    ) {
    }
}
```


### Transfer objects in properties or constants

**Problem:**

Container compilation fails when transfer objects are used in class properties or constants.

**Example error:**

```php
Class &quot;Generated\Shared\Transfer\CustomerTransfer&quot; not found.
```

**Cause:**

Transfer objects are generated at runtime. During container compilation (especially on fresh installations), transfer objects don&apos;t exist yet.

**Solution 1 - Use transfer objects only in methods:**

```php
&lt;?php

namespace Pyz\Zed\Customer\Business;

class CustomerProcessor
{
    // ❌ WRONG - Will fail during compilation
    private const DEFAULT_CUSTOMER = CustomerTransfer::class;
    private CustomerTransfer $defaultCustomer;

    // ✅ CORRECT - Transfer objects only in method signatures
    public function process(CustomerTransfer $customer): CustomerTransfer
    {
        // Use transfer objects here
        return $customer;
    }
}
```

**Solution 2 - Exclude modules during compilation:**

In `ApplicationServices.php`, exclude modules that heavily use transfers:

```php
&lt;?php

$excludedModuleConfiguration = [
    &apos;DataImport&apos; =&gt; true, // Often uses many transfer objects
    &apos;ProductPageSearch&apos; =&gt; true,
    &apos;ProductStorage&apos; =&gt; true,
];

foreach ($projectModules as $moduleTransfer) {
    if (isset($excludedModuleConfiguration[$moduleTransfer-&gt;getName()])) {
        continue; // Skip this module
    }

    // ... load module services
}
```

### Argument is type-hinted &quot;array&quot;

**Problem:**

The container compilation fails with an error about configuring values explicitly.

**Example error:**

```php
Cannot autowire service &quot;Spryker\Glue\AuthRestApi\Processor\AccessTokens\AccessTokenUserFinder&quot;: argument &quot;$restUserExpanderPlugins&quot; of method &quot;__construct()&quot; is type-hinted &quot;array&quot;, you should configure its value explicitly.
```

**Cause:**

Symfony can&apos;t automatically detect which classes it should inject as dependency for array&apos;s. There is a type-hint to an array of interfaces but which ones should be added here can&apos;t be automatically detected.

**Solution - Use the Stack Attribute:**

```php
&lt;?php

namespace Spryker\Glue\AuthRestApi\Processor\AccessTokens;

use Spryker\Service\Container\Attributes\Stack;

class AccessTokenUserFinder implements AccessTokenUserFinderInterface
{
    /**
     * @param array&lt;\Spryker\Glue\AuthRestApiExtension\Dependency\Plugin\RestUserMapperPluginInterface&gt; $restUserExpanderPlugins
     */
    #[Stack(
        dependencyProvider: AuthRestApiDependencyProvider::class,
        dependencyProviderMethod: &apos;getRestUserExpanderPlugins&apos;,
        provideToArgument: &apos;$restUserExpanderPlugins&apos;,
    )]
    public function __construct(
        protected array $restUserExpanderPlugins
    ) {}
}
```

During compilation the `\Spryker\Service\Container\Pass\StackResolverPass` understands this configuration and will inject the array dependency through this configuration. When the class is requested from the container, the container knows that it has to pass the returned array from the `AuthRestApiDependencyProvider::getRestUserExpanderPlugins()` method to the argument `$restUserExpanderPlugins`.

Multiple Stack attributes can be used on a class constructor.

## Debugging

When you need to understand how the container resolves services or troubleshoot issues, debug into these key classes:

### ContainerDelegator - Service resolution

**Location:** `Spryker\Service\Container\ContainerDelegator`

**Purpose:** Tracks which service from which container gets resolved.

**Key methods to debug:**

- `get(string $id)`: Main entry point for service resolution (line 94)
- `findInProjectContainer(string $id)`: Searches for services in project container (line 226)
- `getPartsFromId(string $id)`: Extracts namespace, application, module from service ID (line 430)

**What to look for:**

- Check `$this-&gt;resolvedServices` to see already resolved services
- Inspect `$this-&gt;containers` to see attached containers (project_container, application_container)
- Review `$this-&gt;checkedContainer` for which containers were searched

**Debug example:**

```php
// Add breakpoint in ContainerDelegator::get()
public function get(string $id, int $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE): ?object
{
    // Check here what $id is being requested
    // Inspect $this-&gt;containers to see available containers
    // Step through to see resolution logic
}
```

### ControllerResolver - Controller discovery

**Location:** `Spryker\Shared\Router\Resolver\ControllerResolver`

**Purpose:** Resolves controller classes from route definitions and injects dependencies.

**Key methods to debug:**

- `getController(Request $request)`: Main entry point for controller resolution (line 37)
- `getControllerFromString()`: Handles string-based controller definitions (line 66)
- `injectContainerAndInitialize()`: Injects dependencies into controller (line 170)

**What to look for:**

- Check how the controller string is parsed
- See if controller is found in ContainerDelegator via `$globalContainer-&gt;has($controller)` (line 75)
- Verify if controller is being instantiated via DI or traditionally

**Debug example:**

```php
// Add breakpoint in ControllerResolver::getController()
public function getController(Request $request): callable|false
{
    $controller = $request-&gt;attributes-&gt;get(&apos;_controller&apos;);
    // Check $controller value
    // Step through to see if it&apos;s resolved from container
}
```

### Kernel - Application setup

**Location:** `Spryker\Shared\Application\Kernel`

**Purpose:** Sets up the application, manages ApplicationPlugins, and boots the container.

**Extends:** `Symfony\Component\HttpKernel\Kernel`

**Uses:** `Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait`

**Key methods to debug:**

- `__construct()`: Initial setup, attaches containers to ContainerDelegator (line 44)
- `boot()`: Boots Symfony container and ApplicationPlugins (line 130)
- `build()`: Registers compiler passes (line 248)
- `configureContainer()`: Loads service configuration files (line 209)

**Important Symfony base class methods:**

Refer to Symfony documentation for these methods:

- [Symfony HttpKernel Component](https://symfony.com/doc/current/components/http_kernel.html)
- [MicroKernelTrait](https://symfony.com/doc/current/configuration/micro_kernel_trait.html)

**What to look for:**

- Check which ApplicationPlugins are registered
- Inspect `$this-&gt;container` to see if it&apos;s ContainerDelegator or Symfony container
- Review which compiler passes are added
- Verify service configuration file loading

**Debug example:**

```php
// Add breakpoint in Kernel::boot()
public function boot(): void
{
    // Check if container is already compiled
    // See which ApplicationPlugins are being booted
    // Inspect ContainerDelegator attachments
}
```

### Application - Request handling

**Location:** `Spryker\Shared\Application\Application`

**Purpose:** Sets up and boots ApplicationPlugins, selects the correct Kernel, and handles requests via HttpKernel.

**Key methods to debug:**

- `handle()`: Main request handling entry point (line 180)
- `registerPlugins()`: Registers all ApplicationPlugins (line 100)
- `registerPluginsAndBoot()`: Registers and boots ApplicationPlugins (line 131)

**What to look for:**

- Check which ApplicationPlugins are registered
- See when the Kernel is created and booted
- Verify container setup and switching

**Debug example:**

```php
// Add breakpoint in Application::handle()
public function handle(Request $request, int $type = self::MASTER_REQUEST, bool $catch = true): Response
{
    // Check if kernel exists in container
    // See how container is set up
    // Verify plugin registration timing
}
```

### Common debugging workflow

1. **Start with ContainerDelegator** - Check if the service is being requested and from which container
2. **Move to ControllerResolver** - If controller-related, see how it&apos;s being resolved
3. **Check Kernel setup** - Verify ApplicationPlugins and container configuration
4. **Review Application flow** - Understand the complete request lifecycle

### Enabling debug output

To see detailed container compilation information, set the debug flag to true:

In your `config/Shared/config_default.php`:

```php
$config[ApplicationConstants::ENABLE_APPLICATION_DEBUG] = true;
```

This enables:
- Container cache verification
- Detailed compiler pass output
- Service resolution logging

## Additional tips

### Clear application cache

If you encounter container compilation issues or suspect the cache is stale, clear the cache for the affected application.

**Clear cache for Zed:**

```bash
docker/sdk cli vendor/bin/console cache:clear
```

**Clear cache for Glue API:**

```bash
docker/sdk cli vendor/bin/glue cache:clear
```

**Clear cache for Glue Storefront API:**

```bash
docker/sdk cli GLUE_APPLICATION=GLUE_STOREFRONT vendor/bin/glue cache:clear
```

**Clear cache for Glue Backend API:**

```bash
docker/sdk cli GLUE_APPLICATION=GLUE_BACKEND vendor/bin/glue cache:clear
```

These commands clear the compiled container cache and force a fresh compilation on the next request.

### Verify container cache

If you need to manually inspect or remove specific container cache files:

```bash
# Clear the container cache
rm -rf data/cache/Zed/*/appSpryker_Shared_Application_Kernel*

# Rebuild the container
console container:build
```

### Check service availability

To verify if a service is available in the container, check the compiled container file:

```bash
# Location of compiled container
data/cache/Zed/{environment}/appSpryker_Shared_Application_Kernel_{Application}_{Environment}Container.php
```

Search for your service ID in this file to see if it was registered correctly.

### Module compilation check

If a core module doesn&apos;t have a container, check if it exists:

```bash
# Core module container location
vendor/spryker/{module-name}/src/Spryker/Zed/{ModuleName}/Service/Container/{ModuleName}ServiceContainer.php
```

## Next steps

- [Implementation and usage](/docs/dg/dev/architecture/dependency-injection/implementation-and-usage.html)
- [Best practices for Dependency Injection](/docs/dg/dev/architecture/dependency-injection/best-practices.html)
- [Dependency injection](/docs/dg/dev/architecture/dependency-injection.html)
</description>
            <pubDate>Thu, 29 Jan 2026 12:07:47 +0000</pubDate>
            <link>https://docs.spryker.com/docs/dg/dev/architecture/dependency-injection/troubleshooting.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/dg/dev/architecture/dependency-injection/troubleshooting.html</guid>
            
            
        </item>
        
        <item>
            <title>Troubleshooting installation</title>
            <description>This section describes common issues and solutions related to installing Spryker locally.

## Clear application cache

If you encounter compilation errors during installation or after setup, clear the cache for the affected application.

**Clear cache for Zed:**

```bash
docker/sdk cli vendor/bin/console cache:clear
```

**Clear cache for Glue API:**

```bash
docker/sdk cli vendor/bin/glue cache:clear
```

**Clear cache for Glue Storefront API:**

```bash
docker/sdk cli GLUE_APPLICATION=GLUE_STOREFRONT vendor/bin/glue cache:clear
```

**Clear cache for Glue Backend API:**

```bash
docker/sdk cli GLUE_APPLICATION=GLUE_BACKEND vendor/bin/glue cache:clear
```

These commands clear the compiled container cache and resolve most cache-related installation issues.

## Topics

- [Clear application cache](#clear-application-cache)
- [An error during front end setup](/docs/dg/dev/set-up-spryker-locally/troubleshooting-installation/an-error-during-front-end-setup.html)
- [Demo data was imported incorrectly](/docs/dg/dev/set-up-spryker-locally/troubleshooting-installation/demo-data-was-imported-incorrectly.html)
- [Docker daemon is not running](/docs/dg/dev/set-up-spryker-locally/troubleshooting-installation/docker-daemon-is-not-running.html)
- [docker-sync cannot start](/docs/dg/dev/set-up-spryker-locally/troubleshooting-installation/docker-sync-cannot-start.html)
- [Error 403 No valid crumb was included in the request](/docs/dg/dev/set-up-spryker-locally/troubleshooting-installation/error-403-no-valid-crumb-was-included-in-the-request.html)
- [Node Sass does not yet support your current environment](/docs/dg/dev/set-up-spryker-locally/troubleshooting-installation/node-saas-does-not-yet-support-your-current-environment.html)
- [Setup of new indexes throws an exception](/docs/dg/dev/set-up-spryker-locally/troubleshooting-installation/setup-of-new-indexes-throws-an-exception.html)
- [Unable to bring up Mutagen Compose sidecar service](/docs/dg/dev/set-up-spryker-locally/troubleshooting-installation/unable-to-bring-up-mutagen-compose-sidecar-service.html)
- [Vendor folder synchronization error](/docs/dg/dev/set-up-spryker-locally/troubleshooting-installation/vendor-folder-synchronization-error.html)
</description>
            <pubDate>Thu, 29 Jan 2026 12:07:47 +0000</pubDate>
            <link>https://docs.spryker.com/docs/dg/dev/set-up-spryker-locally/troubleshooting-installation/troubleshooting-installation.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/dg/dev/set-up-spryker-locally/troubleshooting-installation/troubleshooting-installation.html</guid>
            
            
        </item>
        
    </channel>
</rss>
