# Configure Auto-Explain Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/auto-explain/configuration The Auto-Explain algorithm constants (`max-depth`, `max-entropy`, the contribution thresholds, and more), what each one does, how to tune them from the Atoti Java SDK and the Atoti Python SDK, and how long an analysis stays retrievable from the chat. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. Auto-Explain exploration is controlled by a set of constants governing the sensitivity to variations and the recursion depth. Proper tuning avoids unnecessary query volume and keeps analysis results focused. This page describes each constant and how to tune it. To understand how the algorithm uses them, see [How Auto-Explain works](./how-it-works). ### Prerequisites Auto-Explain must be enabled before adding configuration. See [Set up Auto-Explain in Java](./setup-java) or [Set up Auto-Explain in Python](./setup-python) for setup instructions. ## Hierarchy inclusion and exclusion By default, Auto-Explain explores all of a cube's hierarchies. You can restrict analysis to specific hierarchies, or exclude some — globally or per measure. These settings apply to both SDKs: * **Atoti Java SDK** — under `auto-explain-configuration` in `application.yaml`. See [Set up Auto-Explain in Java](./setup-java). * **Atoti Python SDK** — as attributes of [`Cube.auto_explain`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti.Cube.auto_explain.html). See [Set up Auto-Explain in Python](./setup-python). | Java (`application.yaml`) | Python (`Cube.auto_explain`) | Description | | ------------------------------ | ---------------------------------- | ---------------------------------------------------------------- | | `excluded-hierarchies` | `excluded_hierarchies` | Hierarchies excluded from all analyses on all measures. | | `excluded-measure-hierarchies` | `excluded_hierarchies_per_measure` | Per-measure hierarchy exclusions. | | `included-hierarchies` | `included_hierarchies` | When set, only these hierarchies are analyzed, for all measures. | | `included-measure-hierarchies` | `included_hierarchies_per_measure` | Per-measure hierarchy inclusions. | A hierarchy is identified by its hierarchy name and its dimension name, as usual in Atoti. ### Exclusion priority Auto-Explain removes any excluded hierarchy from analysis, even if the same hierarchy also appears in the included list. For example, if `Region / Country` is both included and excluded, it is excluded. ## How to tune the constants Set these constants in the SDK you use: * **Atoti Java SDK** — under `constants-config` in `application.yaml`. See [Set up Auto-Explain in Java](./setup-java), which also covers per-cube hierarchy inclusion and exclusion. * **Atoti Python SDK** — as attributes of [`AutoExplain`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.AutoExplain.html), using the same names in snake\_case (for example, `max-depth` becomes `max_depth`). See [Set up Auto-Explain in Python](./setup-python). The constants control how the algorithm explores the cube to find root causes: | Parameter | Description | Default | | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | | `max-depth` | Maximum recursion depth: how many levels the algorithm can drill into along a single path before declaring it a root cause. | `15` | | `max-distinct-hierarchies` | Maximum number of hierarchies evaluated at each recursion step. Only hierarchies with the fewest distinct member values in the current level are evaluated, up to this limit. | `10` | | `max-entropy` | Maximum Shannon entropy for a level to qualify as an explanation. The value should be between 0 and 1. | `0.4` | | `min-percentage-relative-contribution` | Minimum relative contribution (%) to consider a member as significant. | `10` | | `min-percentage-absolute-contribution` | Minimum absolute contribution (%) to consider a member as significant. | `1` | | `min-variation-threshold` | Minimum absolute variation value at a location for Auto-Explain to analyze it. | `1e-6` | | `include-opposite-contributors` | Whether to include members contributing in the opposite direction of the overall variation. | `false` | | `max-members-per-level` | Maximum number of members a hierarchy can have at the current location to be considered in the analysis. If set to -1, this limit is disabled. | `-1` | ### `max-depth` **Default:** `15` The maximum recursion depth along any single path. Each time the algorithm identifies a significant member, it recurses into it and increments the depth by 1. When depth reaches `max-depth`, the algorithm stops and records the current location as a root cause. Each branch of the recursion tree independently tracks depth from the starting cell. For example, the algorithm may find two significant members at depth 2 and recurse into both; each branch then reaches depth 3 on its own. **Tuning guidance:** * **Increase** if the cube has many levels and Auto-Explain stops before reaching meaningful root causes. This produces more detailed explanations at the cost of longer analysis time. * **Decrease** if analyses take too long or return overly detailed results. A lower value produces broader, higher-level explanations. ### `max-distinct-hierarchies` **Default:** `10` The maximum number of hierarchies the algorithm evaluates at each recursion step. Before computing entropy, the algorithm ranks candidate hierarchies by their **member count** (the number of distinct member values in the hierarchy level being evaluated at the current location). It then keeps only the `max-distinct-hierarchies` hierarchies with the fewest members. Hierarchies with fewer members are evaluated first because they require fewer queries. **Tuning guidance:** * **Increase** if the cube has many hierarchies and more of them should be considered at each step. This improves accuracy but increases query volume. * **Decrease** if analyses are slow due to a large number of hierarchies. The algorithm already prioritizes hierarchies with fewer members, so reducing this value typically has limited impact on result quality. ### `max-entropy` **Default:** `0.4` The maximum Shannon entropy value for a hierarchy level to be considered a valid explanation. Entropy has a \[0, 1] range and measures how evenly the variation is distributed across members: * **Entropy near 0**: Variation is concentrated in one or a few members, meaning the hierarchy explains the variation well. * **Entropy near 1**: Variation is evenly spread across all members, meaning the hierarchy does not provide a useful explanation. If all candidate hierarchies have entropy above this threshold, the algorithm stops recursing at the current location. **Tuning guidance:** * **Increase toward 1** if no single member dominates at the locations being analyzed and root causes need to be found in moderately distributed data. This makes the algorithm more permissive but may produce less meaningful explanations. * **Decrease toward 0** if only highly concentrated variations should be explained. This makes the algorithm more selective and produces more precise explanations but may stop early if data is moderately distributed. ### High root cause count Increasing this value may result in a high number of root causes, which may significantly increase analysis time. ### `min-percentage-relative-contribution` **Default:** `10` The minimum relative contribution percentage a member must have to be considered significant. The relative contribution measures a member's share of its parent's variation: ``` relativeContribution = |memberVariation / parentVariation| × 100 ``` If a member's relative contribution falls below this threshold, the algorithm skips it and does not recurse into it. **Tuning guidance:** * **Increase** to focus on only the most dominant contributors at each level. This produces fewer, more impactful root causes but may miss secondary contributors. * **Decrease** to include smaller contributors in the analysis. This captures more nuance but can produce noisier results with many minor root causes. ### `min-percentage-absolute-contribution` **Default:** `1` The minimum absolute contribution percentage a member must have to be considered significant. The absolute contribution measures a member's share of the original top-level variation: ``` absoluteContribution = relativeContribution × parentAbsoluteContribution / 100 ``` At the starting cell (depth 0), `parentAbsoluteContribution` is 100%. This threshold prevents the algorithm from recursing deeply into branches that are locally significant but globally negligible. **Tuning guidance:** * **Increase** to restrict results to members with a meaningful share of the overall variation. Useful when only root causes that materially impact the total are relevant. * **Decrease** to allow the algorithm to explore branches that represent a small fraction of the total variation. Useful when all contributing factors need to be identified, even minor ones. The two contribution thresholds work together. A member must exceed **both** thresholds to be considered significant and trigger further recursion. The relative threshold ensures local significance. The absolute threshold ensures global relevance. ### `min-variation-threshold` **Default:** `1e-6` The minimum absolute value of the variation at a location before the algorithm begins analysis. If the variation is below this threshold, Auto-Explain considers it negligible and does not attempt to explain it. This value must be strictly above 0. The unit matches the unit of the measure being analyzed: for a measure in dollars, the threshold is in dollars; for a normalized measure with values between 0 and 1, the threshold should be set accordingly. **Tuning guidance:** * **Increase** if measures have natural noise or floating-point imprecision and Auto-Explain is trying to explain insignificant variations. * **Decrease** if very small but meaningful variations need to be analyzed, for example when working with normalized or ratio-based measures. Ignoring variations below this threshold prevents division by zero when computing relative contributions (`memberVariation / parentVariation`). This value must always be strictly above 0 to ensure zero variation is always caught before contribution computation. ### `include-opposite-contributors` **Default:** `false` Whether to include members that contribute in the opposite direction of the overall variation. By default, Auto-Explain only considers members that contribute in the same direction as the parent variation (e.g., only positive contributors when the overall variation is positive). When enabled, members contributing in the opposite direction are also considered as root causes. When this parameter is enabled: * Members are sorted by **absolute value** of their marginal variation, regardless of sign. * The contribution threshold filter uses the **absolute value** of both the member's contribution and the threshold, so members with large negative contributions are retained when the overall variation is positive (and vice versa). **Tuning guidance:** * **Enable** (`true`) when opposite-direction members are meaningful for your analysis. For example, if the overall variation is positive but a specific member has a large negative contribution, this member may be important to understand the overall picture. * **Disable** (`false`) when you only want to explain contributions that align with the overall trend direction. ### `max-members-per-level` **Default:** `-1` The maximum number of members a hierarchy can have at the current location to be considered in the analysis. Before entropy is computed, any hierarchy whose member count at the current location exceeds this value is excluded from the candidate set. This exclusion is unconditional: the hierarchy is removed regardless of its entropy or contribution potential. When set to `-1`, the limit is disabled and all hierarchies remain eligible regardless of member count. **Tuning guidance:** * **Set a positive value** to exclude hierarchies with a large number of members at the current location. This reduces query volume and analysis time when some hierarchies are very wide at certain locations. * **Leave at `-1`** (the default) if member count should not restrict eligibility. In this case, `max-distinct-hierarchies` alone controls how many hierarchies are evaluated. ### Combined effect of entropy and contribution thresholds The `max-entropy` and contribution thresholds (`min-percentage-relative-contribution`, `min-percentage-absolute-contribution`) act at different stages of the algorithm. Together, they determine how many root causes Auto-Explain produces. * **`max-entropy`** controls **which hierarchies** the algorithm considers worth exploring. A hierarchy is only selected if its entropy is below this threshold, meaning the variation is sufficiently concentrated. * **Contribution thresholds** control **which members** within the selected hierarchy are pursued further. A member is only recursed into if both its relative and absolute contributions exceed their respective thresholds. ## How to keep analyses retrievable from the chat An analysis that has already run can be asked for again in the chat, available from Atoti 6.2.1, instead of being run a second time. A user can list the analyses available to them, ask for the interactive page of one of them, and drop one they no longer want. Two settings bound what stays retrievable: how many analyses a session keeps, and for how long. In the Atoti Java SDK, set them under `atoti.ai.autoexplain.results` in `application.yaml`: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} atoti: ai: autoexplain: results: maximum-size: 500 time-to-live: 8h ``` The following table describes each setting, and the attribute of [`AutoExplainConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.AutoExplainConfig.html) that sets it in the Atoti Python SDK: | Java (`application.yaml`) | Python (`AutoExplainConfig`) | Description | Default | | ------------------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | | `maximum-size` | `retained_run_count` | How many analyses the session keeps retrievable, across all of its users. Once that many are kept, running another one drops the analysis that ran first. | `100` | | `time-to-live` | `run_lifetime` | How long an analysis stays retrievable, counted from the moment it ran. | `100m` | An analysis is only ever offered to a user allowed to see it. Once an analysis stops being retrievable, asking for it in the chat runs it from scratch. In the Atoti Python SDK, pass an [`AutoExplainConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.AutoExplainConfig.html) to [`AiConfig.auto_explain`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.AiConfig.html): ```python theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} import atoti as tt import os from datetime import timedelta from atoti_ai import AiConfig, AutoExplainConfig from atoti_ai_amazon_bedrock import ConnectionConfig, ChatConfig connection_config = ConnectionConfig( aws_access_key=os.environ["AWS_ACCESS_KEY_ID"], aws_secret_key=os.environ["AWS_SECRET_ACCESS_KEY"], aws_region="eu-west-3", ) chat_config = ChatConfig( model="eu.anthropic.claude-sonnet-4-6", ) ai_config = AiConfig( connection=connection_config, chat=chat_config, auto_explain=AutoExplainConfig( retained_run_count=500, run_lifetime=timedelta(hours=8), ), ) session_config = tt.SessionConfig(ai=ai_config) ``` Asking the chat for the interactive page of an analysis requires Atoti UI 5.2.28 or higher. A chat served to an earlier version answers with the summary alone, and never offers the page. See [Compatibility](../../../releases-and-upgrades/compatibility). ## Related reading * [How Auto-Explain works](./how-it-works) — the algorithm and a worked example * [Set up Auto-Explain in Java](./setup-java) * [Set up Auto-Explain in Python](./setup-python) * [Set up an LLM](../configure-and-start/set-up-an-llm) to enable the optional AI summary # How Auto-Explain works Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/auto-explain/how-it-works How the Auto-Explain recursive tree-search algorithm finds root causes, the key terms (variation, contribution, entropy, depth), the algorithm steps, and a worked example. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. Auto-Explain uses a recursive tree search algorithm. Understanding how it works clarifies the effect of each [configuration parameter](./configuration#how-to-tune-the-constants). Starting from the selected cell, the algorithm identifies the best hierarchy to explain the current variation. It then recurses into the most significant members of that hierarchy. To follow along, first enable Auto-Explain: see [Set up Auto-Explain in Java](./setup-java) or [Set up Auto-Explain in Python](./setup-python), then [Configure Auto-Explain](./configuration) to tune the constants used below. ## Key terms | Term | Meaning | | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Variation | The numeric change at the selected cell that Auto-Explain is trying to explain | | Relative contribution | The contribution of a member to its parent's variation, expressed as a percentage | | Absolute contribution | The contribution of a member to the original top-level variation that Auto-Explain is trying to explain, expressed as a percentage | | Recursion step | One iteration of the algorithm at a given location: filter hierarchies, pick the best one, evaluate its members, and recurse into the significant ones | | Depth | The number of recursion steps from the starting cell along the current path. Increments by 1 each time the algorithm drills into a significant member. Each branch of the recursion tree tracks depth independently | | Significant member | A member whose relative contribution and absolute contribution both meet or exceed their respective thresholds | | Root cause | A location in the cube where the algorithm stops drilling. The algorithm stops when a parameter limit is reached, when the variation is too small (below `min-variation-threshold`), or when the variation is too spread out to explain further | | Entropy | A value between 0 and 1 measuring how evenly variation is distributed across members of a hierarchy level. 0 = concentrated in one member. 1 = evenly spread. Low entropy means the hierarchy is a useful explanation | | Member count | The number of distinct member values in a hierarchy level (not the number of levels). Used to filter candidate hierarchies: those with fewer members are evaluated first | ## Algorithm steps At each recursion step, starting from the selected cell: 1. **Check depth**: if `depth = max-depth`, record this location as a root cause and stop this branch. 2. **Check variation**: if `|variation| < min-variation-threshold`, record this location as a root cause and stop this branch. The variation is now negligible. 3. **Filter candidate hierarchies**: if `max-members-per-level != -1`, exclude any hierarchy whose member count at the current location exceeds this value. Then keep only the hierarchies with the smallest member counts, up to `max-distinct-hierarchies`. This limits query volume without losing quality (hierarchies with fewer members are less expensive to evaluate). 4. **Compute entropy**: for each candidate hierarchy, compute the Shannon entropy of variation across its members at this location. 5. **Select the best hierarchy**: the one with the lowest entropy. 6. **Check entropy**: if the best entropy exceeds `max-entropy`, the variation is too spread out to explain further. Record the current location as a root cause and stop this branch. 7. **Evaluate members**: for each member of the selected hierarchy, compute relative and absolute contributions. * Skip any member below either threshold. * If no member meets both thresholds, record the current location as a root cause and stop this branch. 8. **Recurse**: for each significant member, go back to step 1 with this member as the new context and depth incremented by 1. ## Worked example Values in this example are illustrative and have been rounded for clarity. **Cube setup:** | Hierarchy | Levels | Members | | --------- | ------------------------- | -------------------------------------------------------------------------------- | | Region | 1: Region | North, South, East, West, Central | | Product | 2: Category, Sub-category | Category: Electronics, Clothing, Food, Furniture, Sports (5 sub-categories each) | **Measure:** Sales Revenue. **Observed variation: −1000.** **Parameters for this example:** | Parameter | Value | Note | | -------------------------------------- | ----- | ------------------------------------------------------- | | `max-depth` | 3 | Reduced here to show the depth-limit stopping behavior. | | `max-distinct-hierarchies` | 10 | Default | | `max-entropy` | 0.4 | Default | | `min-percentage-relative-contribution` | 10% | Default | | `min-percentage-absolute-contribution` | 1% | Default | | `include-opposite-contributors` | false | Default | | `max-members-per-level` | -1 | Default (disabled) | ### Depth 0: starting cell (variation = −1000) **Variation check**: |−1000| exceeds `min-variation-threshold` (1e-6). Analysis proceeds. **Hierarchy selection** (`max-distinct-hierarchies = 10`, both qualify): | Hierarchy | Member count | Entropy | Outcome | | ------------------ | ------------ | -------- | ---------------------------------------------------- | | Region | 5 | **0.15** | ✓ Selected. Lowest entropy, below `max-entropy` 0.4. | | Product / Category | 5 | 0.70 | ✗ Not selected. Higher entropy. | **Member distribution, Product / Category** (not selected, shown to illustrate why entropy is high): | Member | Relative | Absolute | | ----------- | -------- | -------- | | Electronics | 24% | 24% | | Clothing | 20% | 20% | | Food | 19% | 19% | | Furniture | 18% | 18% | | Sports | 19% | 19% | Variation is spread roughly evenly across all 5 categories. This produces high entropy (0.70). Product / Category does not explain the drop well at this level. **Member evaluation, Region** (selected): | Member | Relative | Absolute | Outcome | | ------- | -------- | -------- | ----------------------------------------------------------- | | East | 82% | 82% | ✓ Significant, recurse | | North | 8% | 8% | ✗ Below `min-percentage-relative-contribution` 10%, skipped | | South | 5% | 5% | ✗ Skipped | | West | 4% | 4% | ✗ Skipped | | Central | 1% | 1% | ✗ Skipped | Variation is concentrated almost entirely in East. This produces low entropy (0.15). Region is a much better explanation. The algorithm recurses into East (depth 0 to 1). ### Depth 1: East (variation = −820) Region has only 1 level and is at its leaf. Only Product / Category is available. **Hierarchy selection:** | Hierarchy | Member count | Entropy | Outcome | | ------------------ | ------------ | -------- | ------------------------------------ | | Product / Category | 5 | **0.20** | ✓ Selected. Below `max-entropy` 0.4. | **Member evaluation, Product / Category within East:** | Member | Relative | Absolute | Outcome | | ----------- | -------- | -------- | ----------------------------------------------------------- | | Electronics | 70% | 57% | ✓ Significant, recurse | | Clothing | 15% | 12% | ✓ Significant, recurse | | Food | 8% | 7% | ✗ Below `min-percentage-relative-contribution` 10%, skipped | | Furniture | 5% | 4% | ✗ Skipped | | Sports | 2% | 2% | ✗ Skipped | The algorithm recurses into Electronics (Branch A) and Clothing (Branch B), each at depth 2 independently. ### Depth 2, Branch A: East → Electronics (variation = −570) Product / Sub-category is now available (deeper level of the Product hierarchy). **Hierarchy selection:** | Hierarchy | Member count | Entropy | Outcome | | ---------------------- | ----------------------------- | -------- | ------------------------------------ | | Product / Sub-category | 5 (in scope at this location) | **0.12** | ✓ Selected. Below `max-entropy` 0.4. | **Member evaluation, Product / Sub-category within East / Electronics:** | Member | Relative | Absolute | Outcome | | ----------- | -------- | -------- | ---------------------------------------------------------------------------------------------------------------------------- | | Smartphones | 80% | 46% | ✓ Significant, recurse to depth 3. At depth 3, the depth check fires (`depth = max-depth`) and records this as a root cause. | | Laptops | 12% | 7% | ✓ Significant, recurse to depth 3. At depth 3, the depth check fires (`depth = max-depth`) and records this as a root cause. | | Tablets | 5% | 3% | ✗ Skipped | | Accessories | 2% | 1% | ✗ Skipped | | Other | 1% | 1% | ✗ Skipped | ### Depth 2, Branch B: East → Clothing (variation = −123) **Hierarchy selection:** | Hierarchy | Member count | Entropy | Outcome | | ---------------------- | ----------------------------- | -------- | ---------------------------------------------------- | | Product / Sub-category | 5 (in scope at this location) | **0.65** | ✗ Above `max-entropy` 0.4. Variation too spread out. | The drop in Clothing is distributed across all sub-categories with no dominant contributor. No hierarchy passes the entropy threshold. East / Clothing is recorded as a root cause. This branch stops here. **Root causes identified:** | Root cause | Path | Stopped by | | --------------- | -------------------------------- | ------------------------------------------------------------------ | | Smartphones | East → Electronics → Smartphones | `max-depth` reached | | Laptops | East → Electronics → Laptops | `max-depth` reached | | East / Clothing | East → Clothing | `max-entropy` exceeded. Variation too spread out to drill further. | Branch A members (Smartphones, Laptops) are significant at depth 2 and are recursed into. The `max-depth` check fires at the start of depth 3 and records them as root causes. Branch B stops at depth 2 because `max-entropy` is exceeded. Each branch follows its own path and can stop for different reasons. ## Related reading * [Configure Auto-Explain](./configuration) to tune the constants used above * [How to use Auto-Explain](../../../user-guide/auto-explain) in the Atoti UI # Set up Auto-Explain in Java Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/auto-explain/setup-java How to add the Auto-Explain Spring Boot starter to an Atoti Java project, verify it in the Atoti UI, and configure it in `application.yaml`. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. This guide explains how to add Auto-Explain to an Atoti Java project. Auto-Explain does not require an LLM to function. The root-cause analysis, contribution percentages, and contribution tables are produced by a deterministic algorithm and are always available without any AI provider configured. An LLM is only required if the optional AI summary is needed. To enable AI summaries, configure an LLM provider after completing this setup. See [Set up an LLM](../configure-and-start/set-up-an-llm) for instructions. ## Prerequisites Before setting up Auto-Explain, ensure the following requirements are met: * A Java project * A license with the AI flag enabled * Maven or Gradle build system ## Add the dependency Add the Auto-Explain Spring Boot starter to the project. Add the following to `pom.xml`: ```xml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} com.activeviam.springboot starter-ai-autoexplain ${atoti-server.version} ``` ## Verify the setup After adding the dependency, verify that Auto-Explain is available: 1. Build the project. 2. Start the Atoti application. 3. Open the Atoti UI. 4. Right-click two cells in a pivot table. 5. Check that the Auto-Explain option appears in the context menu. ## Configure Auto-Explain Add Auto-Explain configuration to the application configuration file. The configuration block is per-cube and can be repeated to configure multiple cubes. The following example shows all available configuration options in `application.yaml`: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} atoti: ai: autoexplain: cube-configs: - cube-name: Cube auto-explain-configuration: excluded-hierarchies: - dimension-name: Time hierarchy-name: TimeBucket - cube-name: cube-name auto-explain-configuration: measure-naming-config: parent: "Cube__PARENT" sibling: "Cube__SIBLING" marginal: "Cube__MARGINAL" absolute-contribution: "Cube__ABSOLUTE_CONTRIBUTION" relative-contribution: "Cube__RELATIVE_CONTRIBUTION" excluded-hierarchies: - hierarchy-name: hierarchyName1 dimension-name: dimensionName1 - hierarchy-name: hierarchyName2 dimension-name: dimensionName2 excluded-measure-hierarchies: measureName1: - hierarchy-name: hierarchyName3 dimension-name: dimensionName3 included-hierarchies: - hierarchy-name: hierarchyName4 dimension-name: dimensionName4 included-measure-hierarchies: measureName1: - hierarchy-name: hierarchyName5 dimension-name: dimensionName5 constants-config: max-depth: 15 max-distinct-hierarchies: 10 max-entropy: 0.4 min-percentage-absolute-contribution: 1 min-percentage-relative-contribution: 10 min-variation-threshold: 0.000001 include-opposite-contributors: false max-members-per-level: -1 ``` The following table describes the top-level `application.yaml` keys: | Parameter name | Description | | -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `cube-name` | Name of the cube to configure Auto-Explain for. | | `auto-explain-configuration` | Configuration of the parameters of Auto-Explain. | | `auto-explain-configuration.measure-naming-config` | Lists the measures computed by Auto-Explain and their default names. Default names are shown in the configuration example above. Specify only the measures whose names need to change. | The `excluded-hierarchies`, `included-hierarchies`, and their per-measure variants control which hierarchies Auto-Explain analyzes; these apply to both SDKs and are documented in [Hierarchy inclusion and exclusion](./configuration#hierarchy-inclusion-and-exclusion). The `constants-config` block controls how the algorithm explores the cube; see [Configure Auto-Explain](./configuration#how-to-tune-the-constants) for the constants and tuning guidance. ## Related reading After setting up Auto-Explain, proceed to: * [How Auto-Explain works](./how-it-works) * [Configure Auto-Explain](./configuration) to tune the analysis * [Learn how to use Auto-Explain](../../../user-guide/auto-explain) in the Atoti UI # Set up Auto-Explain in Python Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/auto-explain/setup-python How to enable Auto-Explain in an Atoti Python project through the `ai` plugin and `AiConfig`, access it via `Cube.auto_explain`, and tune its constants from Python. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. This guide explains how to enable Auto-Explain in an Atoti Python project. Auto-Explain does not require an LLM to function. The root-cause analysis, contribution percentages, and contribution tables are produced by a deterministic algorithm and are always available without any AI provider configured. An LLM is only required if the optional AI summary is needed. To enable AI summaries, configure an LLM provider. See [Set up an LLM](../configure-and-start/set-up-an-llm). ## Prerequisites Before setting up Auto-Explain, ensure the following requirements are met: * An Atoti Python project * A license with the AI flag enabled ## Install the package Install the Atoti AI package: ```bash theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} uv add "atoti[ai]" ``` ## Enable Auto-Explain Pass an [`AiConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.AiConfig.html) to [`SessionConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti.config.SessionConfig.html) when starting the session. Auto-Explain works with an empty `AiConfig()`, so no LLM provider is required: ```python theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} import atoti as tt from atoti_ai import AiConfig session_config = tt.SessionConfig(ai=AiConfig()) ``` Auto-Explain is then available on each cube through [`Cube.auto_explain`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti.Cube.auto_explain.html). ## Configure Auto-Explain Auto-Explain constants are read and set as attributes of [`AutoExplain`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.AutoExplain.html), reached through [`Cube.auto_explain`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti.Cube.auto_explain.html). For the meaning, defaults, and tuning guidance of each constant, see [Configure Auto-Explain](./configuration). For example, to make the analysis stop after five levels instead of the default 15: ```python theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} cube.auto_explain.max_depth = 5 ``` Per-measure overrides are also available through `excluded_hierarchies_per_measure` and `included_hierarchies_per_measure`, keyed by measure name — the Python equivalent of the Java `excluded-measure-hierarchies` / `included-measure-hierarchies` configuration. ## Verify the setup After enabling Auto-Explain, verify that it is available: 1. Start the Atoti session. 2. Open the Atoti UI. 3. Right-click two cells in a pivot table. 4. Check that the Auto-Explain option appears in the context menu. ## Related reading * [How Auto-Explain works](./how-it-works) — the algorithm and a worked example * [Configure Auto-Explain](./configuration) — constants reference and tuning guidance * [How to use Auto-Explain](../../../user-guide/auto-explain) in the Atoti UI * [`atoti_ai.AutoExplain`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.AutoExplain.html) API reference # Set up a custom disclaimer Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/configure-and-start/set-up-a-custom-disclaimer Why you may want to customize the Atoti Intelligence AI disclaimer, and links to the Atoti Java SDK and Atoti Python SDK configuration pages. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. Atoti Intelligence displays a disclaimer in the UI to inform users when an LLM is involved in a response. ## Why customize the disclaimer? LLMs can make mistakes. Depending on an organization's compliance requirements, a custom disclaimer may be necessary to communicate the appropriate wording to users. If you do not set one, Atoti Intelligence shows a built-in default message. ## Set it up Follow the guide for the SDK you use: * [Custom disclaimer in Java](../disclaimer/setup-java) * [Custom disclaimer in Python](../disclaimer/setup-python) # Set up an LLM Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/configure-and-start/set-up-an-llm What a Large Language Model provides in Atoti Intelligence, why it is required, and the list of supported providers with links to the Atoti Java SDK and Atoti Python SDK setup pages. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. A Large Language Model (LLM) is the AI model that powers Atoti Intelligence's natural-language features. Atoti Intelligence does not include a built-in model: you connect your own LLM provider. ## Why configure an LLM? Configuring an LLM enables the following capabilities: * Natural-language queries and responses * AI-assisted visualization creation with Visualize This * The optional AI summary of Auto-Explain root-cause analysis results Auto-Explain's root-cause analysis works without an LLM. An LLM is only required to generate the optional AI summary of Auto-Explain results, and to use Visualize This. Atoti Intelligence connects to LLM providers through Spring AI, which supports multiple providers through a consistent configuration interface. See the [Spring AI documentation](https://docs.spring.io/spring-ai/reference/api/chat/comparison.html) for more information. ## Supported providers Choose your provider below, then follow the page for the SDK you use: * **Amazon Bedrock** — [Java](../llm/amazon-bedrock-java) / [Python](../llm/amazon-bedrock-python) * **OpenAI** — [Java](../llm/openai-java) / [Python](../llm/openai-python) Many LLMs support the OpenAI API format. A model from another provider may be compatible with the OpenAI configuration. ## Next steps After setting up an LLM, configure the AI tools: * [Set up Auto-Explain](./set-up-auto-explain) * [Set up Visualize This](./set-up-visualize-this) # Set up Auto-Explain Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/configure-and-start/set-up-auto-explain What Auto-Explain is, how its root-cause analysis helps users, and links to the Atoti Java SDK and Atoti Python SDK setup pages. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. Auto-Explain performs automated root-cause analysis on a cube. Starting from a variation between two cells, it drills down through the cube's hierarchies to find the members that most contribute to that variation, and reports them with their contribution percentages. ## How it helps * Turns "why did this number change?" into an answer in a few clicks, without manual drill-down. * Produces deterministic results — contribution percentages and contribution tables — that are always available, even without an LLM. * Optionally generates a natural-language AI summary of the results when an LLM is configured. ## Learn more and set up 1. [How Auto-Explain works](../auto-explain/how-it-works) — the algorithm and a worked example 2. [Configure Auto-Explain](../auto-explain/configuration) — the constants and how to tune them 3. Set it up in the SDK you use: [Java](../auto-explain/setup-java) or [Python](../auto-explain/setup-python) # Set up Visualize This Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/configure-and-start/set-up-visualize-this What Visualize This is, how the AI assistant helps users build visualizations from natural language, and links to the Atoti Java SDK and Atoti Python SDK setup pages. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. Visualize This is an AI assistant in the Atoti UI that turns natural-language requests into visualizations. Users describe the chart or table they want, and the assistant builds it from the data in the cube. ## How it helps * Lets users explore data without knowing the cube's structure or query syntax. * Understands business terminology when you provide cube, dimension, and measure descriptions. * Runs on the LLM you configure, so answers stay grounded in your data. Visualize This requires a configured LLM. See [Set up an LLM](./set-up-an-llm) first. ## Learn more and set up 1. [How Visualize This works](../visualize-this/how-it-works) — how the assistant answers a request 2. [Configure Visualize This](../visualize-this/configuration) — supply cube context to improve responses 3. Set it up in the SDK you use: [Java](../visualize-this/setup-java) or [Python](../visualize-this/setup-python) # Configure and start Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/configure-and-start/steps Overview of the steps to enable Atoti Intelligence AI tools — setting up an LLM, Auto-Explain, Visualize This, and a custom disclaimer — in either the Atoti Java SDK or the Atoti Python SDK. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. Atoti Intelligence adds AI-assisted tools to Atoti. This section walks through enabling those tools, step by step. Each step has a dedicated page for the Atoti Java SDK and for the Atoti Python SDK, so you can follow the guide for the SDK you use. ## Steps 1. **[Set up an LLM](./set-up-an-llm)** — connect a Large Language Model provider. Required for natural-language features such as Visualize This and the optional Auto-Explain AI summary. 2. **[Set up Auto-Explain](./set-up-auto-explain)** — enable root-cause analysis on your cubes. Works with or without an LLM. 3. **[Set up Visualize This](./set-up-visualize-this)** — enable the AI assistant that builds visualizations from natural-language requests. 4. **[Set up a custom disclaimer](./set-up-a-custom-disclaimer)** — customize the message shown to users when an LLM is involved in a response. # Set up a custom disclaimer in Java Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/disclaimer/setup-java How to customize the Atoti Intelligence AI disclaimer in an Atoti Java project through the `atoti.ai.disclaimer` application property, and the default disclaimer shown when none is defined. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. This guide explains how to configure an AI disclaimer for use with Atoti Intelligence in an Atoti Java project. ## Why configure an AI disclaimer? LLMs can make mistakes. Depending on an organization's compliance requirements, an AI disclaimer may be necessary to inform users when an LLM is involved in a response. ## Configuration approach Set the disclaimer in the application configuration file. Add the following to `application.yaml`: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} atoti.ai.disclaimer: "Any AI disclaimer" ``` Any disclaimer set will be displayed in the UI. If none is defined, the disclaimer defaults to: ```java theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} private String disclaimer = "AI can make mistakes, please double check response."; ``` This is what the disclaimer will look like in the UI: Hover over the disclaimer to see it displayed ## Related reading * [Set up an LLM](../configure-and-start/set-up-an-llm) * [Set up a custom disclaimer in Python](./setup-python) # Set up a custom disclaimer in Python Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/disclaimer/setup-python How to customize the Atoti Intelligence AI disclaimer in an Atoti Python project through the `disclaimer` parameter of `AiConfig`. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. This guide explains how to configure an AI disclaimer for use with Atoti Intelligence in an Atoti Python project. ## Why configure an AI disclaimer? LLMs can make mistakes. Depending on an organization's compliance requirements, an AI disclaimer may be necessary to inform users when an LLM is involved in a response. ## Configuration approach Set the disclaimer through the `disclaimer` parameter of [`AiConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.AiConfig.html) when building the session configuration: ```python theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} import os from atoti_ai import AiConfig from atoti_ai_amazon_bedrock import ConnectionConfig, ChatConfig connection_config = ConnectionConfig( aws_access_key=os.environ["AWS_ACCESS_KEY_ID"], aws_secret_key=os.environ["AWS_SECRET_ACCESS_KEY"], aws_region="eu-west-3", ) chat_config = ChatConfig( model="eu.mistral.pixtral-large-2502-v1:0", ) custom_disclaimer = "Custom disclaimer." ai_config = AiConfig( connection=connection_config, chat=chat_config, disclaimer=custom_disclaimer, ) session_config = tt.SessionConfig(ai=ai_config) ``` Then start the session with that configuration: ```python theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} session = tt.Session.start(session_config) ``` Any disclaimer set will be displayed in the UI. Until one is set, the disclaimer defaults to: ```java theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} private String disclaimer = "AI can make mistakes, please double check response."; ``` This is what the disclaimer will look like in the UI: Hover over the disclaimer to see it displayed ## Related reading * [Set up an LLM](../configure-and-start/set-up-an-llm) # Set up Atoti Intelligence to use Amazon Bedrock in Java Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/llm/amazon-bedrock-java How to add Amazon Bedrock as the LLM provider for Atoti Intelligence in an Atoti Java project via Spring AI, including the `spring-ai-starter-model-bedrock-converse` Maven dependency and `application.yaml` configuration for AWS credentials, region, and Converse API model selection. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. This guide explains how to configure Amazon Bedrock as the Large Language Model (LLM) provider for Atoti Intelligence in an Atoti Java project. ## Prerequisites Before configuring Amazon Bedrock, ensure the following requirements are met: * An AWS account with Amazon Bedrock access and appropriate permissions * The AWS region where Bedrock models are available ## Add the dependency Add the Spring AI Amazon Bedrock dependency to the project. Add the following to `pom.xml`: ```xml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} org.springframework.ai spring-ai-starter-model-bedrock-converse ``` ## Configure the model Configure the Amazon Bedrock model in the application configuration file. This example assumes that `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` are passed as JVM arguments or environment variables. Add the following to `application.yaml`: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} spring: ai: bedrock: aws: access-key: ${AWS_ACCESS_KEY_ID} secret-key: ${AWS_SECRET_ACCESS_KEY} region: "your-aws-region" converse: chat: options: temperature: 0. maxTokens: 5000 topP: 0.8 model: eu.anthropic.claude-sonnet-4-6 ``` Replace the following placeholders: * `your-aws-region`: the AWS region where Bedrock is available * Model name: choose an available Bedrock model Refer to the [Spring AI documentation](https://docs.spring.io/spring-ai/reference/api/chat/comparison.html) for any additional configuration options. ## Verify the configuration After completing the configuration, verify that the LLM connection works: 1. Start the Atoti application. 2. Check the application logs for successful LLM initialization. 3. Test an AI feature such as Visualize This or Auto-Explain. ## Related reading After configuring Amazon Bedrock, proceed to set up AI features: * [Set up Auto-Explain in Java](../auto-explain/setup-java) * [Set up Visualize This in Java](../visualize-this/setup-java) # Set up Atoti Intelligence to use Amazon Bedrock in Python Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/llm/amazon-bedrock-python How to configure Amazon Bedrock as the LLM provider for Atoti Intelligence in an Atoti Python project, using `ConnectionConfig` and `ChatConfig` from `atoti_ai_amazon_bedrock` with `AiConfig`. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. This guide explains how to configure Amazon Bedrock as the LLM provider for Atoti Intelligence in an Atoti Python project. ## Prerequisites Before configuring Amazon Bedrock, ensure the following requirements are met: * An Atoti Python project * An AWS account with Amazon Bedrock access and appropriate permissions * The AWS region where Bedrock models are available ## Install the package ```bash theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} uv add "atoti[ai-amazon-bedrock]" ``` ## Configure the LLM Use [`ConnectionConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai_amazon_bedrock.connection_config.html) and [`ChatConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai_amazon_bedrock.chat_config.html) from `atoti_ai_amazon_bedrock` to configure the LLM connection, then pass them to [`AiConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.ai_config.html): ```python theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} import atoti as tt import os from atoti_ai import AiConfig from atoti_ai_amazon_bedrock import ConnectionConfig, ChatConfig connection_config = ConnectionConfig( aws_access_key=os.environ["AWS_ACCESS_KEY_ID"], aws_secret_key=os.environ["AWS_SECRET_ACCESS_KEY"], aws_region="eu-west-3", ) chat_config = ChatConfig( model="eu.mistral.pixtral-large-2502-v1:0", ) ai_config = AiConfig(connection=connection_config, chat=chat_config) session_config = tt.SessionConfig(ai=ai_config) ``` Then pass the config to the session through [`SessionConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti.config.session_config.html): ```python theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} session = tt.Session.start(tt.SessionConfig(ai=ai_config)) ``` ### `ConnectionConfig` parameters | Parameter | Type | Required | Description | | -------------------------------- | ---------- | -------- | ------------------------------------------------------------------------- | | `async_read_timeout` | `Duration` | No | Timeout for reading asynchronous responses. | | `aws_access_key` | `str` | No | AWS access key ID for authentication. | | `aws_region` | `str` | No | AWS region where Bedrock models are available (for example, `eu-west-3`). | | `aws_secret_key` | `str` | No | AWS secret access key for authentication. | | `aws_session_token` | `str` | No | Optional AWS session token for temporary credentials. | | `connection_acquisition_timeout` | `Duration` | No | Timeout for acquiring a connection from the pool. | | `connection_timeout` | `Duration` | No | Timeout for establishing connections to Bedrock. | | `timeout` | `Duration` | No | Timeout for Bedrock API requests. | ### `ChatConfig` parameters | Parameter | Type | Required | Description | | ------------- | ------- | -------- | ------------------------------------------------------------------------------------ | | `model` | `str` | Yes | The ID of the model to use, for example `"anthropic.claude-3-sonnet-20240229-v1:0"`. | | `max_tokens` | `int` | No | Maximum number of tokens to generate in the response. | | `temperature` | `float` | No | Controls randomness in responses from 0.0 (deterministic) to 1.0 (creative). | | `top_k` | `int` | No | Limits vocabulary to top K tokens at each generation step. | | `top_p` | `float` | No | Nucleus sampling parameter. Controls diversity via cumulative probability. | ## Verify the configuration After completing the configuration, verify that the LLM connection works: 1. Start the Atoti session. 2. Open the Atoti UI. 3. Test an AI feature such as Visualize This or Auto-Explain. ## Related reading After configuring Amazon Bedrock, proceed to set up AI features: * [Set up Auto-Explain in Python](../auto-explain/setup-python) * [Set up Visualize This in Python](../visualize-this/setup-python) * [`atoti_ai_amazon_bedrock`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai_amazon_bedrock.html) API reference # Set up Atoti Intelligence to use OpenAI in Java Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/llm/openai-java How to add OpenAI as the LLM provider for Atoti Intelligence in an Atoti Java project via Spring AI, including the `spring-ai-starter-model-openai` Maven dependency, `application.yaml` API key and model configuration, and support for OpenAI-compatible APIs. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. This guide explains how to configure OpenAI as the Large Language Model (LLM) provider for Atoti Intelligence in an Atoti Java project. ### Compatible APIs Many LLMs support the OpenAI API format. A model from another provider may be compatible with this configuration. ## Prerequisites Before configuring OpenAI, ensure the following requirements are met: * An OpenAI account with API access, or a compatible provider * An OpenAI API key ## Add the dependency Add the Spring AI OpenAI dependency to the project. Add the following to `pom.xml`: ```xml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} org.springframework.ai spring-ai-starter-model-openai ``` ## Configure the model Configure the OpenAI model in the application configuration file. This example assumes that `LLM_API_KEY` is passed as an environment variable or JVM argument. Add the following to `application.yaml`: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} spring: ai: openai: api-key: ${LLM_API_KEY} chat: options: model: gpt-4o temperature: 0. max-tokens: 5000 ``` Replace the model name with an available OpenAI model. Refer to the [Spring AI documentation](https://docs.spring.io/spring-ai/reference/api/chat/comparison.html) for any additional configuration options. ## Verify the configuration After completing the configuration, verify that the LLM connection works: 1. Start the Atoti application. 2. Check the application logs for successful LLM initialization. 3. Test an AI feature such as Visualize This or Auto-Explain. ## Related reading After configuring OpenAI, proceed to set up AI features: * [Set up Auto-Explain in Java](../auto-explain/setup-java) * [Set up Visualize This in Java](../visualize-this/setup-java) # Set up Atoti Intelligence to use OpenAI in Python Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/llm/openai-python How to configure OpenAI as the LLM provider for Atoti Intelligence in an Atoti Python project, using `ConnectionConfig` and `ChatConfig` from `atoti_ai_openai` with `AiConfig`, including OpenAI-compatible providers. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. This guide explains how to configure OpenAI as the LLM provider for Atoti Intelligence in an Atoti Python project. ### Compatible APIs Many LLMs support the OpenAI API format. A model from another provider may be compatible with this configuration. ## Prerequisites Before configuring OpenAI, ensure the following requirements are met: * An Atoti Python project * An OpenAI account with API access, or a compatible provider * An OpenAI API key ## Install the package ```bash theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} uv add "atoti[ai-openai]" ``` ## Configure the LLM Use [`ConnectionConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai_openai.connection_config.html) and [`ChatConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai_openai.chat_config.html) from `atoti_ai_openai` to configure the LLM connection, then pass them to [`AiConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.ai_config.html). The following example uses Azure OpenAI, an OpenAI-compatible provider. Adapt the `base_url` and environment variable names for other providers. ```python theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} import atoti as tt import os from atoti_ai import AiConfig from atoti_ai_openai import ConnectionConfig, ChatConfig connection_config = ConnectionConfig( api_key=os.environ["AZURE_OPENAI_API_KEY"], base_url="https://aiwopenai.openai.azure.com/openai/v1", ) chat_config = ChatConfig( model="gpt-5", max_completion_tokens=5000, ) ai_config = AiConfig(connection=connection_config, chat=chat_config) session_config = tt.SessionConfig(ai=ai_config) ``` Then pass the config to the session through [`SessionConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti.config.session_config.html): ```python theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} session = tt.Session.start(tt.SessionConfig(ai=ai_config)) ``` ### `ConnectionConfig` parameters | Parameter | Type | Required | Description | | ----------------- | ------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------- | | `api_key` | `str` | No | OpenAI API key for authentication. | | `base_url` | `str` | No | Base URL for the OpenAI API. Useful for OpenAI-compatible providers. The path to the API (such as `/v1`) must be included. | | `custom_headers` | `FrozenMapping[str, str]` | No | Custom HTTP headers to add to every request. | | `max_retries` | `int` | No | Maximum number of retries for requests to OpenAI. | | `organization_id` | `str` | No | OpenAI organization ID. | | `timeout` | `Duration` | No | Timeout for requests to OpenAI. | ### `ChatConfig` parameters | Parameter | Type | Required | Description | | ----------------------- | ------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `model` | `str` | Yes | The ID of the model to use, for example `"gpt-4o"`. | | `extra_body` | `FrozenMapping[str, bool \| int \| float \| str]` | No | Additional parameters for OpenAI-compatible servers. | | `max_completion_tokens` | `int` | No | Maximum number of tokens to generate for reasoning models (e.g. o1, o3). Mutually exclusive with `max_tokens`. | | `max_tokens` | `int` | No | Maximum number of tokens to generate in the response. For non-reasoning models. Mutually exclusive with `max_completion_tokens`. | | `parallel_tool_calls` | `bool` | No | Enable parallel function calling during tool use. | | `seed` | `int` | No | Seed for deterministic sampling (Beta). | | `temperature` | `float` | No | Controls randomness in responses from 0.0 (deterministic) to 2.0 (creative). Not supported by reasoning models (e.g. o1, o3, gpt-5). | | `tool_choice` | `str` | No | Tool/function calling behavior (`"none"`, `"auto"`, or a specific function name). | | `top_p` | `float` | No | Nucleus sampling parameter. Controls diversity via cumulative probability. Not supported by reasoning models (e.g. o1, o3, gpt-5). | ## Verify the configuration After completing the configuration, verify that the LLM connection works: 1. Start the Atoti session. 2. Open the Atoti UI. 3. Test an AI feature such as Visualize This or Auto-Explain. ## Related reading After configuring OpenAI, proceed to set up AI features: * [Set up Auto-Explain in Python](../auto-explain/setup-python) * [Set up Visualize This in Python](../visualize-this/setup-python) * [`atoti_ai_openai`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai_openai.html) API reference # Configure Visualize This Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/visualize-this/configuration How to configure Visualize This - cube context, dynamic tool discovery and the `atoti.ai.chat.enabled` switch that turns chat off in the Atoti Java SDK, and the chat system prompt in the Atoti Python SDK. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. Providing context about your cubes improves Visualize This responses: the more the LLM knows about the business meaning of cubes, dimensions, hierarchies, levels, and measures, the more relevant the visualizations it produces. Configuration is optional but recommended. ### Prerequisites Visualize This must be enabled before adding configuration. See [Set up Visualize This in Java](./setup-java) or [Set up Visualize This in Python](./setup-python) for setup instructions. ## Atoti Java SDK Add Visualize This configuration to the application configuration file. Add the following to `application.yaml`: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} atoti: ai: context: cubes: - name: "cubeName1" description: "Description of the cube 1" dimensions: - name: "dimensionName1" description: "description dimension1" hierarchies: - name: "hierarchyName1" description: "description hierarchy1" levels: - name: "levelName1" description: "description level1" - name: "dimensionName2" description: "description dimension2" hierarchies: - name: "hierarchyName2" description: "description hierarchy2" measures: - name: "measure1" description: "description measure1" - name: "measure2" description: "description measure2" measure-folders: - name: "folderName1" description: "description folder1" - name: "folderName2" description: "description folder2" - name: "cubeName2" description: "Description of the cube 2" dimensions: - name: "dimensionName3" hierarchies: - name: "hierarchyName3" levels: - name: "levelName3" description: "description level3" - name: "hierarchyName4" description: "description hierarchy4" levels: - name: "levelName4" description: "description level4" - name: "dimensionName5" description: "description dimension4" measures: - name: "measure3" description: "description measure3" - name: "measure4" description: "description measure4" measure-folders: - name: "folderName3" description: "description folder3" - name: "folderName4" description: "description folder4" system-prompt-paths: - "prompts/prompt1.md" - "prompts/prompt2.md" ``` ### Configuration parameters The following table describes each configuration parameter: | Parameter name | Description | | ------------------- | --------------------------------------------------------------------------------------------------------------------------- | | system-prompt-paths | Ordered list of paths to system prompt files. Files are concatenated in the declared order and appended to the LLM context. | | name | Name of the cube to configure Visualize This for. | | description | Description of the cube. | | dimensions | List of dimensions to provide additional information to the LLM. | |   name | Name of the dimension. | |   description | Description of the dimension. | |   hierarchies | List of hierarchies to provide additional information to the LLM. | |     name | Name of the hierarchy. | |     description | Description of the hierarchy. | |     levels | List of levels to provide additional information to the LLM. | |       name | Name of the level. | |       description | Description of the level. | | measures | List of measures to provide additional information to the LLM. | |   name | Name of the measure. | |   description | Description of the measure. | | measure-folders | List of measure folders to provide additional information to the LLM. | |   name | Name of the measure folder. | |   description | Description of the measure folder. | ### Alternative: XMLA\_DESCRIPTION property Descriptions for dimensions, hierarchies, and levels can also be sourced from the `XMLA_DESCRIPTION` property set directly on the OLAP element schema definition. When this property is present on an element, Visualize This reads it as the element's description. This is useful when descriptions are already defined in the cube schema, and you want to avoid duplicating them in the application configuration file. If both `XMLA_DESCRIPTION` and the application configuration file provide a description for the same element, the two values are concatenated. The `XMLA_DESCRIPTION` property applies to dimensions, hierarchies, levels, and measures only. Cubes and measure folders must be described through the application configuration file. ### Partial configuration Configuration does not require descriptions for all elements. Provide descriptions only for elements that need additional context. ## How to turn Visualize This off An application can serve Atoti Intelligence without serving chat. Setting `atoti.ai.chat.enabled` to `false`, available from Atoti 6.2.1, registers no chat endpoint: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} atoti: ai: chat: enabled: false ``` The chat endpoints are then absent, and every call to them answers `404 Not Found`. The `/versions` endpoint stops advertising the `activeviam/ai/chat` namespace, so service discovery no longer offers chat. The Atoti UI reports chat as absent, and shows no chat panel. The `activeviam/ai` namespace stays advertised as long as Auto-Explain is enabled. Every other Atoti Intelligence feature keeps working, Auto-Explain and the MCP server included. The setting defaults to `true`. Turning chat off differs from configuring no LLM. An application with no LLM keeps advertising the `activeviam/ai/chat` namespace, and refuses each call to it with `404 Not Found`. Chat stays discoverable there, and starts answering as soon as an LLM is configured. In the Atoti Python SDK, set [`AiConfig.chat_enabled`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.AiConfig.html) to `False`: ```python theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} import atoti as tt import os from atoti_ai import AiConfig from atoti_ai_amazon_bedrock import ConnectionConfig, ChatConfig connection_config = ConnectionConfig( aws_access_key=os.environ["AWS_ACCESS_KEY_ID"], aws_secret_key=os.environ["AWS_SECRET_ACCESS_KEY"], aws_region="eu-west-3", ) chat_config = ChatConfig( model="eu.anthropic.claude-sonnet-4-6", ) ai_config = AiConfig( connection=connection_config, chat=chat_config, chat_enabled=False, ) session_config = tt.SessionConfig(ai=ai_config) ``` A session started that way serves no chat, and [`Session.chat`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti.Session.chat.html) reports chat as absent. ## Dynamic tool discovery Visualize This can send the LLM every available tool on each request. Alternatively, it can send only the tools that match the current request. Dynamic tool discovery, available from Atoti 6.2.0, is the second mode. The model calls a tool-search tool that queries a keyword index and receives only the matching tools. This reduces prompt token usage and improves tool selection. Atoti enables dynamic tool discovery by default under the Atoti Intelligence Essentials license. Without that license it stays off. Dynamic tool discovery applies to both SDKs, and both can turn it off. Beyond the opt-out, the settings described in this section can only be configured through the Atoti Java SDK. ### How to opt out Turning dynamic tool discovery off sends the whole tool set to the model on every request instead. This restores the behavior Atoti used before dynamic tool discovery existed. A small tool set, where search adds no benefit, is one reason to turn it off. Debugging which tools the model can see is another. In the Atoti Java SDK, set `spring.ai.chat.client.tool-search-advisor.enabled` to `false`: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} spring: ai: chat: client: tool-search-advisor: enabled: false ``` In the Atoti Python SDK, set [`AiConfig.dynamic_tool_discovery`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.AiConfig.html) to `False`: ```python theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} import atoti as tt import os from atoti_ai import AiConfig from atoti_ai_amazon_bedrock import ConnectionConfig, ChatConfig connection_config = ConnectionConfig( aws_access_key=os.environ["AWS_ACCESS_KEY_ID"], aws_secret_key=os.environ["AWS_SECRET_ACCESS_KEY"], aws_region="eu-west-3", ) chat_config = ChatConfig( model="eu.anthropic.claude-sonnet-4-6", ) ai_config = AiConfig( connection=connection_config, chat=chat_config, dynamic_tool_discovery=False, ) session_config = tt.SessionConfig(ai=ai_config) ``` ### Atoti defaults Dynamic tool discovery is Spring AI's tool search advisor, configured under the `spring.ai.chat.client.tool-search-advisor` prefix. Atoti overrides three of its properties: | Property | Atoti default | | ---------------------------------- | ------------------------------------------------------------------------------------- | | `enabled` | `true` under the Atoti Intelligence Essentials license, otherwise Spring AI's `false` | | `tool-index-type` | `lucene`, whose scoring suits the natural-language queries the model produces | | `reference-tool-name-accumulation` | `false`, so a follow-up search narrows the tool set rather than widening it | Every other setting — result limits, session eviction, the tool-search instructions given to the model — keeps its Spring AI default. See the [Spring AI documentation](https://docs.spring.io/spring-ai/reference/guides/dynamic-tool-search.html) for the full list of properties and their behavior. Atoti does not ship `spring-ai-vector-store`. Add that dependency and a `VectorStore` bean to the application before setting `tool-index-type` to `vector`. ## Atoti Python SDK The chat is available on the session through [`Session.chat`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti.Session.chat.html). Its [`system_prompt`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.Chat.system_prompt.html) is a custom addition to Atoti's built-in system prompt: it is empty by default, and any value you set is appended to the built-in prompt to give the LLM extra context about your cubes. Reading it queries the server; assigning it takes effect on the next chat run and requires the `ROLE_ADMIN` role. ```python theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} # Add extra context on top of the built-in system prompt session.chat.system_prompt = "The Quantity measure is expressed in units, not currency." ``` The system prompt is **global**: it applies to every request rather than to a specific cube (the assistant infers which cube a request targets). Use it for overall guidance. To give the assistant more information about a specific cube, set descriptions on its **measures** and **hierarchies** — for example `cube.measures["Revenue.SUM"].description` and `cube.hierarchies["Product"].description`. The assistant reads these descriptions through its tools. The Java SDK additionally accepts cube, dimension, level, and measure-folder descriptions through `application.yaml`. ### How to serve no chat Set [`AiConfig.chat_enabled`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.AiConfig.html) to `False` to register no chat endpoint, as described in [How to turn Visualize This off](#how-to-turn-visualize-this-off). ### How to opt out of dynamic tool discovery [Dynamic tool discovery](#dynamic-tool-discovery) is on by default. Set [`AiConfig.dynamic_tool_discovery`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.AiConfig.html) to `False` to send the whole tool set to the model on every request instead: ```python theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} import atoti as tt import os from atoti_ai import AiConfig from atoti_ai_amazon_bedrock import ConnectionConfig, ChatConfig connection_config = ConnectionConfig( aws_access_key=os.environ["AWS_ACCESS_KEY_ID"], aws_secret_key=os.environ["AWS_SECRET_ACCESS_KEY"], aws_region="eu-west-3", ) chat_config = ChatConfig( model="eu.anthropic.claude-sonnet-4-6", ) ai_config = AiConfig( connection=connection_config, chat=chat_config, dynamic_tool_discovery=False, ) session_config = tt.SessionConfig(ai=ai_config) ``` The remaining dynamic tool discovery settings are not exposed in the Atoti Python SDK. Configure them through the Atoti Java SDK, as described in [Atoti defaults](#atoti-defaults). ## Related reading * [How Visualize This works](./how-it-works) * [Set up Visualize This in Java](./setup-java) * [Set up Visualize This in Python](./setup-python) * [How to use Visualize This](../../../user-guide/chat) in the Atoti UI # How Visualize This works Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/visualize-this/how-it-works How Visualize This turns a natural-language request into a visualization — the cube context and system prompt sent to the LLM, and how the assistant builds widgets from the data model. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. Visualize This is an AI assistant in the Atoti UI that turns natural-language requests into visualizations. Understanding what it sends to the LLM clarifies why configuration improves results. To try Visualize This, first enable it: see [Set up Visualize This in Java](./setup-java) or [Set up Visualize This in Python](./setup-python), then [Configure Visualize This](./configuration) to supply cube context. ## How a request is answered 1. **The user describes what they want** in natural language in the Atoti UI (for example, "show revenue by country for last year"). 2. **Atoti builds the context** sent to the LLM: the cube's data model (dimensions, hierarchies, levels, measures) plus any descriptions and system prompt you configured. 3. **The LLM interprets the request** against that context and produces a query and a widget definition. 4. **Atoti renders the visualization** from the result, using the same query engine as the rest of the UI, so the numbers are consistent with everything else. ## Why context matters The LLM only knows what it is told about your cube. The more business meaning you provide — clear cube, dimension, and measure descriptions, and a focused system prompt — the more accurately it maps a request to the right members and measures. This is what the [configuration](./configuration) step supplies. The LLM runs on the provider you configured (see [Set up an LLM](../configure-and-start/set-up-an-llm)), so responses stay grounded in your data rather than general knowledge. ## Related reading * [Configure Visualize This](./configuration) to supply cube context * [How to use Visualize This](../../../user-guide/chat) in the Atoti UI # Set up Visualize This in Java Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/visualize-this/setup-java How to add the Visualize This Spring Boot starter to an Atoti Java project and verify that the AI assistant appears in Atoti UI. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. This guide explains how to add Visualize This to an Atoti Java project. ## Prerequisites The following requirements must be met before setting up Visualize This: * A Java project * A license with the AI flag enabled * A configured LLM (see [Set up an LLM](../configure-and-start/set-up-an-llm)) * Maven or Gradle build system ## Add the dependency Add the Visualize This Spring Boot starter to the project. Add the following to `pom.xml`: ```xml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} com.activeviam.springboot starter-ai-chat ${atoti-server.version} ``` ## Verify the setup After adding the dependency, verify that Visualize This is available: 1. Build the project. 2. Start the Atoti application. 3. Open the Atoti UI. 4. Check that the AI assistant appears in the interface. ## Related reading * [How Visualize This works](./how-it-works) * [Configure Visualize This](./configuration) to supply cube context * [How to use Visualize This](../../../user-guide/chat) in the Atoti UI * [Set up a custom disclaimer in Java](../disclaimer/setup-java) # Set up Visualize This in Python Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/enable-ai-tools/visualize-this/setup-python How to enable Visualize This in an Atoti Python project through `AiConfig` with an LLM connection and chat model. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. This guide explains how to enable Visualize This in an Atoti Python project. ## Prerequisites The following requirements must be met before setting up Visualize This: * An Atoti Python project * A license with the AI flag enabled * A configured LLM (see [Set up an LLM](../configure-and-start/set-up-an-llm)) ## Install the package Visualize This requires an LLM provider. Install the package for your provider, for example: ```bash theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} uv add "atoti[ai-openai]" ``` ## Enable Visualize This Unlike Auto-Explain, Visualize This requires an LLM. Provide both a `connection` and a `chat` model to [`AiConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.AiConfig.html), then pass it to [`SessionConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti.config.SessionConfig.html). The example below uses OpenAI; see the [LLM provider pages](../configure-and-start/set-up-an-llm) for other providers. ```python theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} import os import atoti as tt from atoti_ai import AiConfig from atoti_ai_openai import ChatConfig, ConnectionConfig with tt.experimental({"ai"}): ai_config = AiConfig( connection=ConnectionConfig(api_key=os.environ["OPENAI_API_KEY"]), chat=ChatConfig(model="gpt-4o"), ) session = tt.Session.start(tt.SessionConfig(ai=ai_config)) ``` ## Verify the setup After enabling Visualize This, verify that it is available: 1. Start the Atoti session. 2. Open the Atoti UI. 3. Check that the AI assistant appears in the interface. ## Related reading * [How Visualize This works](./how-it-works) * [Configure Visualize This](./configuration) to supply cube context * [How to use Visualize This](../../../user-guide/chat) in the Atoti UI * [Set up a custom disclaimer in Python](../disclaimer/setup-python) # How connecting to other MCP Servers works Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/mcp-server/connect-to-other-servers/how-it-works How an Atoti Server uses the tools of other MCP Servers as its own, covering the license tier, the `none`, `atoti-jwt` and `pass-through` authentication modes that carry the calling user's identity, remote tool naming, the `getConnectedServers` chat tool, connection resilience, and how remote tools reach this server's own MCP endpoint. ### Atoti Intelligence SDK This is part of the Atoti Intelligence SDK offer. An Atoti Server can connect out to other Model Context Protocol (MCP) Servers, typically the other Atoti Servers of the same deployment, each exposing its own cube. It then uses their tools as its own, both in chat and on its own MCP endpoint. This page covers the behavior shared by both SDKs; declaring a connection is SDK-specific. To follow along, first declare a connection: see [Connect to other MCP Servers in Java](./setup-java) or [Connect to other MCP Servers in Python](./setup-python). Both assume the Atoti MCP Server is already set up; see [How to set up the Atoti MCP Server](../setup/atoti-mcp-server-setup). Connecting to other MCP Servers requires the Atoti Intelligence Extension tier, which itself requires Essentials, like the rest of Atoti's MCP surface. ## What does connecting to other MCP Servers provide? * A chat user on one Atoti Server can query cubes hosted on another, without duplicating tool logic across servers * Remote tools appear alongside local cube tools and custom tools, wherever tools are offered to the model * The remote cube's own role-based data restrictions stay in force for every remote call * Remote tools are reported on this server's own MCP endpoint too. One server therefore shows an external MCP client the tools of the whole deployment, each client told what its own credential can reach ## Which authentication modes are available? Each connection names its own mode, in its own declaration. | Mode | What it sends | When to choose it | | ---------------- | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | `none` (default) | No credential. | The remote server is genuinely unauthenticated, for example a local development server. | | `atoti-jwt` | A fresh Atoti JWT, minted for the calling user, carrying their username and authorities. | The remote server shares this deployment's JWT signing key, the standard setup within one Atoti deployment. | | `pass-through` | The calling user's own bearer token, forwarded unchanged. | The remote server validates tokens against an external identity provider instead of this server's signing key. | `none` is the default, and deliberately so. Declaring a connection says where a server is, never that it belongs to this deployment, and nothing else in the configuration can say it either. Writing `atoti-jwt` is that assertion, so make it only for servers under the same ownership: the minted token is accepted by every server sharing the deployment's signing key. A third party given one holds a working credential for the whole deployment, in the name of a real user. `atoti-jwt` mints its token from the authenticated principal rather than replaying one, so it works whichever way the calling user authenticated: Basic, JWT, OIDC, or LDAP. Both servers must share the signing key; see [Java](./setup-java#how-to-authenticate-with-atoti-jwt) or [Python](./setup-python#how-to-authenticate-with-atoti-jwt). `pass-through` replays either kind of token this server accepts (an Atoti JWT, or an OAuth 2 access token). This brings two limits. A user who authenticated with Basic or form login presents no bearer token, so the call carries no credential and is rejected. A replayed OAuth 2 token also keeps the audience it was issued for, so the remote server accepts it only when configured to trust tokens issued for this server. A connection that runs the remote server as a local process, over standard input and output, identifies itself by being that process, so it accepts no authentication mode at all. ## Why does the calling user's identity carry through? Every mode derives the outgoing credential from the calling user's security context, evaluated on the caller's own thread at the moment of the call. A remote tool therefore always runs under the identity of whoever triggered it. This is what keeps the remote cube's role-based data restrictions in force: a user denied a measure or a member on the remote server gains nothing by asking through chat. Listing a remote server's tools is an authenticated call of the same kind. Its result is cached per calling identity (the username together with its authorities), rather than once for the whole server. A remote server that varies its tool list by role therefore never has one user's list served to another. ## How are remote tools named? Atoti names every remote tool `_`; the server's own tools stay unprefixed. The prefix matters because every Atoti Server exposes the same cube tools. Unprefixed, a second connected server's tools collide with the first one's, and only the first occurrence of a name survives. Each remote tool's description also states which server it runs on. The connection name is first normalized to the alphabet tool names may use: a hyphen becomes an underscore, and anything else outside letters, digits and underscores is dropped. `fo ficc/server:1` becomes `foficcserver1`, and the `run_mdx_query` tool of a `pnl-server` connection becomes `pnl_server_run_mdx_query`. Two rules follow from that alphabet, and from the 64-character limit most model providers impose on a tool name: * Two names differing only by dropped characters normalize to the same prefix, for example `pnl-server` and `pnl_server`. Atoti checks the prefixes at startup and refuses to start rather than silently drop a server's tools. The same check catches one name declared twice. Each transport has its own set of connections, and names are not compared across transports. * When a prefixed name exceeds 64 characters, the prefix is kept whole and the tool's own name is shortened. A short hash is appended so two shortened names never collapse into one. A connection name of no more than 53 characters always keeps its prefix. Past that, the prefix is shortened instead, and `getConnectedServers` then reports no `toolPrefix` for that connection rather than one its tools do not carry. The scheme can be replaced; see [Connect to other MCP Servers in Java](./setup-java#which-other-properties-and-beans-matter). ## What does the `getConnectedServers` chat tool do? A deployment of several connected servers gives the model tools from several cubes, and nothing in those tools says which server each one reaches. `getConnectedServers` closes that gap: it lists the server the chat runs on, then every connected server, whichever transport declares it. The model calls it to name the servers available, to attribute an answer to one of them, or to check that one is up. It requires the Atoti Intelligence Extension tier, like the rest of this page, and can be withheld; see [Connect to other MCP Servers in Java](./setup-java#which-other-properties-and-beans-matter). `getConnectedServers` puts deployment-internal addresses into the chat prompt. Those addresses reach the model provider, and the model can repeat them to any user allowed to chat, whatever their role. Atoti registers the tool for chat only, never on this server's own MCP endpoint. ### What does the tool report? The example below comes from a server named `fo-ficc-server`, declaring the connections `pnl-server` and `sandbox`, with `sandbox` down: ```json theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} [ { "server": "fo-ficc-server", "url": "https://atoti.example.com/atoti", "current": true, "reachable": true, "version": "6.2.0", "instructions": "Front-office FICC risk cube." }, { "server": "pnl-server", "url": "https://pnl.example.com", "toolPrefix": "pnl_server_", "reachable": true, "reportedName": "P&L cube", "version": "6.2.0" }, { "server": "sandbox", "url": "http://localhost:9090", "toolPrefix": "sandbox_", "reachable": false } ] ``` | Field | What it holds | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | `server` | The name this deployment gives the server, which is the name the model calls it by. For a connected server, it is the connection name. | | `url` | Where the server is, whole path and no MCP endpoint on the end. Absent for a connection declared without a URL, such as one running a local process. | | `toolPrefix` | The prefix every tool of that server carries, for example `pnl_server_`. Reported only when it is a prefix the tools really carry. | | `current` | Present, and `true`, on the server the chat runs on. Absent from every other entry. | | `reachable` | Whether the calling user reached the server on this call. | | `reportedName` | What the server calls itself in the MCP handshake, a label rather than an address. Reported for a reachable server only. | | `version` | The version the server reports. | | `instructions` | What the server says it is for, when it says anything. | An entry describes a server; it is not a way to call one. The model reaches a connected server through that server's own prefixed tools, never through the reported URL. **The server running the chat** always comes first, marked `current: true`, and is the only entry with no `toolPrefix`. This is what tells the model that its unprefixed tools are this server's own. A server that declares no connection still reports itself, so a question about the available servers never gets an empty answer. Its `url` is the address the asking client used, up to and including the context path, read from the request being served rather than from configuration. Two clients of one server, one direct and one through an ingress, are therefore each told the address they used. Behind a reverse proxy the server has to be told to trust the forwarded headers, or the reported address is the proxy's back-end hop; see [Connect to other MCP Servers in Java](./setup-java#which-other-properties-and-beans-matter). **A connected server** is reported with the URL its connection was declared with, whole and unchanged, with no MCP endpoint appended: `url: https://pnl.example.com` is reported as `https://pnl.example.com`, not `https://pnl.example.com/mcp`. What the report shows is the address a person recognizes the server by, and can open. **Reachability** is established per call and per user. The tool pings every connected server with the calling user's own credential, exactly as a remote tool call does, so a server is reported `reachable: false` when it is down, when it rejects that credential, or when the user has no access to it. Such an entry keeps its name and its URL, so the model can say which server is unavailable. The pings run concurrently and the whole sweep is bounded to ten seconds, so an unreachable server costs a chat turn a bounded wait rather than its transport's full request timeout. ## How do remote tools appear on this server's own MCP endpoint? On their own, alongside the local cube tools, for every client that connects. There is nothing to enable and no identity to configure. No LLM is required either: an LLM is only required for chat. Each client is told the tools its own credential can reach. An MCP client authenticates to this server first (an unauthenticated request is answered with a `401` that starts the OAuth 2.1 flow), so by the time it asks for tools there is a real user to ask on behalf of. Two clients logged in as different users are therefore told different things. Calling a remote tool through this endpoint runs it as the calling user, exactly as from chat. ## How resilient is a connection to an unreachable remote server? An unreachable remote server costs only its own tools. Atoti lists every connected server separately, so one that is down or that rejects the credential it received leaves the other servers' tools untouched. The failure is not cached: that server is retried on the next request, and its tools reappear as soon as it answers. An unreachable peer never stops this server from starting, and never keeps its MCP endpoint from answering. ## Related reading * [Connect to other MCP Servers in Java](./setup-java) and [in Python](./setup-python) * [Migration notes](../../../releases-and-upgrades/migration-notes#spring-ai-mcp-client-defaults) for the Spring AI MCP client defaults this capability changes * [What is the Atoti MCP Server?](../introduction) and [How to add custom tools](../custom-tools) # Connect to other MCP Servers in Java Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/mcp-server/connect-to-other-servers/setup-java How to declare an outbound MCP connection in an Atoti Java application through `spring.ai.mcp.client` — the accepted keys, the supported transports, sharing the `atoti.jwt.key` signing key, and the Spring properties and beans that name the server, replace the tool naming scheme, or withhold `getConnectedServers`. ### Atoti Intelligence SDK This is part of the Atoti Intelligence SDK offer. This guide explains how to connect an Atoti Java application to the Model Context Protocol (MCP) servers of other Atoti Server instances, so that it uses their tools as its own. For what a connection then provides (the authentication modes, identity propagation, remote tool naming, `getConnectedServers`, and resilience), see [How connecting to other MCP Servers works](./how-it-works). ## Prerequisites * An Atoti Java project with the Atoti MCP Server already set up; see [How to set up the Atoti MCP Server](../setup/atoti-mcp-server-setup) * A license including the Atoti Intelligence Extension tier, which itself requires Essentials ## How to declare a connection Declare a connection under `spring.ai.mcp.client.streamable-http.connections.`. Everything about it goes on that one node. `url` and `endpoint` are Spring AI's own properties, documented in the [Spring AI MCP Client Boot Starter reference](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-client-boot-starter-docs.html). `authentication` is Atoti's own property. Below, `pnl-server` is a peer Atoti Server in the same deployment, authenticating with a token minted for the calling user. `sandbox` is an unsecured local server used during development: it names no authentication mode, so it sends no credential. ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} spring: ai: mcp: client: streamable-http: connections: pnl-server: url: https://pnl.example.com authentication: atoti-jwt sandbox: url: http://localhost:9090 ``` See [Which authentication modes are available?](./how-it-works#which-authentication-modes-are-available) for what each `authentication` value sends and when to choose it. A connection accepts `url`, `authentication`, and `endpoint`, and nothing else. Any other key is flagged by the IDE as it is typed, and refused at startup with the connection and the offending key named. A misspelled `authentication` would otherwise bind to nothing, leaving the connection silently on `none`. On the wire, that looks exactly like a remote server refusing a correct credential. `authentication` belongs to the HTTP transports only. A connection declared under `spring.ai.mcp.client.stdio.connections` runs a local process and identifies itself by being that process. Writing `authentication` on one is refused at startup rather than ignored. Streamable HTTP is the only transport Atoti supports for an outbound connection. The server-sent events transport is deprecated for removal in Spring AI 2.0.0. Declare every connection under `spring.ai.mcp.client.streamable-http.connections`. Set no `spring.ai.mcp.server.protocol` on the servers being connected to, which leaves them on Streamable HTTP. A connection declared under `spring.ai.mcp.client.sse.connections` is reported at startup as unsupported and gets none of the documented behavior. Its calls carry no credential whatever `authentication` says, and it is absent from `getConnectedServers`. Spring AI still builds a client for it, so nothing else says anything is wrong. ## How to authenticate with `atoti-jwt` An `atoti-jwt` connection mints a token accepted by every server sharing the deployment's signing key. Both servers must be configured with the same `atoti.jwt.key`. Against a session started from the Atoti Python SDK, the same key pair must be passed to that session; see [Connect to other MCP Servers in Python](./setup-python#how-to-authenticate-with-atoti-jwt). Declaring a connection states where a server is, never that it belongs to this deployment. Choose `atoti-jwt` only for servers under the same ownership. ## Which other properties and beans matter? | To | Use | | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Name the server running the chat | `spring.ai.mcp.server.name`, `spring.ai.mcp.server.version`, and `spring.ai.mcp.server.instructions`, which fill the `server`, `version`, and `instructions` fields of its `getConnectedServers` entry. | | Report the right address behind a proxy | `server.forward-headers-strategy`, set to `framework` or `native`. Spring trusts `X-Forwarded-*` headers only when that property tells it to, so without it the reported address is the proxy's back-end hop. `server.address` and `server.port` are not used: they name the interface the server bound, which no client can be given. | | Replace the [remote tool naming scheme](./how-it-works#how-are-remote-tools-named) | An `McpToolNamePrefixGenerator` bean. | | Withhold `getConnectedServers` from an application that holds the Extension tier | Exclude the `connectedServersTools` bean. | Two properties are deliberately not needed. Spring AI's own `spring.ai.mcp.server.expose-mcp-client-tools` is a different mechanism: it publishes one fixed tool list assembled while the application starts, before any user has authenticated. It would therefore need a service account to enumerate the peers, and would then show every client that one account's list. Leave it unset. Remote tools are reported on this server's MCP endpoint over Streamable HTTP, the default. An application that switches its endpoint to the deprecated SSE transport with `spring.ai.mcp.server.protocol=SSE` keeps a working endpoint and its own tools, but not the remote ones. A chat run that carries no address reports its entry with no `url` rather than with an invented one. This happens only when the `chatExecutor` bean is replaced with one that does not propagate the address. ## Related reading * [How connecting to other MCP Servers works](./how-it-works) and [Connect to other MCP Servers in Python](./setup-python) * [Migration notes](../../../releases-and-upgrades/migration-notes#spring-ai-mcp-client-defaults) for the Spring AI MCP client defaults this capability changes * [Spring AI MCP Client Boot Starter reference](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-client-boot-starter-docs.html) for the client properties Atoti builds on * [How to set up the Atoti MCP Server](../setup/atoti-mcp-server-setup) and [How to add custom tools](../custom-tools) # Connect to other MCP Servers in Python Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/mcp-server/connect-to-other-servers/setup-python How to configure an Atoti session in Python to use the tools of other MCP Servers, with `AiConfig`, `McpClientConfig`, `StreamableHttpMcpServerConfig`, and `StdioMcpServerConfig` from `atoti_ai`, covering the server configuration parameters, invalid server names, and sharing a JWT key pair for `atoti-jwt`. ### Atoti Intelligence SDK This is part of the Atoti Intelligence SDK offer. This guide explains how to connect an Atoti session started from Python to other Model Context Protocol (MCP) servers, so that it uses their tools as its own. For what a connection then provides (the authentication modes, identity propagation, remote tool naming, `getConnectedServers`, and resilience), see [How connecting to other MCP Servers works](./how-it-works). ## Prerequisites * An Atoti Python project * A license including the Atoti Intelligence Extension tier, which itself requires Essentials ## How to install the package ```bash theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} uv add "atoti[ai]" ``` ## How to declare a connection Pass an `AiConfig` with an `mcp` attribute to [`SessionConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti.config.SessionConfig.html) when starting the session. The `mcp` attribute takes a `McpClientConfig`, mapping the name the session gives a server to that server's own configuration. Use `StreamableHttpMcpServerConfig` for a server reached over Streamable HTTP, and `StdioMcpServerConfig` for one run as a local process. Below, `pnl-server` is an Atoti Server reached over HTTP, authenticated with a token minted for the calling user. `filesystem` is a local MCP Server started as a stdio process: ```python theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} import atoti as tt from atoti_ai import ( AiConfig, McpClientConfig, StdioMcpServerConfig, StreamableHttpMcpServerConfig, ) mcp_config = McpClientConfig( servers={ "filesystem": StdioMcpServerConfig( command="npx", args=["-y", "@modelcontextprotocol/server-filesystem", "/tmp"], ), "pnl-server": StreamableHttpMcpServerConfig( url="https://pnl.example.com", authentication="atoti-jwt", ), }, ) session_config = tt.SessionConfig(ai=AiConfig(mcp=mcp_config)) ``` ### `StreamableHttpMcpServerConfig` parameters | Parameter | Type | Required | Description | | ---------------- | ---------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `url` | `str` | Yes | The address of the server, without the MCP endpoint. For example `"https://pnl.example.com"`. | | `authentication` | `Literal["none", "atoti-jwt", "pass-through"]` | No | How the session authenticates itself against the server. \* `"none"` sends no credential, for a server that is genuinely unauthenticated. \* `"atoti-jwt"` sends a JWT minted for the calling user, carrying their username and authorities, and requires the server to share this session's JWT signing key (see `JwtConfig`). .. warning:: Only choose this for servers operated by whoever operates this session. The token is handed to the server, which can then send it to any other server sharing the same signing key and be taken for the calling user there. \* `"pass-through"` forwards the calling user's own bearer token unchanged, for a server validating tokens against an external identity provider. | | `endpoint` | `str` | No | The path at which the server speaks the MCP protocol. Defaults to `"/mcp"`, which is the path Atoti Server serves it at. | See [Which authentication modes are available?](./how-it-works#which-authentication-modes-are-available) for what each `authentication` value sends and when to choose it. ### `StdioMcpServerConfig` parameters | Parameter | Type | Required | Description | | --------- | ------------------------- | -------- | ------------------------------------------------------------------------------ | | `command` | `str` | Yes | The executable to run, for example `"node"`. | | `args` | `FrozenSequence[str]` | No | The arguments to pass to `command`. | | `env` | `FrozenMapping[str, str]` | No | The environment variables to give the process, on top of the ones it inherits. | A server declared with `StdioMcpServerConfig` runs as a local process and identifies itself by being that process. It accepts no `authentication` parameter. ## Which server names are invalid? A server name cannot be empty and cannot contain a `.`, which would read as a separator between configuration keys. Building the configuration refuses such a name. The name also prefixes every tool taken from that server, after normalization. Two names normalizing to the same prefix make the session refuse to start. See [How are remote tools named?](./how-it-works#how-are-remote-tools-named) for the normalization rule and the 64-character limit on tool names. ## Where do remote tools appear? They are offered to the LLM in chat, alongside the session's own tools. They are also reported on the session's own MCP endpoint at `f"{session.url}/mcp"`, per calling client. No LLM is required for that: an LLM is only required for chat. ## How to authenticate with `atoti-jwt` Both sessions must share a JWT signing key. From Python, pass the same [`atoti.KeyPair`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti.KeyPair.html) to both: `tt.SessionConfig(security=tt.SecurityConfig(jwt=tt.JwtConfig(key_pair=key_pair)))`. Against a Java Atoti Server, that server's `atoti.jwt.key` property must match the same key pair; see [Connect to other MCP Servers in Java](./setup-java#how-to-authenticate-with-atoti-jwt). Declaring a server states where it is, never that it belongs to this deployment. `atoti-jwt` mints a token accepted by every server sharing the deployment's signing key. Choose it only for servers under the same ownership. ## Related reading * [How connecting to other MCP Servers works](./how-it-works) and [Connect to other MCP Servers in Java](./setup-java) * [How to set up the Atoti MCP Server](../setup/atoti-mcp-server-setup) and [How to add custom tools](../custom-tools) * [`atoti_ai.AiConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.AiConfig.html), [`atoti_ai.McpClientConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.McpClientConfig.html), [`atoti_ai.StreamableHttpMcpServerConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.StreamableHttpMcpServerConfig.html), and [`atoti_ai.StdioMcpServerConfig`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.StdioMcpServerConfig.html) API references # How to add custom tools Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/mcp-server/custom-tools How to extend the Atoti MCP Server with user-defined tools using Spring AI `@Tool`, `@ToolParam`, and `MethodToolCallbackProvider`, including an implementation example, tool method requirements, and verification steps. ### Atoti Intelligence SDK This is part of the Atoti Intelligence SDK offer. This guide explains how to add custom tools to the Atoti MCP Server. ## What are custom tools? Custom tools are user-defined functions that extend the MCP Server's capabilities. They appear alongside built-in Atoti tools and can be called by LLM clients. Custom tools are useful for extending the MCP Server to support workflows beyond those provided by the default Atoti toolset. ## Why add custom tools? Adding custom tools provides several benefits: * Extend MCP Server functionality for specific use cases * Expose domain-specific operations to LLM clients * Integrate business logic with AI interactions * Create specialized data analysis capabilities ## How to add a custom tool Custom tools follow this process: 1. Create a service class with methods annotated with `@Tool` 2. Use `@ToolParam` to describe parameters for the LLM 3. Create a `ToolCallbackProvider` bean that references the service 4. The tools are automatically exposed through the MCP Server ## Prerequisites Before adding custom tools, ensure the following requirements are met: * Atoti MCP Server is set up * Spring Framework knowledge for creating beans and services * Understanding of Spring AI tool annotations ## What does an implementation example look like? The following example shows how to add a custom greeting tool. Add the following code to the main application class or a configuration class: ```java theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} import org.springframework.ai.tool.ToolCallbackProvider; import org.springframework.ai.tool.annotation.Tool; import org.springframework.ai.tool.annotation.ToolParam; import org.springframework.ai.tool.method.MethodToolCallbackProvider; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Service; /** * @author ActiveViam */ @Service public class CustomTools { @Tool(name = "greet", description = "Greets a person with the given name.") public String greet(@ToolParam(description = "Name of the person to greet") final String name) { return "Hello, " + name + "!"; } @Bean public ToolCallbackProvider toolCallbackCustomToolProvider(final CustomTools customTool) { return MethodToolCallbackProvider.builder().toolObjects(customTool).build(); } } ``` ## What are the key components of a custom tool? The implementation includes the following components: * **@Service**: Marks the class as a Spring service * **@Tool**: Marks a method as an MCP tool with name and description * **@ToolParam**: Describes parameters to help the LLM understand usage * **ToolCallbackProvider bean**: Registers the tool with the MCP Server * **MethodToolCallbackProvider**: Wraps the service methods as tools ## What are the tool method requirements? Tool methods must follow these requirements: * Return a value (non-void) * Use simple parameter types (String, int, boolean, or simple objects) * Provide clear descriptions for the LLM * Handle errors appropriately ## Best practices Follow these practices when creating custom tools: * Use descriptive names that indicate the tool's purpose * Write clear descriptions for both tools and parameters * Keep tool logic focused and simple * Return structured data when appropriate * Log tool invocations for debugging * Handle edge cases and errors gracefully ## How to verify custom tools After implementing custom tools, verify they are available: 1. Start the Atoti application 2. Connect to the MCP Server with Claude or Postman 3. Check that the custom tool appears in the tool list 4. Test the tool by calling it with appropriate parameters ## Troubleshooting If custom tools do not appear, check the following: * The service class has the `@Service` annotation * Methods have the `@Tool` annotation * The `ToolCallbackProvider` bean is properly configured * The application starts without errors * The MCP Server is properly initialized ## Related reading After adding custom tools, consider: * [Connect with Postman](./setup/connect-with-postman) to test the tools without an LLM * [Connect with Claude](./setup/connect-with-claude) to test the tools with an LLM # What is the Atoti MCP Server? Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/mcp-server/introduction What the Atoti MCP Server is and why to use it, the best practices for configuring MCP across a deployment - serving chat from one main application and connecting every other server to it - and how it exposes Atoti cubes, hierarchies, measures, and custom tools to any MCP-compatible LLM client such as Claude Desktop. ### Atoti Intelligence SDK This is part of the Atoti Intelligence SDK offer. The Model Context Protocol (MCP) Server is a lightweight service that exposes Atoti's analytical capabilities to external Large Language Model (LLM) clients. * It acts as a bridge between an Atoti data model and AI tools * It enables dynamic, context-aware interactions ## What does the MCP Server provide? The MCP Server provides the following capabilities: * Query Atoti cubes, hierarchies, and measures through an LLM client * Call custom tools that encapsulate business-specific logic * Connect to any MCP-compatible LLM client, such as Claude Desktop * Use the tools of other MCP Servers as Atoti's own ## Why use the Atoti MCP Server? * Use Atoti's analytical capabilities from external AI tools without modifying the Atoti application * No vendor lock-in: works with any MCP-compatible LLM client * Standardized protocol eliminates the need for custom integration code For more information on Model Context Protocol, see the [Model Context Protocol documentation](https://modelcontextprotocol.io/docs/getting-started/intro). ## Can Atoti connect to other MCP Servers? Atoti Server is not only an MCP Server: it can also be an MCP client. It connects out to other MCP Servers. This is typically the other Atoti Servers of the same deployment. * Each server exposes its own cube. * Each cube uses their tools as its own, in chat and on its own MCP endpoint. * Every call runs under the identity of the user who triggered it. This means that the other cube's role-based restrictions stay in force. See [How connecting to other MCP Servers works](./connect-to-other-servers/how-it-works). ## What are the best practices for MCP configuration? When an Atoti deployment runs several Atoti Servers, each server exposes its own cubes. Two rules cover most deployments: 1. Serve chat from one application 2. Connect every other server to that application over MCP The main application: * Holds the only LLM configuration for the deployment. * Answers every cube in one conversation. The other applications do not serve chat. They keep their cubes, their own MCP endpoint and Auto-Explain. ### How to configure chat across a deployment Every application serves chat by default. For now, configure a deployment so that only one of them does: 1. Pick the application that users send their prompts to, called the main application below. 2. Turn chat off on every other application of the deployment. 3. Declare, on the main application, one MCP connection per other application. ```mermaid theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} flowchart LR UI["Atoti UI chat"] --> MAIN["Main application (serves chat)"] CLIENT["Third-party MCP client"] --> MAIN MAIN -- MCP --> PNL["PnL server (chat off)"] MAIN -- MCP --> RISK["Risk server (chat off)"] MAIN -- MCP --> REF["Reference data server (chat off)"] ``` In the Atoti Java SDK, turn chat off with `atoti.ai.chat.enabled`, available from Atoti Server 6.2.1. Add the following to `application.yaml`: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} atoti: ai: chat: enabled: false ``` In the Atoti Python SDK, set [`AiConfig.chat_enabled`](https://docs.activeviam.com/products/atoti/python-sdk/latest/api/atoti_ai.AiConfig.html) to `False` when starting the session: ```python theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} import atoti as tt from atoti_ai import AiConfig session_config = tt.SessionConfig(ai=AiConfig(chat_enabled=False)) ``` This setting results in the following behavior: * The `/chat` endpoint is not registered. * The `/versions` endpoint stops advertising the `activeviam/ai/chat` namespace. * Auto-Explain and the MCP Server are unaffected * The cube tools stay available to the main application. See [How to turn Visualize This off](../enable-ai-tools/visualize-this/configuration#how-to-turn-visualize-this-off) for the full behavior of the setting. This is the recommendation for Atoti Server 6.2.1. A later release may serve chat from several applications of one deployment. An application serving no chat still needs an LLM to produce the optional Auto-Explain AI summary. ### How to connect to an external MCP Server The practices below apply to every outbound connection, toward another Atoti Server as well as toward a third-party MCP Server. Connecting out requires a license including the Atoti Intelligence Extension tier, which itself requires Essentials. * **Connect to every server directly.** Tools do not chain from one connection to the next: a server asked by another aggregating server answers with its own tools alone. Connecting to a peer never brings in the servers that peer is itself connected to. * **Use Streamable HTTP.** Declare every connection under `spring.ai.mcp.client.streamable-http.connections`. It is the only transport supported for an outbound connection. * **Match the authentication mode to the remote server.** Use `atoti-jwt` for another application of the same deployment, sharing the same `atoti.jwt.key` signing key. Use `pass-through` for a server validating tokens against an external identity provider. Leave the default `none` only for a genuinely unauthenticated server, such as a local development server. * **Name the connection after the server.** The name prefixes every tool taken from it, and the model reads it. Keep it to 53 characters or fewer, and keep names distinct after normalization: `pnl-server` and `pnl_server` collide, and the application refuses to start. * **Vet a server run as a local process.** Such a server runs on the machine hosting the application, with that process's rights. Declare only commands the deployment controls. * **Plan no failover.** An unreachable server costs only its own tools, and the failure is not cached. Every other server keeps answering, and the tools reappear on the next answered request. Choose `atoti-jwt` only for servers under the same ownership. The minted token is accepted by every server sharing the deployment's signing key, in the name of a real user. The `getConnectedServers` chat tool reports the address of every connected server, so those addresses reach the model provider. Atoti registers the tool for chat only, never on the MCP endpoint. An application that must keep its internal addresses out of the prompt can exclude the `connectedServersTools` bean; see [Connect to other MCP Servers in Java](./connect-to-other-servers/setup-java#which-other-properties-and-beans-matter). For what a connection provides once declared, see [How connecting to other MCP Servers works](./connect-to-other-servers/how-it-works). To declare one, see [Connect to other MCP Servers in Java](./connect-to-other-servers/setup-java) or [in Python](./connect-to-other-servers/setup-python). # How to set up the Atoti MCP Server Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/mcp-server/setup/atoti-mcp-server-setup How to add the Atoti MCP Server to an Atoti Java project via the `starter-ai-mcp-server` and `mcp-server-spring` Maven dependencies, with steps to verify the MCP Server initializes and its `POST /mcp` endpoint is accessible. ### Atoti Intelligence SDK This is part of the Atoti Intelligence SDK offer. This guide explains how to add the MCP Server to an Atoti Java project. Read more about best practices for configuring MCP across a deployment in [What are the best practices for MCP configuration?](../introduction#what-are-the-best-practices-for-mcp-configuration). ## Prerequisites Before setting up the MCP Server, ensure the following requirements are met: * Java project * The Atoti application has a valid AI license ## Add the MCP Server dependencies to the project Add the following to `pom.xml`: ```xml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} com.activeviam.springboot starter-ai-mcp-server ${activepivot.version} ``` ```xml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} org.springframework.ai spring-ai-starter-mcp-server-webmvc ${spring-ai.version} ``` ## Verify the setup After adding the dependencies, verify that the MCP Server is available: 1. Build the project 2. Start the Atoti application 3. Check the application logs for MCP Server initialization messages 4. Verify that the MCP Server endpoint is accessible, at `POST /mcp` `POST /mcp` is the Streamable HTTP transport, which the starter configures by default. The older server-sent events transport at `/sse` is deprecated for removal in Spring AI 2.0.0; use `/mcp` everywhere. See [MCP transport](./configure-oauth2-self-issued#which-mcp-transport-does-self-issued-mode-use). ## Related reading After setting up the MCP Server, proceed to: * [Connect with Postman](./connect-with-postman) to test the MCP Server * [Connect with Claude](./connect-with-claude) to integrate with Claude AI * [Configure OAuth 2.1 discovery](./configure-oauth2-discovery) to enable browser-based SSO against your IdP for MCP clients * [Add custom tools](../custom-tools) to extend functionality * [MCP credentials page](./mcp-credentials-page) to mint long-lived bearer tokens for MCP clients (opt-in feature, disabled by default) # Configure OAuth 2.1 discovery Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/mcp-server/setup/configure-oauth2-discovery Configure the Atoti MCP Server as an OAuth 2.1 resource server that publishes RFC 9728 Protected Resource Metadata, enabling MCP clients (Claude Code, Cursor, Cline, Gemini CLI) to drive browser-based PKCE authentication against a corporate identity provider such as Okta, Entra ID, or Keycloak. ### Atoti Intelligence SDK This is part of the Atoti Intelligence SDK offer. This guide explains how to enable the OAuth 2.1 / PKCE browser-SSO flow on the Atoti MCP Server, so MCP clients (Claude Code, Claude Desktop, Cursor, Cline, VS Code's MCP support, Gemini CLI) can drive authentication against your IdP without users copy-pasting Bearer tokens. ## What does this feature enable? When this feature is enabled, the MCP Server: 1. Publishes an [RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728) **Protected Resource Metadata** document at `/.well-known/oauth-protected-resource`. The document tells clients which authorization server(s) to talk to and which scopes to request. 2. Returns `WWW-Authenticate: Bearer realm="mcp", resource_metadata="..."` on 401 responses from `/mcp/**` and `/sse`, so clients can discover the metadata document on first contact. Compliant MCP clients then drive the standard [OAuth 2.1 authorization code + PKCE](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization) flow against the IdP: * The client opens the system browser at the IdP authorization endpoint. * The user signs in, subject to whatever the IdP enforces (MFA, conditional access, and so on). * The IdP redirects back to a loopback URI. * The client swaps the code for an access token. * The token is stored in the OS keychain and refreshed silently in the background. Users SSO once in a browser instead of copy-pasting tokens into their MCP client configuration. ## Prerequisites * The Atoti MCP Server is already running. See [How to set up the Atoti MCP Server](./atoti-mcp-server-setup). * An OAuth 2.0 authorization server (Okta, Entra ID, Auth0, Keycloak, Cognito, ...) is configured to issue access tokens for users who should be able to call MCP endpoints. * The Atoti Spring Security stack is already configured to validate the IdP's JWTs (this is the same setup used by other Bearer-secured Atoti endpoints — no extra steps). ## How to enable OAuth 2.1 discovery Add the following to your `application.yml`: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} atoti: server: endpoint: mcp: oauth2: enabled: true authorization-servers: - https://idp.example.com/realms/atoti scopes-supported: - mcp.read - mcp.write ``` `authorization-servers` is the only required setting when `enabled=true`. Startup fails with a clear error if it is left empty. ## Property reference | Property | Type | Default | Description | | ----------------------------------------------------------- | --------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `atoti.server.endpoint.mcp.oauth2.enabled` | boolean | `false` | Master switch. When `false`, none of the discovery beans are registered and MCP endpoints behave exactly as before. | | `atoti.server.endpoint.mcp.oauth2.resource` | string (URI) | request-derived | Absolute URI identifying this MCP Server as an OAuth 2.0 resource. When unset, derived from the request's context path at serve time. Set this explicitly if the server is behind a reverse proxy that rewrites URLs. | | `atoti.server.endpoint.mcp.oauth2.authorization-servers` | list of URIs | `[]` | URLs of trusted authorization servers. At least one is required when the feature is enabled. | | `atoti.server.endpoint.mcp.oauth2.scopes-supported` | list of strings | `[]` | Optional OAuth 2.0 scopes advertised to clients. Omitted from the payload when empty. | | `atoti.server.endpoint.mcp.oauth2.bearer-methods-supported` | list of strings | `["header"]` | Supported Bearer token transport methods per RFC 6750. | | `atoti.server.endpoint.mcp.oauth2.resource-documentation` | string (URI) | *unset* | Optional URL pointing at human-readable documentation for the resource. | | `atoti.server.endpoint.mcp.oauth2.realm` | string | `"mcp"` | Realm used in the `WWW-Authenticate: Bearer realm="..."` challenge. | | `atoti.server.endpoint.mcp.oauth2.well-known-path` | string | `/.well-known/oauth-protected-resource` | Path under which the metadata document is served. Override only if another resource server on the same origin already owns the default path. | ## How to set up the IdP Concrete steps vary by IdP, but the broad shape is: 1. Configure your IdP to issue access tokens for the MCP client (Claude Desktop, Claude Code, Cursor, etc.). Most enterprise IdPs require the client to be pre-registered; some support [Dynamic Client Registration (RFC 7591)](https://datatracker.ietf.org/doc/html/rfc7591). 2. Set the resource/audience claim on the issued tokens to match `atoti.server.endpoint.mcp.oauth2.resource`. Atoti's JWT validator must already trust this audience. 3. Allow the redirect URI used by your client. Most MCP clients use a random loopback URI such as `http://127.0.0.1:/callback`. ## How does each MCP client behave? * **Claude Code, Claude Desktop, Cursor, Cline, VS Code MCP, Gemini CLI**: detect the `WWW-Authenticate` header automatically, open the system browser for the PKCE flow, store the resulting access and refresh tokens in the OS keychain, and refresh silently. * **Older or stdio-only MCP clients**: use the [`mcp-remote`](https://github.com/geelen/mcp-remote) bridge — it performs the PKCE dance locally and proxies SSE to the remote MCP Server. ## What are the reverse-proxy caveats? If the Atoti Server sits behind a reverse proxy that rewrites the host or scheme: * Either set `atoti.server.endpoint.mcp.oauth2.resource` explicitly to the public URL of the server, or * Enable Spring Boot's `ForwardedHeaderFilter` (via `server.forward-headers-strategy=framework`) so the request-derived URL honours `X-Forwarded-*`. Without one of these, the `resource` field and the `resource_metadata=` URL in the challenge header will reflect the internal hostname instead of the public one. ## What are the limitations and out-of-scope features? In `external` mode the MCP Server is only a resource server — it advertises discovery metadata and validates Bearer tokens, but it does not issue them. The following are therefore out of scope **for `external` mode** (they are the IdP's responsibility): * **Dynamic Client Registration (RFC 7591).** Customers pre-register MCP clients in their IdP, or rely on the IdP's own DCR support. * **`/.well-known/oauth-authorization-server`.** That endpoint is served by the IdP. If you want Atoti itself to handle client registration and serve the authorization-server metadata, use [self-issued mode](./configure-oauth2-self-issued) instead — it implements both. The following are not implemented in either mode in this release: * **Token Exchange (RFC 8693).** The MCP Server does not exchange tokens for downstream services. * **Per-error-code `WWW-Authenticate` parameters** (`error=invalid_token`, etc., per RFC 6750). The v1 challenge contains only `realm` and `resource_metadata`. ## Related reading * [How to set up the Atoti MCP Server](./atoti-mcp-server-setup) * [Connect with Claude](./connect-with-claude) * [RFC 9728: OAuth 2.0 Protected Resource Metadata](https://datatracker.ietf.org/doc/html/rfc9728) * [MCP authorization spec (2025-06-18)](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization) # Configure self-issued OAuth 2.1 Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/mcp-server/setup/configure-oauth2-self-issued Configure the Atoti MCP Server as its own OAuth 2.1 authorization server, handling Dynamic Client Registration, browser PKCE sign-in against Atoti's own login page, and JWT issuance without an external identity provider. ### Atoti Intelligence SDK This is part of the Atoti Intelligence SDK offer. This guide explains how to enable the `self-issued` OAuth 2.1 mode, available from Atoti Server 6.2.0, on the Atoti MCP Server, where the Atoti Server acts as its own authorization server. MCP clients (Claude Code, Claude Desktop, Cursor, Cline, VS Code's MCP support, Gemini CLI) drive the standard browser-based PKCE flow directly against Atoti. No external identity provider is required. Users sign in with their existing Atoti credentials. No separate IdP, no extra user store. ## What is self-issued mode? The Atoti MCP Server supports two OAuth 2.1 modes, selected by `atoti.server.endpoint.mcp.oauth2.mode`: | Mode | Who issues tokens | When to use | | -------------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | | `external` (default) | A corporate IdP (Okta, Entra ID, Auth0, Keycloak, ...) | SSO, MFA, and enterprise identity management are already handled by the IdP. See [Configure OAuth 2.1 discovery](./configure-oauth2-discovery). | | `self-issued` | The Atoti Server itself | The deployment authenticates users through Atoti's own user store and no external IdP is available or desired. | In `self-issued` mode the Atoti Server is both the OAuth 2.1 authorization server and the resource server. It publishes the standard metadata documents, handles Dynamic Client Registration, and issues JWTs signed with Atoti's own keys. The MCP client's authorization flow is identical to `external` mode; only the server the client talks to changes. ## Prerequisites * The Atoti MCP Server is already running. See [How to set up the Atoti MCP Server](./atoti-mcp-server-setup). * Atoti Server is configured with an RSA keypair via `atoti.jwt.key.*` (recommended). When no keypair is configured, an ephemeral key is generated at startup (see [Signing keys](#which-signing-key-does-self-issued-mode-use) for the implications). ## Minimal configuration Self-issued mode requires only four lines. Add the following to `application.yml`: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} atoti: server: endpoint: mcp: oauth2: enabled: true mode: self-issued ``` No authorization-server URL, no client registration, no IdP setup. Atoti handles everything. ## How does the browser PKCE flow work? The following steps describe the full authorization flow as a client such as Claude Code experiences it. 1. The client sends `POST /mcp` and receives `401` with `WWW-Authenticate: Bearer realm="mcp", resource_metadata="..."`. 2. The client fetches `/.well-known/oauth-protected-resource` (RFC 9728). The document advertises the same origin as the authorization server. 3. The client fetches `/.well-known/oauth-authorization-server` (RFC 8414). The document advertises `authorization_endpoint`, `token_endpoint`, `registration_endpoint`, `jwks_uri`, and PKCE `S256` support. 4. The client performs anonymous Dynamic Client Registration at `POST /oauth2/register` (also accepted at `POST /register`). It receives a generated `client_id`. 5. The client opens the system browser at `/oauth2/authorize`. The user is redirected to Atoti's own branded login page at `/login` and signs in with existing Atoti credentials. 6. After sign-in, the browser is shown a consent page at `/oauth2/consent` titled "Allow Atoti to connect to \?" listing the requested scopes (for example, `mcp.read`, `mcp.write`). The user clicks **Allow** or **Deny**. 7. On **Allow**, the browser redirects back to the client's loopback URI with an authorization code. On **Deny**, `access_denied` is returned to the client and no token is issued. 8. The client exchanges the code at `POST /oauth2/token` for a JWT access token and a refresh token. 9. The client calls `POST /mcp` with `Authorization: Bearer `. Atoti validates the token and the user's Atoti roles authorize the requested MCP tools. ## Which endpoints does self-issued mode expose? When `mode=self-issued`, the following endpoints become active in addition to the standard `/mcp` endpoint: | Endpoint | Purpose | | ----------------------------------------- | ----------------------------------------- | | `/.well-known/oauth-protected-resource` | RFC 9728 protected resource metadata | | `/.well-known/oauth-authorization-server` | RFC 8414 authorization server metadata | | `/oauth2/authorize` | Authorization endpoint (browser redirect) | | `/oauth2/token` | Token endpoint (code exchange, refresh) | | `/oauth2/jwks` | JWKS endpoint (public signing keys) | | `/oauth2/register` | Dynamic Client Registration (RFC 7591) | | `/register` | Alias for `/oauth2/register` | | `/oauth2/consent` | Browser consent page (Allow/Deny) | ## How does self-issued mode work? ### How does self-issued mode handle identity and keys? Self-issued mode reuses Atoti's existing identity stack. End users authenticate against the same user store that secures the rest of the Atoti deployment (the application's configured `UserDetailsService` or authentication manager). The issued JWTs are signed with Atoti's own RSA keypair, validated by Atoti's normal JWT filter, and carry the user's real Atoti roles into `/mcp` authorization. No separate key material or user store is needed. Self-issued mode **requires** the application to provide a `UserDetailsService` (or authentication manager) bean. Atoti deployments already supply one: the basic-authentication fallback registers a `UserDetailsService` whenever any authentication is configured. For local development without a full deployment, the `apps/basic` sample application supplies an in-memory user store. If no `UserDetailsService` is configured, the server still starts but logs a warning, and the browser login cannot authenticate users until one is provided: `atoti.server.endpoint.mcp.oauth2.mode=self-issued is active but no UserDetailsService is configured, so the OAuth 2.1 browser login cannot authenticate users.` ### Which signing key does self-issued mode use? The server selects the signing key in the following order of precedence: 1. **Atoti's configured RSA keypair** (recommended). Set via `atoti.jwt.key.*` or `activeviam.jwt.key.*`. The same key signs MCP tokens and all other Atoti JWTs. 2. **A PKCS#12 or JKS keystore**, configured via `atoti.server.endpoint.mcp.oauth2.authserver.jwk.keystore-location`, `...keystore-password`, and `...key-alias`. 3. **An ephemeral keypair**, generated at startup. This fallback is for development only: all issued tokens become invalid on restart, and a warning is logged at startup. For production deployments, use option 1 or 2 so that tokens survive server restarts. ### How is the issuer URI configured? `atoti.server.endpoint.mcp.oauth2.authserver.issuer` is optional. When unset, the issuer and all advertised absolute URLs are derived from the incoming HTTP request. Set it explicitly when the server runs behind a reverse proxy that rewrites the host or scheme, or enable Spring Boot's `ForwardedHeaderFilter` via `server.forward-headers-strategy=framework`. ### Which MCP transport does self-issued mode use? The starter configures `spring.ai.mcp.server.protocol=STREAMABLE` by default, which exposes a single `POST /mcp` endpoint. This is the transport expected by current MCP clients, and the one to use everywhere. The older server-sent events transport, `spring.ai.mcp.server.protocol=SSE`, is deprecated for removal in Spring AI 2.0.0. It still serves this server's own tools at `/sse`, but the tools of [connected MCP Servers](../connect-to-other-servers/how-it-works) are not reported on it, and Atoti cannot connect out to a server that only speaks it. Leave the property unset unless a client outside the deployment's control requires SSE, and plan to move that client to `POST /mcp`. ### How does user consent work in self-issued mode? After a user authenticates, the browser is shown a consent page at `/oauth2/consent` titled "Allow Atoti to connect to \?". The page lists the requested OAuth scopes (for example, `mcp.read`, `mcp.write`) and presents **Allow** and **Deny** buttons. * **Allow** completes the flow: an authorization code is issued and the client exchanges it for a JWT. * **Deny** returns `access_denied` to the client; no token is issued. Consent is requested on every authorization request, including when the user already has an active Atoti browser session. Consent is never remembered across requests. The consent page itself is protected by the deployment's existing human security filter chain (the same authentication method as the rest of the Atoti UI). A browser that arrives at `/oauth2/consent` unauthenticated is redirected to the Atoti login page first. A non-browser caller receives `401`. **CSRF protection.** The Allow/Deny decision is protected by a single-use session-bound consent key. The key is generated when the gate stashes the pending authorization request, and consumed on the subsequent `/oauth2/authorize` pass. An attacker cannot forge a consent POST without knowing that key, which lives only in the server-side session. For production deployments, also set `server.servlet.session.cookie.same-site=Lax` so the session cookie is not sent on cross-site navigations, adding defense in depth against CSRF on the consent endpoint. To disable the consent step and restore the previous behavior (a code is issued immediately after authentication), set `atoti.server.endpoint.mcp.oauth2.authserver.consent.enabled` to `false`. ## Property reference All properties are under the `atoti.server.endpoint.mcp.oauth2` prefix unless noted. | Property | Type | Default | Description | | ------------------------------------------------------------------- | ------------ | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `atoti.server.endpoint.mcp.oauth2.enabled` | boolean | `false` | Master switch. Must be `true` to activate self-issued mode. | | `atoti.server.endpoint.mcp.oauth2.mode` | enum | `external` | Set to `self-issued` to use the Atoti Server as its own authorization server. | | `atoti.server.endpoint.mcp.oauth2.authserver.issuer` | string (URI) | request-derived | Issuer advertised in tokens and metadata documents. Set when the server is behind a rewriting reverse proxy. | | `atoti.server.endpoint.mcp.oauth2.authserver.access-token-ttl` | duration | `1h` | Lifetime of issued JWT access tokens. | | `atoti.server.endpoint.mcp.oauth2.authserver.refresh-token-ttl` | duration | `8h` | Lifetime of refresh tokens. | | `atoti.server.endpoint.mcp.oauth2.authserver.jwk.keystore-location` | string | *unset* | Path to a PKCS#12 or JKS keystore holding the RSA signing key. When unset, Atoti's `atoti.jwt.key.*` keypair is used; when that is also absent, an ephemeral dev keypair is generated. | | `atoti.server.endpoint.mcp.oauth2.authserver.jwk.keystore-password` | string | *unset* | Password for the keystore. | | `atoti.server.endpoint.mcp.oauth2.authserver.jwk.key-alias` | string | *unset* | Alias of the signing key entry in the keystore. | | `atoti.server.endpoint.mcp.oauth2.authserver.client.client-id` | string | `atoti-mcp` | Pre-registered client ID. MCP clients normally self-register via Dynamic Client Registration and do not need this. | | `atoti.server.endpoint.mcp.oauth2.authserver.client.redirect-uris` | list | loopback defaults | Allowed OAuth 2.0 redirect URIs. | | `atoti.server.endpoint.mcp.oauth2.authserver.client.scopes` | list | `[mcp.read, mcp.write]` | Scopes the pre-registered client may request. | | `atoti.server.endpoint.mcp.oauth2.authserver.consent.enabled` | boolean | `true` | Show the consent page ("Allow Atoti to connect to \?") before issuing a code. When `false`, a code is issued immediately after authentication, with no consent step. | ## Which limitations apply to self-issued mode? **Open Dynamic Client Registration.** The `/oauth2/register` endpoint accepts unauthenticated registration requests by design: any caller can register a client, but no token is issued until a user completes interactive login at `/oauth2/authorize`. For deployments with strict registration policies, place the endpoint behind rate-limiting or a registration filter. **In-memory client store.** Dynamically registered clients are held in memory. They are lost on server restart, but clients re-register transparently on the next connection attempt. **Ephemeral signing key.** If no RSA keypair is configured (neither `atoti.jwt.key.*` nor a keystore), an ephemeral key is generated at startup. All tokens issued with that key become invalid on restart. A warning is logged. Use a persistent key in production. **Token lifetime.** Access tokens default to one hour. Configure `atoti.server.endpoint.mcp.oauth2.authserver.access-token-ttl` to a shorter value in security-sensitive environments. ## When should each OAuth 2.1 mode be used? | Scenario | Recommended mode | | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | The deployment uses a corporate IdP (Okta, Entra ID, Auth0, Keycloak) and SSO/MFA is required | `external` (see [Configure OAuth 2.1 discovery](./configure-oauth2-discovery)) | | Atoti already manages user authentication and no external IdP is available or desired | `self-issued` (this page) | | Prototyping or local development without any IdP | `self-issued` with the application providing a user store (the `apps/basic` sample application includes an in-memory one) | ## Related reading * [How to set up the Atoti MCP Server](./atoti-mcp-server-setup) * [Configure OAuth 2.1 discovery](./configure-oauth2-discovery) (`external` mode with a corporate IdP) * [Connect with Claude](./connect-with-claude) * [RFC 8414: OAuth 2.0 Authorization Server Metadata](https://datatracker.ietf.org/doc/html/rfc8414) * [RFC 7591: OAuth 2.0 Dynamic Client Registration Protocol](https://datatracker.ietf.org/doc/html/rfc7591) * [RFC 9728: OAuth 2.0 Protected Resource Metadata](https://datatracker.ietf.org/doc/html/rfc9728) * [MCP authorization spec (2025-06-18)](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization) # How to connect with Claude Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/mcp-server/setup/connect-with-claude How to configure Claude Desktop to connect to the Atoti MCP Server, including the `mcpServers` JSON configuration block, `mcp-remote` via `npx`, Base64 Basic Auth passkey generation, and tool discovery verification steps. ### Atoti Intelligence SDK This is part of the Atoti Intelligence SDK offer. This guide explains how to connect Claude Desktop to the Atoti MCP Server. ### OAuth 2.1 browser authentication If the Atoti Server has OAuth 2.1 enabled, recent versions of Claude Desktop and Claude Code drive the browser-based PKCE flow automatically, with no Basic-auth passkey or manual token handling required. Skip the `--header "Authorization: Basic {passkey}"` step below and point Claude directly at the server's `POST /mcp` URL. Two modes are available: [external IdP discovery (Okta, Entra ID, Auth0, Keycloak)](./configure-oauth2-discovery) and [self-issued mode](./configure-oauth2-self-issued), where the Atoti Server acts as its own authorization server. The examples below use the Streamable HTTP transport at `POST /mcp`, which the starter configures by default. The older server-sent events transport at `/sse` is deprecated for removal in Spring AI 2.0.0; it is served only when the deployment sets `spring.ai.mcp.server.protocol=SSE`, and reaching it means pointing the client at `http://localhost:9090/sse` with `--transport sse-only`. See [MCP transport](./configure-oauth2-self-issued#which-mcp-transport-does-self-issued-mode-use). ## Prerequisites Before connecting Claude, ensure the following requirements are met: * Atoti MCP Server is set up and running * Claude Desktop is installed * Access to Claude Desktop configuration file * Atoti application credentials (username and password) ## How to configure Claude Desktop Add the MCP Server configuration to the Claude Desktop config file. The location of this file depends on the operating system. The following examples assume the application runs locally on port `9090`. Replace `9090` with the port on which the application is running. ### Option 1: Basic authentication The following example uses HTTP Basic authentication. Replace `{passkey}` with a Base64-encoded string in the format `Base64(:)`. ```json theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} { "mcpServers": { "my-mcp-server": { "command": "npx", "args": [ "-y", "mcp-remote", "http://localhost:9090/mcp", "--transport", "http-only", "--header", "Authorization: Basic {passkey}" ] } } } ``` ### Option 2: Bearer token authentication The following example uses a long-lived JWT bearer token. Replace `` with a token generated from the [MCP credentials page](./mcp-credentials-page). ```json theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} { "mcpServers": { "my-mcp-server": { "command": "npx", "args": [ "-y", "mcp-remote", "http://localhost:9090/mcp", "--transport", "http-only", "--header", "Authorization: Bearer " ] } } } ``` The bearer token approach avoids embedding credentials in the configuration file. The MCP credentials page must be enabled in the application before a token can be generated. ## How to generate the passkey Replace `{passkey}` in the Basic authentication configuration with a Base64-encoded string. Generate the passkey using the following format: ``` Base64(:) ``` Replace `` and `` with the Atoti application credentials. ## How to verify the connection After configuring Claude Desktop, verify that the connection works: 1. Restart Claude Desktop 2. Check that Claude discovers the MCP Server tools Tool Discovery 3. Test interaction with the Atoti Server by asking Claude to use the available tools Claude Answer 1 Claude Answer 2 ## Troubleshooting If Claude does not discover the tools, check the following: * The Atoti application is running and accessible * The MCP Server endpoint is available at the configured URL * The passkey is correctly formatted and encoded * The Claude Desktop configuration file is valid JSON ## Related reading After connecting Claude, explore additional capabilities: * [Add custom tools](../custom-tools) to extend MCP Server functionality # How to connect with Postman Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/mcp-server/setup/connect-with-postman How to test and debug the Atoti MCP Server with Postman, including Basic Auth configuration, tool discovery via SSE, JSON-RPC `tools/call` POST request format, response interpretation, and custom tool validation. ### Atoti Intelligence SDK This is part of the Atoti Intelligence SDK offer. This guide explains how to use Postman to test and interact with the Atoti MCP Server. ## Why connect with Postman? Using Postman to connect to the MCP Server provides several benefits: * Test MCP Server configuration and availability * Validate tool discovery and execution * Explore available tools and their parameters * Debug integration issues * Test custom tools during development ## Prerequisites Before connecting with Postman, ensure the following requirements are met: * Atoti MCP Server is set up and running * Postman is installed (desktop or web version) * Atoti application credentials (username and password) * The MCP Server endpoint URL, `http://localhost:9090/mcp` for the default Streamable HTTP transport The following examples assume the application runs locally on port `9090`. Replace `9090` with the port on which the application is running. `/sse` is the older server-sent events transport, deprecated for removal in Spring AI 2.0.0 and not served unless the deployment sets `spring.ai.mcp.server.protocol=SSE`. Use `POST /mcp` everywhere. See [MCP transport](./configure-oauth2-self-issued#which-mcp-transport-does-self-issued-mode-use). ## How to configure authentication Set up authentication in Postman to access the MCP Server. Follow these steps: 1. Open Postman 2. Create a new request 3. Select the Authorization tab 4. Choose "Basic Auth" as the type and enter the Atoti username and password. Alternatively, choose "Bearer Token" and paste a token generated from the [MCP credentials page](./mcp-credentials-page). ## How to discover available tools Make a request to the MCP Server to discover available tools. The following example shows a request to list tools: Postman tool discovery ## How to make tool requests After discovering available tools, make requests to execute specific tools. Configure the request with the following components: * **Method**: POST * **URL**: The MCP Server endpoint * **Headers**: * `Content-Type: application/json` * `Accept: text/event-stream` (for SSE endpoints) * **Body**: JSON payload with tool name and parameters ## What does an example request look like? The following example shows a typical tool execution request: ```json theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "tool-name", "arguments": { "parameter1": "value1", "parameter2": "value2" } } } ``` Replace the following placeholders: * `tool-name`: The name of the tool to execute * `parameter1`, `parameter2`: Tool-specific parameters * `value1`, `value2`: Parameter values ## How to interpret responses The MCP Server returns responses in JSON-RPC format. A successful response includes: * Response data in the `result` field * Request ID matching the original request * HTTP status code 200 An error response includes: * Error details in the `error` field * Error code and message * HTTP error status code ## Common use cases Once connected, Postman can be used to test the following: * Verify MCP Server availability * List all available tools * Execute tools with different parameters * Test authentication and authorization * Validate custom tool implementations * Debug integration issues ## Troubleshooting If connections fail, check the following: * The Atoti application is running * The MCP Server endpoint is accessible * Authentication credentials are correct * The request format matches JSON-RPC specifications * Firewall or network settings allow connections ## Related reading After testing with Postman, consider: * [How to set up the Atoti MCP Server](./atoti-mcp-server-setup) * [MCP credentials page](./mcp-credentials-page) to generate a Bearer token * [Connect with Claude](./connect-with-claude) for AI-powered interaction * [Add custom tools](../custom-tools) to extend functionality # What is the MCP credentials page? Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/mcp-server/setup/mcp-credentials-page How to enable the opt-in MCP credentials page to mint long-lived RS512-signed JWT bearer tokens for MCP clients, including token lifetime configuration, token generation, and security considerations. ### Atoti Intelligence SDK This is part of the Atoti Intelligence SDK offer. The MCP credentials page, available from Atoti Server 6.2.0, is a built-in browser interface that mints long-lived JWT bearer tokens for use with MCP clients. Instead of embedding a username and password in every MCP client configuration, a signed-in user generates a token once. The user then pastes the token into the client. The MCP credentials page is opt-in and disabled by default. ## Prerequisites Before the MCP credentials page is available, ensure the following conditions are met: * The Atoti application has a valid AI license * The `starter-ai-mcp-server` dependency is included in the project * The `atoti.mcp.credentials.enabled` property is set to `true` (see [How to enable the credentials page](#how-to-enable-the-credentials-page)) ## How to enable the credentials page The credentials page is disabled by default. Enable this feature deliberately. The page allows any authenticated Atoti user to mint long-lived tokens. Review access controls before enabling in production environments. To enable the credentials page, add the following to the application configuration: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} atoti: mcp: credentials: enabled: true ``` The equivalent environment variable is `ATOTI_MCP_CREDENTIALS_ENABLED=true`. When this property is absent or set to `false`, no beans for the credentials page load and the `/mcp-credentials/**` path is not handled. ## What optional configuration is available? The following property controls the maximum token lifetime a user can request: | Property | Type | Default | Description | | ------------------------------------ | -------- | ------- | -------------------------------------------------------------------------------------------------- | | `atoti.mcp.credentials.max-lifetime` | Duration | `P365D` | Upper bound on the requested expiration date. Requests beyond this limit return `400 Bad Request`. | Example — restrict token lifetime to 30 days: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} atoti: mcp: credentials: max-lifetime: P30D ``` ## How to generate a token The MCP credentials page is available at `/mcp-credentials` once the property is enabled. If the session is not authenticated, Spring Security redirects to `/login/index.html?redirectUrl=/mcp-credentials`. It returns to the credentials page after a successful login. To generate a token: 1. Navigate to `/mcp-credentials` in a browser while signed in to the Atoti application. 2. Select an expiration preset: **7 days**, **30 days**, **60 days**, **90 days**, **1 year**, or **Custom date**. 3. For a custom date, select a date within the configured maximum lifetime. 4. Click **Generate token**. 5. Copy the displayed token immediately. Atoti does not store the token after it is displayed. If the token is lost, generate a new one. ## How to use the token with an MCP client Pass the token as a bearer authorization header in the MCP client configuration. The following example shows how to configure Claude Desktop with a bearer token. Replace `9090` with the application port and `` with the generated token: This example uses the Streamable HTTP transport at `POST /mcp`, which the starter configures by default. The older server-sent events transport at `/sse` is deprecated for removal in Spring AI 2.0.0. See [MCP transport](./configure-oauth2-self-issued#which-mcp-transport-does-self-issued-mode-use). ```json theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} { "mcpServers": { "my-mcp-server": { "command": "npx", "args": [ "-y", "mcp-remote", "http://localhost:9090/mcp", "--transport", "http-only", "--header", "Authorization: Bearer " ] } } } ``` The same bearer token can be used in any MCP-compatible client that accepts custom HTTP headers. ## What the token contains The token is a standard RS512-signed JWT. It contains the following claims: | Claim | Description | | ------------- | ----------------------------------------------- | | `sub` | The authenticated user's username | | `iss` | `activeviam` | | `iat` | Issued-at timestamp | | `nbf` | Not-before timestamp | | `exp` | Expiration timestamp matching the selected date | | `jti` | Unique token identifier | | `authorities` | The user's roles at the time of minting | ## What are the security considerations? * **Tokens are not persisted.** The server does not store tokens after issuing them. There is no server-side revocation list. * **Expiration is the only revocation mechanism.** If a token needs to be invalidated before its expiration date, the only option is to rotate the RSA key used to sign tokens. Rotating the key invalidates all existing tokens. * **Losing a token is not recoverable.** Generate a new token from the credentials page. * **Token authorities are fixed at mint time.** If the user's roles change after the token is minted, the token still carries the original authorities until it expires. * **The page is opt-in.** It is disabled by default to follow the principle of least privilege. ## Related reading * [How to set up the Atoti MCP Server](./atoti-mcp-server-setup) for initial server configuration * [How to connect with Claude](./connect-with-claude) for Claude Desktop configuration examples * [How to connect with Postman](./connect-with-postman) for testing with Postman # Monitoring Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/monitoring How to collect diagnostic information for Atoti Intelligence at runtime, including DEBUG logging for Auto-Explain and Visualize This in `application.yaml`, Spring AI logback configuration, and resolutions for MCP server context path, keep-alive, and chat stream proxy buffering issues. This page explains how to monitor and diagnose Atoti Intelligence features, including Auto-Explain, Visualize This, and the MCP server. ## Why monitor Atoti Intelligence? Monitoring provides visibility into the behavior of AI features at runtime. It helps identify configuration problems, connectivity issues, and unexpected behavior before they affect end users. Increasing log verbosity is the primary way to collect detailed diagnostic information. Combined with common pitfall resolutions, this page covers the most common situations encountered when operating Atoti Intelligence features. ## How to collect diagnostic information When reporting an issue, gather the following information: * Application logs at the relevant log level * Browser console output * Screenshots of the issue Enable DEBUG logging before reproducing the issue. This captures more detail and makes logs more useful for diagnosis. ## How to increase logging levels The following sections explain how to enable DEBUG-level logging for each Atoti Intelligence feature. ### Auto-Explain Set Auto-Explain logging to DEBUG level in the application configuration file. Add the following to `application.yaml`: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} logging: level: atoti: server: autoexplain: DEBUG ``` ### Spring AI Set Spring AI logging to DEBUG level in the logback configuration file. Add the following to the logback configuration: ```xml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} ``` ### Visualize This Set Visualize This logging to DEBUG level in the application configuration file. Add the following to `application.yaml`: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} logging: level: atoti: server: chat: DEBUG ``` ## OpenTelemetry metrics Atoti Server exposes OpenTelemetry metrics for AI and chat features (`atoti.ai.chat.*`), covering prompt execution, conversations, and tool calls. These metrics can be collected using any OpenTelemetry-compatible backend. In addition, Spring AI provides its own metrics and traces for model interactions, which are automatically available when OpenTelemetry is configured. For the full metrics reference, see [Metrics](https://docs.activeviam.com/products/atoti/server/latest/docs/monitoring/metrics) in the Atoti Server documentation. To configure OpenTelemetry collection, see [How to set up observability with OpenTelemetry](https://docs.activeviam.com/products/atoti/server/latest/docs/monitoring/otel_how_to) in the Atoti Server documentation. ## Common pitfalls ### Context path When the application runs under a context path, the MCP server requires an explicit base URL to resolve correctly. Add the following to `application.yaml`: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} spring: ai: mcp: server: base-url: ${context_path} ``` ### Keep-alive Some third-party applications drop the connection to the MCP server after a period of inactivity. Configuring a keep-alive interval causes the server to send periodic pings to the client, preventing the connection from timing out. Add the following to `application.yaml`: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} spring: ai: mcp: server: keep-alive-interval: 30s ``` A shorter interval sends pings more frequently and reduces the chance of a timeout. A longer interval reduces network overhead but increases the risk of the connection dropping between pings. ### Reverse proxy buffering In Visualize This, client tools (adding a widget, a page, or a filter to the dashboard) time out behind a reverse proxy, with the server log reporting `Client tool '' ... timed out after ms`, and plain-text answers arrive all at once instead of streaming. The cause is a reverse proxy buffering or compressing the chat endpoint's `text/event-stream` (SSE) response at `/activeviam/ai/rest/v2/chat`. Mid-stream tool-call events then only reach the browser once the stream ends, by which time the server-side wait has already timed out. Starting with Atoti Server 6.1.23, chat streaming responses carry `X-Accel-Buffering: no` and `Cache-Control: no-cache, no-transform` to prevent this. If the proxy ignores those headers, or on earlier versions, configure the proxy location for the chat endpoint explicitly: disable response buffering, caching, and compression, and set the read or idle timeout above the SSE stream lifetime (30 minutes by default, controlled by the `sseEmitterTimeoutMs` property). ```nginx theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} location /activeviam/ai/rest/v2/chat { proxy_pass http://backend; proxy_buffering off; # disable response buffering proxy_cache off; # disable caching gzip off; # exclude this response from compression proxy_read_timeout 1800s; # 30 minutes, matching sseEmitterTimeoutMs } ``` Directive names and syntax vary by proxy vendor and version. ## Related reading * [How to set up the Atoti MCP Server](./mcp-server/setup/atoti-mcp-server-setup) * [How to set up Auto-Explain in Java](./enable-ai-tools/auto-explain/setup-java) * [How to set up Auto-Explain in Python](./enable-ai-tools/auto-explain/setup-python) * [How to set up Visualize This in Java](./enable-ai-tools/visualize-this/setup-java) * [How to set up Visualize This in Python](./enable-ai-tools/visualize-this/setup-python) * [Metrics](https://docs.activeviam.com/products/atoti/server/latest/docs/monitoring/metrics) — full list of Atoti Server metrics, including AI-specific chat metrics * [How to set up observability with OpenTelemetry](https://docs.activeviam.com/products/atoti/server/latest/docs/monitoring/otel_how_to) # Retries and timeouts Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/retries-and-timeouts The six guards bounding what one Visualize This prompt can cost — a wall-clock deadline, caps on repeated tool calls, tool errors and rounds that run nothing, and caps on how many times the provider and the chat ask again — plus the transport timeouts underneath them. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. A single question asked in Visualize This can turn into several calls to the LLM, and a slow model, an unreachable provider or a long tool call can keep one question running far longer than the person who asked it is willing to wait. Six guards bound that. All have a default, and all are overridable. | Guard | What it bounds | Property | Default | | --------------------- | ------------------------------------------------------------------- | ------------------------------------------------------- | ----------------------------- | | Timeout | How long one prompt may run, everything below it included | `atoti.ai.context.prompt-timeout` | 5 minutes | | LLM retries | How many times the provider re-sends one request | Per provider, see below | Per provider | | Chat retries | How many times the chat re-sends the whole prompt | `atoti.ai.context.max-retry-attempts` | 1, the prompt being sent once | | Repeated tool calls | How many times in a row one prompt repeats a tool call verbatim | `atoti.ai.context.max-consecutive-identical-tool-calls` | 3 | | Tool errors | How many tool calls one prompt may see fail before it answers | `atoti.ai.context.max-tool-errors` | 5 | | Rounds without a tool | How many rounds in a row may run no tool at all before the run ends | `atoti.ai.context.max-consecutive-refused-rounds` | 3 | ## The timeout guard `atoti.ai.context.prompt-timeout` bounds a whole prompt, whatever the provider does underneath it. When it expires, the prompt is abandoned, the run reports a timeout, and the partial answer is dropped from the conversation history so the next prompt does not build on an answer nobody saw. ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} atoti: ai: context: prompt-timeout: 5m ``` The deadline is checked wherever a cancellation is: before every tool call, and at every round of the tool-calling loop, before the model is asked again. A model looping over a set of tools is therefore stopped at the next round, whichever tools it chose. It does not interrupt an HTTP request already in flight, so the effective ceiling is the deadline plus one provider call, which the transport timeouts bound. ## The LLM retry guard The provider's own client re-sends a failed request rather than reporting it immediately. It is the right place for that decision: it backs off between attempts, and it does not retry a request it already knows is hopeless, such as an authentication failure or a malformed request. What it is not is uniform: each provider reads a different property, and counts differently. `atoti.ai.max-attempts` is the one to reach for. It is a number of attempts, the first one included, and Atoti translates it into whatever the provider serving the call reads: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} atoti: ai: max-attempts: 5 ``` | Property | Governs | Counts | Default | | ------------------------------ | --------------------- | -------------------------------- | ------- | | `atoti.ai.max-attempts` | every provider | attempts, retries included | 5 | | `spring.ai.openai.max-retries` | OpenAI, Azure Foundry | retries, after the first attempt | 3 | | `spring.ai.retry.max-attempts` | Google GenAI | attempts, retries included | 10 | Declaring `atoti.ai.max-attempts` wins over the `spring.ai.*` counts above, wherever those are declared — `application.yml`, an environment variable, a command-line argument. Leaving it out hands the decision back: a `spring.ai.*` count an application declares then stands, so a deployment already tuned per provider keeps its tuning. With neither declared, the default of 5 attempts applies to every provider, over the 4 of the OpenAI SDK and the 10 of Spring AI. Amazon Bedrock has no `spring.ai.*` count of its own: it retries through the AWS SDK rather than through Spring AI, and the SDK's own default of 3 attempts is out of reach of any property — `AWS_MAX_ATTEMPTS` reaches it, but process-wide. To make that number reachable, Atoti supplies the two Bedrock runtime clients that Spring AI would otherwise build itself, carrying every `spring.ai.bedrock.aws.*` timeout over unchanged. An application that declares a `BedrockRuntimeClient` or `BedrockRuntimeAsyncClient` bean of its own keeps it, and is then responsible for that client's retry policy. So does one that excludes Spring AI's Bedrock auto-configuration: Atoti's clients stand down with it, and the SDK's own default of 3 attempts applies again. Whichever provider is configured, the timeout guard bounds the retries too: they all happen inside one prompt. ### Retrying the whole prompt Above the provider sits the chat's own loop, `atoti.ai.context.max-retry-attempts`. It defaults to 1, so the prompt is sent once and the retrying is left to the provider, which backs off between attempts and does not retry a request it already knows is hopeless — neither of which this loop can do. ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} atoti: ai: context: max-retry-attempts: 1 ``` Raise it only for failures that happen outside the provider call, such as a malformed tool call coming back from the model. Each extra attempt re-sends the whole prompt and re-runs its tools, and every attempt draws on the same tool-error budget described below: an attempt that spent it does not get it back by being run again. ## The no-progress guards Two guards stop a prompt that is getting nowhere, both by answering the model rather than running the tool: it reads why it was stopped and writes the explanation the user sees. ### Repeated tool calls A tool called with the very same arguments, back to back, returns the very same result, so calling it again makes no progress. Past `atoti.ai.context.max-consecutive-identical-tool-calls` times in a row, the call is not run again: the model is told it was just made and returned the same thing, and it does something else instead. ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} atoti: ai: context: max-consecutive-identical-tool-calls: 3 ``` This is what bounds a model stuck on a failing tool. A prompt instructing it to "retry until it works" would otherwise repeat the call until the timeout guard expires, which is hundreds of model calls to reach a conclusion that was already available on the second one. Only a run of identical calls is caught. Any round without that call starts a fresh run, so a tool the model comes back to after doing something else keeps running, however many times. So does the same tool called with different arguments, which is different work. Each call is counted on its own, so a model asking for several tools at once is caught on the one it is stuck on and keeps the rest. That round still runs: only the stuck call is refused, and the others return their results as usual — but it is charged one tool error, so a model that keeps pairing the call it is stuck on with a fresh one is still brought to a stop. ### Tool errors A model varying its arguments every round never repeats itself, so the guard above never sees it. What it does collect is failures. Once `atoti.ai.context.max-tool-errors` tool calls have failed in one prompt, no further tool call is run: the model is told to stop and answer the user with what it has. ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} atoti: ai: context: max-tool-errors: 5 ``` Every failure counts, whether it came from a tool running in Atoti Server or from one running in Atoti UI that the browser answered with an error. A round in which a call was refused counts too, once for the round however many of its calls were refused: a refusal is work the model asked for and did not get. The budget covers the whole prompt, the `max-retry-attempts` retries included. An attempt that spent it does not get it back by being run again. ### The last resort Refusing a call answers the model, which then decides what to do next. A model may simply ask for the same call again. Because each of those rounds is one more call to the model, a run in which `atoti.ai.context.max-consecutive-refused-rounds` rounds in a row ran no tool at all is ended outright, and the user is told the question could not be answered. ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} atoti: ai: context: max-consecutive-refused-rounds: 3 ``` Reaching it means the model ignored that many explanations of why it was getting nowhere; the server log names the tool and the arguments it was stuck on. Any round that ran a tool starts the count over, so this only fires on a model that is doing nothing else. All five `atoti.ai.context` properties above are validated at startup: `prompt-timeout` must not be negative and accepts zero to mean no deadline; `max-retry-attempts`, `max-consecutive-identical-tool-calls`, `max-tool-errors` and `max-consecutive-refused-rounds` must each be at least 1. A value outside those ranges stops the application from starting rather than surfacing on someone's first question. ## Transport timeouts The transport timeouts sit below every guard above, and bound the retries as well as the first attempt. For Amazon Bedrock they are the `spring.ai.bedrock.aws.*` properties, `timeout` above all: it caps the whole call including its retries. See [Set up Amazon Bedrock in Java](./enable-ai-tools/llm/amazon-bedrock-java). For OpenAI it is `spring.ai.openai.timeout`, 60 seconds by default, capping the same call the same way. ## Atoti Python SDK ```python theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} from datetime import timedelta import atoti as tt from atoti_ai import AiConfig, PromptConfig from atoti_ai_amazon_bedrock import ChatConfig, ConnectionConfig ai_config = AiConfig( connection=ConnectionConfig(aws_region="eu-west-3"), chat=ChatConfig(model="eu.anthropic.claude-sonnet-4-6"), max_attempts=5, prompt=PromptConfig( timeout=timedelta(minutes=5), max_retry_attempts=1, max_consecutive_identical_tool_calls=3, max_tool_errors=5, max_consecutive_refused_rounds=3, ), ) session_config = tt.SessionConfig(ai=ai_config) ``` The `atoti.ai.context` guards live in `PromptConfig` because they bound one chat prompt. `AiConfig.max_attempts` sits outside it, next to the connection rather than inside it, because it applies to every call to whichever provider the session connects to. ## Auto-Explain Every `atoti.ai.context` guard above bounds a chat prompt, and only a chat prompt. Auto-Explain calls the LLM directly, without the tool-calling loop those guards sit in, so what bounds it is the provider layer: the LLM retry guard and the transport timeouts. Under Amazon Bedrock, `atoti.ai.max-attempts` needs the chat on the classpath — the `starter-ai-chat` Spring Boot starter, or an Atoti Python SDK session — since that is what brings in Atoti's Bedrock clients. A Java application that declares only `starter-ai-autoexplain` builds none of them, so the AWS SDK's own default of 3 attempts applies there; cap it with `spring.ai.bedrock.aws.timeout` instead, which bounds the whole call including its retries. The other providers read the property wherever it is set. # How to set up the frontend Source: https://docs.activeviam.com/atoti-intelligence/6.2/developer-guide/ui-chat/setup How to add the `@activeviam/ai-extension` to the Atoti UI for Visualize This and Auto-Explain, covering the integrated `extensions.json` approach for Java projects and the standalone `package.json` and `pnpm` build approach. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. This guide explains how to add the AI extension to the Atoti UI to enable AI-powered features. ## What is frontend setup? Frontend setup involves adding the AI extension to the Atoti UI. This extension provides the user interface components for AI features like Visualize This and Auto-Explain. ## Why set up the frontend? Setting up the frontend enables the following capabilities: * Display the AI assistant interface in the Atoti UI * Enable natural language interaction with data * Provide UI components for AI-powered features * Create a seamless user experience for AI features ## Prerequisites Before setting up the frontend, ensure the following requirements are met: * Backend AI features are configured (Visualize This and/or Auto-Explain) ## Setup for integrated frontend Use this approach when the Atoti UI is integrated with the Java application. ### Add the UI dependency Add the Atoti UI dependency to the project. Add the following to `pom.xml`: ```xml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} com.activeviam.atoti-ui atoti-ui ${atoti-ui.version} ``` ```xml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} com.activeviam.springboot atoti-ui-starter ${atoti-server.version} ``` ### Add the AI extension Create an extensions configuration file to enable the AI extension. Create a file at the following location: ``` src/main/resources/static/atoti-ui/extensions.json ``` Add the following content (or add this entry if the file already exists): ```json theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} { "@activeviam/ai-extension": "extensions/@activeviam/ai-extension/extensionEntry.js" } ``` ### Verify the setup After completing the setup, verify that the AI extension is available: 1. Build the project 2. Start the Atoti application 3. Open the Atoti UI in a browser 4. Check that the AI assistant appears in the interface ## Setup for standalone frontend Use this approach when the Atoti UI runs as a separate application without a build zip. ### Create package.json Create a `package.json` file with the following content: ```json theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} { "name": "your-application-name-goes-here", "version": "1.0.0", "private": true, "description": "Your application's description goes here", "author": "Your name", "type": "module", "exports": "./dist/manifest.json", "files": [ "dist" ], "scripts": { "build:extension": "atoti-ui-cli build-extension", "build:application": "atoti-ui-cli build-application --extensions . ./node_modules/@activeviam/ai-extension --env-file env.production.js", "start:extension": "atoti-ui-cli start-extension --port 3001", "start:application": "atoti-ui-cli start-application --port 3000 --extensions http://localhost:3001 --env-file env.development.js", "build": "npm-run-all -s build:extension build:application", "start": "npm-run-all -p start:*" }, "dependencies": { "@activeviam/ai-extension": "^{atoti-ui.version}", "lodash-es": "^4.17.21" }, "devDependencies": { "@activeviam/atoti-ui-cli": "{atoti-ui.version}", "@types/lodash-es": "^4.17.6", "@types/react": "18.3.3", "npm-run-all": "^4.1.5", "typescript": "^5.4.2" }, "peerDependencies": { "@activeviam/atoti-ui-sdk": "{atoti-ui.version}", "antd": "5.6.4", "react": "18.3.1", "react-dom": "18.3.1" }, "engines": { "node": ">=18.12.1" } } ``` Replace `{atoti-ui.version}` with the version of Atoti UI being used. ### Create pnpm-workspace.yaml Create a `pnpm-workspace.yaml` file with the following content: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} overrides: "antd": "5.6.4" ``` ### Install dependencies Install the project dependencies: ```bash theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} npm install ``` ### Build and start Build and start the standalone frontend: ```bash theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} npm run build npm start ``` ### Verify the setup After starting the frontend, verify that the AI extension is available: 1. Open the Atoti UI in a browser (typically at `http://localhost:3000`) 2. Check that the AI assistant appears in the interface ## Troubleshooting If the AI extension does not appear, check the following: * The backend AI features are properly configured * The extensions.json file is in the correct location * The file contains valid JSON * The Atoti UI version is compatible with the AI extension * The browser cache is cleared ## Related reading After setting up the frontend, proceed to use AI features: * [Use Visualize This](../../user-guide/chat) to create visualizations * [Use Auto-Explain](../../user-guide/auto-explain) to analyze data variations # Introduction to Atoti Intelligence Source: https://docs.activeviam.com/atoti-intelligence/6.2/intro/intro Atoti Intelligence lets risk managers, traders, and analysts query live financial data in natural language, with accurate and auditable results that general-purpose AI tools cannot deliver. ## What is Atoti Intelligence? Atoti Intelligence is the agentic layer of the Atoti platform. It sits on top of the Atoti Engine and brings AI capabilities to the platform. This page is intended for users familiar with Atoti applications and analytics concepts. Atoti Intelligence is designed for financial institutions that want to use AI agents to query live data and accelerate investigation and analysis. ## Why use Atoti Intelligence? Risk managers, traders, and analysts spend significant time on complex and repetitive tasks: querying data, investigating exceptions, and building dashboards. General-purpose AI tools cannot perform these tasks reliably on financial data. They lack access to real-time data and do not understand the relationships between complex non-linear metrics. They cannot provide deterministic, auditable outcomes, which are a requirement for risk and regulatory functions. Atoti Intelligence addresses these limitations by grounding AI in the Atoti Engine's semantic layer. Atoti Intelligence sits on top of Atoti Server, adding AI Analytics and Agentic Workflows to the Aggregation Engine and database. Natural language queries are mapped to precise business concepts, with hierarchical understanding of organizational structures and deterministic roll-up and drill-down logic. This eliminates hallucination risk and ensures that AI-powered insights are accurate and auditable. Key benefits include: * **Deterministic outcomes** AI queries are grounded in Atoti's semantic layer, producing precise and auditable results rather than probabilistic responses. * **Real-time data** Agents operate on live, granular data across trading, position, risk, and other systems. Data is never stale. * **IP control and data safety** Atoti Intelligence operates entirely within the firm's environment. Proprietary data, models, and algorithms remain under the firm's control. * **Bring Your Own LLM** Firms can connect their own approved LLM. The platform is not locked to any single provider. * **Open and extensible** Atoti Intelligence connects to existing agents, LLMs, and enterprise AI infrastructure through the Atoti MCP Server, and can use the tools of other MCP servers as its own. ## Who is Atoti Intelligence for? Atoti Intelligence is used by teams that work with Atoti applications and want to interact with data using natural language. Typical users include: * Risk managers and analysts. * Front office traders and desk heads. * Operations and control teams. Common use cases include: * Querying live risk and P\&L data using natural language. * Performing automated root-cause analysis on complex metrics. * Creating dashboards from natural-language prompts. * Integrating Atoti capabilities into a broader firm AI infrastructure. ## How does Atoti Intelligence work? Atoti Intelligence is built on the Atoti Engine's semantic layer. The semantic layer provides the trusted business context that AI agents need to reason correctly on financial data. It maps natural language queries to precise business concepts, with hierarchical understanding of organizational structures and deterministic analytics. Users can access Atoti Intelligence directly from Atoti UI. This allows them to interact with their data using natural language instead of manually building queries and dashboards. Atoti Intelligence includes four components: * **Auto-Explain**: automated root-cause analysis on complex metrics. * **Visualize This**: dashboard creation from natural-language prompts. * **Atoti UI Chat**: a natural-language interface for querying live data. * **Atoti Intelligence Agent and MCP Server**: the agent that connects to the firm's chosen LLM, and the MCP Server that exposes Atoti's semantic layer, data, and tools so they are discoverable by AI agents, and that connects out to other MCP servers to use their tools as Atoti's own. ## What is the relationship to other Atoti products? Atoti Intelligence is part of the Atoti platform. It is not a standalone product. It sits on top of the Atoti Engine and requires an existing Atoti application. # How to connect AI to an Atoti cube Source: https://docs.activeviam.com/atoti-intelligence/6.2/intro/intro-LLM-and-MCP Atoti Intelligence connects AI in two directions: connect an LLM to Atoti via Spring AI for use from Atoti UI, or connect Atoti to any MCP-compatible third-party application via the Atoti MCP Server. Atoti Intelligence does not bundle an LLM. How AI connects depends on where users work, and the two paths differ in what the client provides. * **From Atoti UI — connect an LLM to Atoti.** The client brings an LLM and connects it to Atoti Server via Spring AI. Any Spring AI provider works. Atoti Server is the application: it hosts the agent, runs the agent loop on the Spring AI Chat Client, executes native Atoti tools against the cube, and enforces role-based security. * **From a third-party application — connect Atoti to that application.** The client does not connect an LLM to Atoti. Instead, Atoti Server exposes an MCP server, built with Spring AI, that plugs into any MCP-compatible application (Claude, ChatGPT, and others). The third-party application brings its own LLM and agent, runs the agent loop, and calls Atoti tools through the MCP server. Atoti Server runs each tool request against the cube under the user's security context. This page assumes familiarity with Atoti Server, Atoti UI, and the in-memory cube. ## Why does Atoti Intelligence need an LLM? Atoti Intelligence does not include its own internal large language model (LLM). Clients connect an LLM of their choice instead. This approach provides: * No vendor lock-in * Flexibility to run on-premises, in the cloud, or with a custom LLM * Full control over data privacy and model selection An LLM enables Atoti Intelligence to: * Analyze data and generate clear explanations * Understand user queries in natural language * Create visualizations based on context * Provide conversational assistance ## What are the two ways to connect an LLM to an Atoti cube? Atoti Intelligence connects to an LLM in one of two ways. The choice depends on where Atoti Intelligence is used. 1. Atoti UI is used to interact with Atoti Intelligence. The user's prompt is sent from Atoti UI. 2. A third-party application (Claude, ChatGPT, etc.) is used to interact with Atoti Intelligence. The user's prompt is sent from the third-party application's UI. Keep in mind that Auto-Explain and Visualize This can only be used from inside an Atoti UI dashboard. They are not available when interacting with Atoti from a third-party application. ### What are the building blocks of an LLM application? An LLM application is built from a small set of elements. Each element has one role. * **LLM**: The reasoning engine. It takes a question in plain text and returns an answer in plain text. It holds no memory between calls. * **System prompt**: A message that gives the LLM context, examples, and guidance for handling different user queries. * **Tools**: Actions the model can take to retrieve more data. Examples include querying a cube, calling a system, or running a calculation. * **RAG**: Retrieval-Augmented Generation. Documents and data fetched from external sources to inform the answer. * **Skill**: A focused, reusable capability. It pairs an instruction with the action that carries it out. It is composed of system prompts and tools. * **Agent**: An LLM running in a loop. It reacts to prompts. At each step it decides whether to answer, fetch data through RAG, call a tool, or use a skill. The loop continues until the task is complete. * **Application**: The layer that brings everything together. It wraps one or more agents in an interface and orchestrates each request end to end. * **Application UI**: The part of the application where a user interacts with agents through prompts. LLM-application.png The structure of an LLM application ## How does an LLM connect to an Atoti cube? The sections below cover each paths in full: how the integration is structured, and how a prompt becomes an answer. Visualize This can only be used from inside an Atoti UI dashboard. This is not available when interacting with Atoti from a third-party application. In both paths, the cube runs every query under the user's own profile. The difference is which system handles authentication and token passing. ### Prompts from Atoti UI When Atoti UI is used for prompts, Atoti Server is the application. Atoti Server hosts the agent and runs the agent loop on the Spring AI Chat Client. It executes native Atoti tools, including discovery, cube query, drillthrough, and filter, against the cube. It enforces role-based security on every query. The LLM is external to Atoti Server: it receives text and returns tool calls or a final answer. Atoti UI is the application UI. Atoti UI Chat is the conversational entry into the cube. The analyst prompts in natural language. from-atoti-ui.png What happens when the analyst prompts Atoti Intelligence from Atoti UI #### How a prompt becomes an answer from Atoti UI This sequence describes the request loop when the analyst uses Atoti UI. Atoti Server runs the agent loop on the Spring AI Chat Client and authenticates the user. The Atoti cube provides the in-memory OLAP data. The LLM is reached through an external completion API. 1. The analyst, logged in with a user ID, sends a prompt and a conversation ID to Atoti Server. 2. Atoti Server authenticates the user and resolves identity and roles. 3. Atoti Server sends the prompt, the tool list, and the LLM token to the LLM. 4. The LLM receives the request and responds by asking to call a tool. 5. Atoti Server receives the call to use a tool for the user's profile. 6. Atoti Server sends the tool request and the user's security context to the cube. 7. The cube runs the query with the user's profile. 8. The cube sends data filtered for the user back to Atoti Server. 9. Atoti Server sends the filtered data and the LLM token to the LLM. 10. The LLM receives the filtered data and generates the final response. 11. The LLM sends the final response to Atoti Server. 12. Atoti Server streams the response to the UI as a reply. prompt-atoti-ui.png #### Which LLM providers are supported? Atoti Intelligence works with any LLM supported by Spring AI. Configuration guides are provided for: * Amazon Bedrock * OpenAI ### Prompts from a third-party application When the third-party application is used for prompts, it hosts the agents. The agents orchestrate the loop and run the Atoti tools against an Atoti cube. The Atoti Model Context Protocol (MCP) Server bridges the third-party application and the Atoti data model. It is a lightweight service that exposes Atoti's analytical capabilities to external LLMs. The third-party application acts as an MCP client and connects to the Atoti MCP Server endpoint. The Atoti MCP Server provides: * Exposure of Atoti tools to LLM clients such as Claude * Dynamic interaction with Atoti cubes, hierarchies, and measures * Custom extensions for business-specific logic * A standardized, vendor-agnostic integration protocol Atoti Server uses native Atoti tools to run every query in the user's own security context. The third-party application provides the UI and the conversational entry into the cube. The agent has access to an LLM, RAG, and tools such as search and write. #### How a prompt becomes an answer from a third-party application This sequence describes the request loop when the analyst uses a third-party application. The third-party application runs the agent loop. The Atoti MCP Server and cube run each query. The LLM is reached through an external completion API. The third-party application authenticates the user, holds the Atoti token, and passes it to the Atoti MCP Server with each tool request. 1. The analyst, logged in with a user ID, sends a prompt to the third-party application. 2. The third-party application sends the prompt, the tool list, and the LLM token to the LLM. 3. The LLM receives the request and responds by asking to call the Atoti tool. 4. The third-party application receives the call to use the tool, along with the Atoti token. 5. The third-party application sends the tool request and the user's Atoti token to the Atoti MCP Server. 6. Atoti Server receives the tool request and runs the query against the cube with the user's profile. 7. Atoti Server sends data filtered for the user back to the third-party application. 8. The third-party application sends the filtered data and the LLM token to the LLM. 9. The LLM receives the filtered data and generates the final response. 10. The LLM sends the final response to the third-party application. 11. The third-party application streams the response to the UI as a reply. prompt-from-application.png ## Can Atoti use the tools of other MCP servers? Both directions above have Atoti Server answering an MCP client. Atoti Server can also be the MCP client: it connects out to other MCP servers — typically the other Atoti Servers of the same deployment, each exposing its own cube — and uses their tools as its own. Those tools are then offered wherever Atoti's own tools are, in Atoti UI chat and on Atoti's own MCP endpoint. Every call runs under the identity of the user who triggered it, so the other cube's role-based restrictions stay in force. This is how one Atoti Server answers a question spanning several cubes, and how a third-party application reaches the whole deployment's tools through a single endpoint. ## Next steps and related reading * [Connect an LLM to prompt from Atoti UI](../developer-guide/enable-ai-tools/configure-and-start/set-up-an-llm) * [Connect a third-party application to prompt Atoti](../developer-guide/mcp-server/introduction) * [How connecting to other MCP Servers works](../developer-guide/mcp-server/connect-to-other-servers/how-it-works) # Atoti Intelligence tools Source: https://docs.activeviam.com/atoti-intelligence/6.2/intro/tools What Auto-Explain and Visualize This do in Atoti Intelligence, including automated root-cause analysis of metric variations, natural language visualization creation, and cube structure querying via an integrated LLM assistant. Atoti Intelligence introduces two in‑built AI tools, Auto‑Explain and Visualize This. They are designed to work directly within Atoti UI. Users can interact with their data using natural language, generate insights instantly, and understand what is driving changes in their metrics. ## What is Auto-Explain? Auto‑Explain is a feature that automatically analyzes variations in data and identifies the root causes behind them. When a metric changes between two points (across dates, categories, products, or any other dimension) Auto‑Explain breaks down the shift to show which underlying factors contributed most. It operates directly in Atoti UI, allowing users to launch explanations as soon as they notice an unusual movement in a chart, KPI, or table. This supports fast, in‑context exploration without interrupting the analysis flow. ### Why use Auto-Explain? Auto‑Explain helps users understand their data faster by: * Reduces the time spent investigating unexpected metric changes * Identifies the dimensions that drive variations are automatically * Provides clear, easy‑to‑interpret explanations * Works seamlessly with the existing Atoti data model It is especially valuable for analysts who need quick clarity on performance drivers in complex, multidimensional datasets. ## What is Visualize This? Visualize This is an AI‑assisted visualization feature that lets users generate charts, dashboards, and insights through natural language. By interacting with an integrated AI assistant inside the Atoti UI, users can ask for visualizations conversationally, without having to configure chart settings manually. The AI assistant is supported by Atoti‑specific tools that understand the platform's data structures. This means it generates visualizations that are accurate, meaningful, and aligned with the dataset. ### Why use Visualize This? Visualize This is powered by a large language model with access to Atoti-specific tools. This combination makes it useful in three ways: * **Data visualization**: Create charts, dashboards, and multi-widget pages from natural language requests, without manually configuring widgets. The assistant selects appropriate visualization types and maps your data to them. * **Cube knowledge**: Ask questions about your cube structure — available measures, hierarchies, dimensions — and get answers drawn from the Atoti context provided to the assistant. * **General-purpose assistance**: Because the assistant is backed by an LLM, it can also handle any question you would ask a conversational AI, from explaining a concept to writing a cookie recipe. # Changelog Source: https://docs.activeviam.com/atoti-intelligence/6.2/releases-and-upgrades/changelog For details about versioning, see our [Versioning Policy](https://docs.activeviam.com/atoti-eos.html). ## 6.2.1 2026-09-03 ### Added * PIVOT-14244 Chat: An application can now serve no chat, with `atoti.ai.chat.enabled=false`. No chat endpoint is registered, so `/versions` stops advertising the `activeviam/ai/chat` namespace and the Atoti UI reports chat as absent. This differs from configuring no LLM, which keeps the namespace advertised and answers 404 on each call. Auto-Explain and the MCP server are unaffected. See [Configure Visualize This](../developer-guide/enable-ai-tools/visualize-this/configuration#how-to-turn-visualize-this-off). * PIVOT-14439 Chat: Dynamic tool discovery can now be turned off with `spring.ai.chat.client.tool-search-advisor.enabled=false`, which sends the whole tool set to the model on every request instead. It stays enabled by default under the Atoti Intelligence Essentials license, and stays off without that license. The advisor is now auto-configured by Spring AI's `spring-ai-starter-tool-search-advisor`, so its other settings (the index backend, the result limit, and session eviction) are configurable under the same `spring.ai.chat.client.tool-search-advisor` prefix. See [Configure Visualize This](../developer-guide/enable-ai-tools/visualize-this/configuration#dynamic-tool-discovery). * PIVOT-14244 Atoti Intelligence: Chat and Auto-Explain each have their own REST namespace, so the two features version independently: `activeviam/ai/chat` serving `/activeviam/ai/chat/rest/v1`, and `activeviam/ai/autoexplain` serving `/activeviam/ai/autoexplain/rest/v1`. Both namespaces are advertised on the `/versions` endpoint. The payloads are unchanged from the endpoints they replace. See the [migration notes](./migration-notes#chat-and-auto-explain-rest-namespaces). * PIVOT-14244 MCP server: An Atoti Server instance can now connect out to other MCP servers, typically the other Atoti Server instances of the same deployment, and use their tools as its own, both in chat and on its own MCP endpoint. A connection is declared under `spring.ai.mcp.client.streamable-http.connections.`, whose new Atoti `authentication` key selects how it authenticates as the calling user. This requires the Atoti Intelligence Extension tier. See the [migration notes](./migration-notes#connecting-to-other-mcp-servers). * PIVOT-14244 Atoti Python SDK: Added the `AiConfig.mcp` attribute, using `McpClientConfig`, to take the tools of other MCP servers, either `StreamableHttpMcpServerConfig` over HTTP or `StdioMcpServerConfig` as a local process. See [Connect to other MCP servers in Python](../developer-guide/mcp-server/connect-to-other-servers/setup-python). * PIVOT-14121 Chat: The assistant can now display the interactive Auto-Explain page of an analysis it ran, on top of the summary it already returned. This requires Atoti UI 5.2.28 or higher. See [Configure Auto-Explain](../developer-guide/enable-ai-tools/auto-explain/configuration#how-to-keep-analyses-retrievable-from-the-chat). * PIVOT-14121 Chat: An Auto-Explain analysis that has already run can now be listed, displayed again, or dropped from the chat, instead of being run a second time. How many analyses stay retrievable, and for how long, are set with `atoti.ai.autoexplain.results.maximum-size` and `atoti.ai.autoexplain.results.time-to-live`. See [Configure Auto-Explain](../developer-guide/enable-ai-tools/auto-explain/configuration#how-to-keep-analyses-retrievable-from-the-chat). * PIVOT-14121 Atoti Python SDK: Added the `AutoExplainConfig` class, passed to `AiConfig.auto_explain`, setting how many Auto-Explain analyses stay retrievable from the chat, and for how long. See [Configure Auto-Explain](../developer-guide/enable-ai-tools/auto-explain/configuration#how-to-keep-analyses-retrievable-from-the-chat). * PIVOT-14839 Atoti Intelligence: Added a guard on how many times the LLM provider re-sends a request, `atoti.ai.max-attempts`: one property for every provider, counting attempts with the first one included, defaulting to 5. Declaring it overrides the per-provider counts Spring AI exposes, `spring.ai.openai.max-retries` and `spring.ai.retry.max-attempts`, wherever those are declared; leaving it out lets them stand. See [Retries and timeouts](../developer-guide/retries-and-timeouts#the-llm-retry-guard). * PIVOT-14839 Chat: Added a timeout guard on the whole prompt, `atoti.ai.context.prompt-timeout`, covering every tool call and every provider retry underneath it. It defaults to 5 minutes; when it expires the prompt is abandoned, the run reports a timeout, and the partial answer is dropped from the conversation history. The deadline is now checked wherever a cancellation is, including at every round of the tool-calling loop, so a model looping over a set of tools is stopped at the next round whichever tools it chose. See [Retries and timeouts](../developer-guide/retries-and-timeouts#the-timeout-guard). * PIVOT-14839 Chat: Added a guard on repeated tool calls, `atoti.ai.context.max-consecutive-identical-tool-calls`. Past 3 rounds in a row asking for the same tool with the very same arguments, the call is no longer run: the model is told it was just made and returned the same result, and does something else instead. Round after round, an identical call makes no progress, and a prompt instructing the model to retry until it works previously repeated it for as long as the model kept asking, nothing in the tool-calling loop being able to stop it. Each call is counted on its own, so a round asking for several tools loses only the one the model is stuck on and still runs the others, though it is charged one tool error for the refusal; any round without that call starts a fresh run. See [Retries and timeouts](../developer-guide/retries-and-timeouts#repeated-tool-calls). * PIVOT-14839 Chat: Added a guard on failing tool calls, `atoti.ai.context.max-tool-errors`. Once 5 tool calls have failed in one prompt, retries included, no further tool call is run: the model is told to stop and answer the user with what it has. Every failure counts, whether the tool ran in Atoti Server or in Atoti UI, and so does a round in which a call was refused, once for the round however many of its calls were refused. See [Retries and timeouts](../developer-guide/retries-and-timeouts#tool-errors). * PIVOT-14839 Chat: Added a guard on rounds that run no tool at all, `atoti.ai.context.max-consecutive-refused-rounds`. Once 3 rounds in a row have run nothing, the run ends and the user is told the question could not be answered; any round that runs a tool starts the count over. Refusing a call answers the model, which may ask for it again, and Spring AI's tool-calling loop has no iteration cap of its own, so nothing but the prompt deadline used to stop a model that would not take the refusal. See [Retries and timeouts](../developer-guide/retries-and-timeouts#the-last-resort). * PIVOT-14839 Chat: The five `atoti.ai.context` guard properties, and `atoti.ai.max-attempts`, are validated at startup, so a value no prompt could work within stops the application from starting instead of surfacing on someone's first question. * PIVOT-14839 Atoti Python SDK: Added the `PromptConfig` class, passed to `AiConfig.prompt`, bounding what one chat prompt may spend, and the `AiConfig.max_attempts` attribute, bounding the calls to the LLM provider. ### Changed * PIVOT-14439 Chat: An application that declares its own `ToolCallingAdvisor.Builder` bean now takes precedence over Atoti's tool-search advisor. Previously Atoti's advisor won and the application's bean was ignored. * PIVOT-14547 Chat: The tools of the assistant now return their result directly, instead of wrapping it in an internal envelope that also carried an unused message for the model. The tool results streamed to Atoti UI and sent to the model are unchanged. * PIVOT-14839 Chat: A client that stops listening now aborts the prompt running behind it, instead of the whole prompt being run again, tools included, with nobody left to read the answer. ### Deprecated * PIVOT-14244 MCP server: The server-sent events transport is deprecated, following Spring AI 2.0.0, which deprecates it for removal in favor of Streamable HTTP. Use `POST /mcp` everywhere: it is what the starter configures by default, and what an MCP client expects. Connecting out to another MCP server, and reporting the tools of connected servers, both require Streamable HTTP. See [MCP transport](../developer-guide/mcp-server/setup/configure-oauth2-self-issued#which-mcp-transport-does-self-issued-mode-use). * PIVOT-14244 Atoti Intelligence: The `activeviam/ai` namespace, which served both chat and Auto-Explain, is deprecated in favor of the `activeviam/ai/chat` and `activeviam/ai/autoexplain` namespaces. `/activeviam/ai/rest/v2/chat` and `/activeviam/ai/rest/v2/autoexplain` keep answering exactly as before, and the namespace stays advertised on `/versions`, so existing applications and Atoti UI need no change. Both addresses are served by the same instances, so a conversation started on one is visible from the other. They will be removed in a future major release. ### Fixed * PIVOT-14402 Atoti Intelligence: A license that does not enable the AI components is now reported at startup. When an Atoti AI module is on the classpath but the license misses the `ai-essentials` component, a warning explains that the `/activeviam/ai` REST service is not registered, which previously surfaced only in Atoti UI as "Unable to find the AI service on any of the servers". The `ai-extension` component is reported the same way when the MCP server starter is present. * PIVOT-14292 MCP server: A license without the Atoti Intelligence Extension tier now keeps the MCP server off even when the application sets `spring.ai.mcp.server.enabled=true`. The tier check is applied at the highest property precedence, so it can no longer be overridden from `application.yml`, an environment variable or a command-line argument. A license enabling `ai-extension` without `ai-essentials` no longer starts the MCP server either, as the Extension tier builds on Essentials. * PIVOT-14310 Chat: AG-UI streaming responses now carry `X-Accel-Buffering: no` and `Cache-Control: no-cache, no-transform` so that reverse proxies do not buffer or compress the event stream. A buffering proxy delivered the tool-call events to the browser only at the end of the run, so client tools always hit the server-side timeout. Client tool timeouts, stale tool results and retried chat prompts are now logged. See [Monitoring](../developer-guide/monitoring#reverse-proxy-buffering). ### Security * PIVOT-14752 Security: Upgraded Spring AI to 2.0.1 to fix CVE-2026-59279 in `org.springframework.ai:mcp-spring-webmvc`. * PIVOT-14752 Security: Pinned `io.modelcontextprotocol.sdk:mcp-bom` to 2.0.1 to fix the unbounded request-body denial of service in `mcp-core` that the MCP server starter reaches through Spring AI. Spring AI 2.0.1 still declares `mcp-core` 2.0.0, so the Spring AI upgrade alone does not fix it. ## 6.2.0 2026-07-27 ### Added * PIVOT-14139 The Atoti chat now uses dynamic tool discovery: instead of sending all available tools on every request, the model searches a Lucene keyword index for matching tools and receives only those results, reducing prompt token usage and improving tool selection. * PIVOT-14220 Cube: Added a `Dimension` API in the Atoti Java SDK to configure which cube attributes are exposed to the AI tools. * PIVOT-14122 Atoti Python SDK: Added `Session.chat` to open a chat session against a cube. * PYTHON-922 Auto-Explain: Added a Python API. See [How to set up Auto-Explain in Python](../developer-guide/enable-ai-tools/auto-explain/setup-python). * PIVOT-14426 Atoti Python SDK: Added the `AiConfig.disclaimer` attribute to configure the disclaimer shown with AI responses. See [How to set up a disclaimer in Python](../developer-guide/enable-ai-tools/disclaimer/setup-python). * PIVOT-13970 MCP server: Added OAuth 2.1 support, with an authorization-server discovery mode and a self-issued authorization-server mode. See [Configure OAuth 2.1 discovery](../developer-guide/mcp-server/setup/configure-oauth2-discovery) and [Configure self-issued OAuth 2.1](../developer-guide/mcp-server/setup/configure-oauth2-self-issued). ### Changed * PIVOT-14286 Chat: Improved the system prompt to help the LLM navigate the UI. * PYTHON-859 Auto-Explain: Root-cause analysis (root-cause members, contribution percentages, and contribution tables) no longer requires an LLM and is always available without an AI provider configured. An LLM is now only required for the optional AI summary. When no LLM is configured, the AI summary is unavailable. See[Set up Auto-Explain in Java](../developer-guide/enable-ai-tools/auto-explain/setup-java) or [in Python](../developer-guide/enable-ai-tools/auto-explain/setup-python). * PIVOT-13680 Moved the cube context configuration from the `atoti.ai` prefix to `atoti.ai.context`. Update your `application.yaml` accordingly. See [How to configure Visualize This](../developer-guide/enable-ai-tools/visualize-this/configuration) for the updated configuration format. * PIVOT-14227 Chat: Improved error handling in the tool-calling flow. * PIVOT-14236 Chat: Fixed filters being added without their members. Member validation now resolves members by their full name path, so the assistant reliably finds them in the cube. ### Fixed * PIVOT-007 MCP server: Fixed the credentials page failing to load when the application runs under a custom context path. # Compatibility Source: https://docs.activeviam.com/atoti-intelligence/6.2/releases-and-upgrades/compatibility This page lists the requirements for using Atoti Intelligence features. ## Requirements All AI features require the following components: * Atoti Server version 6.2.0 or higher * Java project (Python support coming soon) * License with AI flag enabled * Spring AI version 2.0.1 * Atoti UI version 5.2.24 or higher (for features with UI components) Some features need a more recent Atoti UI than the version above: | Feature | Minimum Atoti UI version | | -------------------------------------------------------------------- | ------------------------ | | Asking the chat for the interactive page of an Auto-Explain analysis | 5.2.28 | A chat served to an earlier Atoti UI never offers that page, and answers with the Auto-Explain summary alone. See [How to keep analyses retrievable from the chat](../developer-guide/enable-ai-tools/auto-explain/configuration#how-to-keep-analyses-retrievable-from-the-chat). For information on which LLMs have been validated, see [LLMs Performance Reference](./llms_performance_reference). ## LLM providers ### Atoti Java SDK Atoti Intelligence uses Spring AI to connect to LLM providers. Spring AI supports multiple providers through a consistent configuration interface. See the [Spring AI documentation](https://docs.spring.io/spring-ai/reference/api/chat/comparison.html) for more information. # Migration notes Source: https://docs.activeviam.com/atoti-intelligence/6.2/releases-and-upgrades/migration-notes What to change in your application when upgrading Atoti Intelligence from one version to the next. For a detailed list of all changes, see the [Changelog](./changelog). For details about versioning, see our [Versioning Policy](https://docs.activeviam.com/atoti-eos.html). ## 6.2.1 \{@today: -} ### Chat and Auto-Explain REST namespaces Chat and Auto-Explain each have their own REST namespace, so the two features version independently: | Feature | Address | Namespace on `/versions` | | ------------ | ------------------------------------ | --------------------------- | | Chat | `/activeviam/ai/chat/rest/v1` | `activeviam/ai/chat` | | Auto-Explain | `/activeviam/ai/autoexplain/rest/v1` | `activeviam/ai/autoexplain` | No action is required to upgrade. The addresses these replace — `/activeviam/ai/rest/v2/chat` and `/activeviam/ai/rest/v2/autoexplain` — keep answering with the same payloads, and the `activeviam/ai` namespace stays advertised on `/versions`, which is how Atoti UI and the Atoti Python SDK detect that Atoti Intelligence is available. Both addresses are served by the same instances, so a conversation started on one is visible from the other and you can migrate one caller at a time. The new addresses are versioned from `v1` because their namespaces are new; the payloads are those the old addresses served as `v2`. The old addresses are deprecated and will be removed in a future major release, so move your own callers to the new ones when convenient. If you secured the AI endpoints with your own filter chain rather than the built-in one, extend its matcher to cover `/activeviam/ai/chat/rest/**` and `/activeviam/ai/autoexplain/rest/**`. ### Connecting to other MCP servers Atoti Server can now connect out to other MCP servers, typically the other Atoti Server instances of the same deployment, and use their tools as its own, both in chat and on its own MCP endpoint. An application that declares no connection is unaffected. A connection is declared under Spring AI's own `spring.ai.mcp.client.streamable-http.connections` prefix, and `authentication` is the only key Atoti adds to it. That key selects how this server identifies itself to the remote one: `none`, the default, sends no credential, `atoti-jwt` mints a token for the calling user, and `pass-through` forwards the token that user presented. Every mode but `none` derives its credential from the calling user's security context, so a remote tool runs under the identity of whoever triggered it and the remote cube's role-based data restrictions stay in force. A new `getConnectedServers` chat tool reports which servers can answer: first the one the chat is running on, marked `current: true` and addressed up to its context path, then each connected server with its address, its tool prefix, and whether the calling user can reach it. It is registered for chat only, never as a `ToolCallbackProvider` bean, since it puts the deployment's internal addresses into the prompt, from where they reach the model provider and any user who can chat. Two points to settle before declaring a connection. Write `atoti-jwt` only for a server of the same deployment, since the token it mints is accepted by every server sharing the deployment's signing key. And declare the connection under `streamable-http`, the only outbound transport supported: one declared under `spring.ai.mcp.client.sse.connections` is reported at startup as unsupported, carries no credential whatever `authentication` says, and is absent from `getConnectedServers`. The connected servers' tools are also reported on this server's own MCP endpoint, per calling client. Nothing has to be enabled and no service account is needed: an MCP client authenticates to this server before it can ask for tools, so Atoti lists each connected server with that user's own credential. Spring AI's `spring.ai.mcp.server.expose-mcp-client-tools` is a different, fixed-list mechanism and is not needed; leave it unset. This applies to the Streamable HTTP transport, which is the default. This capability requires the Atoti Intelligence Extension tier. See [How connecting to other MCP Servers works](../developer-guide/mcp-server/connect-to-other-servers/how-it-works) for the authentication modes in full, remote tool naming, `getConnectedServers`, how the remote tools reach this server's own MCP endpoint, and what an unreachable remote server costs. ### Spring AI MCP client defaults Two Spring AI defaults change for applications that already declare MCP client connections. Atoti contributes these defaults at the lowest precedence, so a property already set by the application still wins. * `spring.ai.mcp.client.initialized` now defaults to `false` instead of Spring AI's `true`. With the previous default, Spring AI performed the MCP initialize handshake with every declared server while the application context was being built, before any user had authenticated. Against a secured remote server this failed with a 401 error and took startup down with it; against an unsecured one it opened a session belonging to nobody. Connections are now established lazily on first use, which happens while serving a user's request, so the handshake carries that user's credential like every later request of the session. * `spring.ai.mcp.client.toolcallback.enabled` now defaults to `false`, handing tool listing to an Atoti provider that lists each server separately. Spring AI's stock provider lists all servers in a single stream, so one unreachable peer aborts the whole listing, and with `expose-mcp-client-tools` enabled, that listing happens at startup and would stop the server from booting. A peer is a remote dependency, not a prerequisite: failures are not cached, so a server that was down is retried on the next request. Successful listings are cached per calling identity rather than once for the whole application, so one user's list is never served to another. Setting the property back to `true` restores Spring AI's provider and gives up all three of those guarantees; Atoti logs a warning naming them at startup when you do. `starter-ai-mcp-server` now also pulls in `org.springframework.ai:spring-ai-starter-mcp-client` (the JDK `HttpClient` variant, matching the servlet stack) as a mandatory dependency. # Release notes Source: https://docs.activeviam.com/atoti-intelligence/6.2/releases-and-upgrades/release-notes For a detailed list of all changes, see the [Changelog](./changelog). For details about versioning, see our [Versioning Policy](https://docs.activeviam.com/atoti-eos.html). ## 6.2.1 2026-09-03 ### New Features * The Atoti MCP Server can now connect to other MCP servers, typically other Atoti Server instances in the same deployment. It can then use their tools in chat and through its own MCP endpoint. This requires the Atoti Intelligence Extension tier. * Applications can now turn off chat entirely with a single configuration property. Atoti UI then reports chat as absent. This differs from running without an LLM, where the chat endpoint stays advertised but every call fails. See [Configure Visualize This](../developer-guide/enable-ai-tools/visualize-this/configuration#how-to-turn-visualize-this-off). * The chat assistant can now display the interactive Auto-Explain page for an analysis it just ran, directly in the conversation. This requires Atoti UI 5.2.28 or higher. * Chat and Auto-Explain now each have a dedicated REST namespace, so the two features can be updated and versioned independently. See the [migration notes](./migration-notes#chat-and-auto-explain-rest-namespaces). * Administrators can now set limits on how long a chat prompt may run, and on retries, repeated tool calls, tool errors, and rounds with no tool call. These limits keep AI runs bounded and predictable, stopping a model that would otherwise loop without making progress. See [Retries and timeouts](../developer-guide/retries-and-timeouts). ### Improvements * Dynamic tool discovery, introduced in 6.2.0, can now be turned off, sending the full tool set to the model on every request instead. * A completed Auto-Explain analysis can now be listed, displayed again, or removed from the chat, instead of being run a second time. * Closing or canceling a chat request now stops the underlying work immediately, instead of letting it keep running unread. * A license missing the required AI components is now reported clearly at startup, instead of surfacing later as a generic error in Atoti UI. * The MCP server now stays disabled when the license lacks the required tier, even if the application tries to enable it through configuration. * Chat responses streamed through a reverse proxy no longer stall. New response headers stop the proxy from buffering or compressing the event stream. ## 6.2.0 2026-07-27 ### New Features * The Atoti chat now uses dynamic tool discovery. Instead of sending every available tool with each request, the model searches a keyword index for matches. This reduces token usage and improves tool selection. * The Atoti Java SDK now includes a `Dimension` API to control which cube attributes are exposed to the AI tools. * Auto-Explain, which identifies the root causes behind measure variations, now has a Python API in the Atoti Python SDK. See [How to set up Auto-Explain in Python](../developer-guide/enable-ai-tools/auto-explain/setup-python). * The Atoti Python SDK now offers `Session.chat` to start a chat session against a cube. * The Atoti Python SDK now exposes the `AiConfig.disclaimer` attribute, letting the disclaimer shown with AI responses be customized. See [How to set up a custom disclaimer in Python](../developer-guide/enable-ai-tools/disclaimer/setup-python). ### Improvements * The chat system prompt was improved to help the LLM navigate the UI. * Fixed the Atoti MCP Server credentials page, which failed to load when the application ran under a custom context path. # Auto-Explain user guide Source: https://docs.activeviam.com/atoti-intelligence/6.2/user-guide/auto-explain How to access and use Auto-Explain in Atoti UI to identify the root causes of metric changes, covering pivot table cell selection, context menu access, result interpretation, and contribution percentage output. Auto-Explain is a feature that automatically analyzes data variations and identifies root causes. It examines the underlying data structure to determine which factors contributed to a metric change between two data points. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. ## What is Auto-Explain Auto-Explain analyzes data to identify the root causes of variations. When a metric changes between two data points, Auto-Explain examines the underlying data structure to determine which factors contributed to the change. Auto-Explain produces two kinds of output: * **Root-cause analysis**: the root cause members, their contribution percentages, and the contribution tables. This is produced by a deterministic algorithm and does not require an LLM. * **AI summary**: an optional natural-language summary of the results. This requires an LLM to be configured. When no LLM is configured, requesting an AI summary returns a message indicating the AI summary is unavailable instead of a generated summary. ## Why use Auto-Explain Auto-Explain reduces the time spent investigating data variations manually. Key benefits include: * Identify root causes automatically * Get clear explanations of metric changes * Work with existing Atoti data models * Focus analysis on relevant dimensions through configuration ## Where to find Auto-Explain Auto-Explain is available in the context menu of pivot tables in the Atoti UI after successful setup. To access it, right-click on a selected cell in a pivot table and select **Auto-Explain** from the context menu: Auto-Explain context menu ## How to use Auto-Explain ### Prerequisites Before using Auto-Explain, ensure the following requirements are met: * Auto-Explain is set up in the project * The Atoti application is running * The Atoti UI is accessible * A pivot table with data is available ### Analyze a variation Follow these steps to analyze a variation between two cells: 1. Open a pivot table in the Atoti UI 2. Select two cells to compare 3. Right-click one of the selected cells 4. Select **Auto-Explain** from the context menu 5. Wait for the analysis to complete Auto-Explain analyzes the variation and displays the results: Auto-Explain results ### Interpret the results The Auto-Explain results always include: * Root cause members that contribute to the variation * Contribution percentages for each factor * Hierarchy levels where variations occur If an LLM is configured and the analysis was requested with AI summary enabled, an additional natural-language summary of the results appears below the contribution data. The AI disclaimer is displayed alongside the summary. If an AI summary is requested but no LLM is configured, a message indicating the AI summary is unavailable appears instead of a generated summary. ## Related reading * [Set up Auto-Explain](../developer-guide/enable-ai-tools/configure-and-start/set-up-auto-explain) to add the feature to a project and customize its behavior # What Auto-Explain can analyze Source: https://docs.activeviam.com/atoti-intelligence/6.2/user-guide/auto-explain-scope The scope of a single Auto-Explain analysis: what one run compares, the requirements a measure and starting cell must meet to succeed, and how the drill-down search prioritizes hierarchies. Auto-Explain analyzes data variations and identifies root causes. This page describes what a single analysis can currently handle, so an analysis can be set up to succeed on the first attempt. It assumes familiarity with the [Auto-Explain user guide](./auto-explain). ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. ## What does a single analysis cover? Each Auto-Explain run is scoped to one focused comparison: * Compares one measure between two specific members (for example, two dates) on a single comparison level * Explains one measure at a time; comparing several measures requires several separate runs * Requires the two compared cells to be identical except for the level being compared (for example, the date) * Uses individual cells, not ranges of dates or values * Stays within a single cube; a cause in a different cube is out of scope for the run * Context values (settings that affect how a query is computed, such as a currency conversion) can be included in the comparison, alongside the cube's regular hierarchies * Searches the cube's regular hierarchies only, not virtual hierarchies (lightweight hierarchies whose members are not stored in the cube) ## What does an Auto-Explain run require to succeed? An analysis needs a complete, valid starting point: * The measure is numeric and has a value at both compared cells * The measure and the cube exist and are valid * The measure works with common aggregations, such as SUM, COUNT, AVERAGE, and MULTIPLY. Percentile and median measures are not yet supported ## How does Auto-Explain search for causes? Auto-Explain drills down automatically through the cube's regular hierarchies to find the members that are most likely to explain a variation. A few behaviors shape how that search proceeds: * Hierarchies are ranked by their number of members at each step, and only a limited number of the smallest ones are explored. A very large hierarchy that holds the true driver can occasionally be skipped as a result. Apply filters to narrow the search if this seems to be happening. * Whoever sets up Auto-Explain for the project can narrow or exclude specific hierarchies from the search, to focus the analysis on relevant dimensions * Virtual hierarchies (lightweight hierarchies whose members are not stored in the cube) are never explored * Sometimes, the search encounters a hierarchy that is correlated with the variation but is not the true cause. In this case, Auto-Explain continues to drill down. The real driver is surfaced alongside the correlated cause. If certain hierarchies are consistently irrelevant, or if it seems that the true driver lies in a large hierarchy that got skipped, the search can be narrowed or adjusted through configuration. See [Set up Auto-Explain](../developer-guide/enable-ai-tools/configure-and-start/set-up-auto-explain) for details. Please talk to the person who manages Atoti in your organisation for more details if necessary. ## Related reading * [Auto-Explain user guide](./auto-explain) to learn how to run an analysis and interpret its results * [Set up Auto-Explain](../developer-guide/enable-ai-tools/configure-and-start/set-up-auto-explain) to add the feature to a project and configure the hierarchies it searches # Visualize This user guide Source: https://docs.activeviam.com/atoti-intelligence/6.2/user-guide/chat How to interact with the Visualize This AI assistant in Atoti UI, covering natural language requests for charts and dashboards, cube knowledge queries, and the types of visualizations the assistant generates from Atoti-specific tool context. Visualize This is a feature that enables AI-assisted visualization within the Atoti UI. It provides an integrated AI assistant and a set of Atoti-specific tools that together generate charts, dashboards, and insights from natural language queries. ### Atoti Intelligence Essentials This is part of the Atoti Intelligence Essentials offer. ## What is Visualize This Visualize This provides two core capabilities: * **AI assistant**: an integrated AI assistant in the Atoti UI that generates visualizations on request * **Atoti-specific tools**: a set of tools designed to work with Atoti's data structures and features ## Why use Visualize This Visualize This is powered by a large language model with access to Atoti-specific tools. This combination makes it useful in three ways: * **Data visualization**: Create charts, dashboards, and multi-widget pages from natural language requests, without manually configuring widgets. The assistant selects appropriate visualization types and maps your data to them. * **Cube knowledge**: Ask questions about your cube structure — available measures, hierarchies, dimensions — and get answers drawn from the Atoti context provided to the assistant. * **General-purpose assistance**: Because the assistant is backed by an LLM, it can also handle any question you would ask a conversational AI, from explaining a concept to writing a cookie recipe. ## Where to find the Visualize This Visualize This appears in the Atoti UI after successful setup. No additional navigation is required to locate it. The screenshot below shows the assistant as it appears in the interface: Visualize This in the Atoti UI ## How to use Visualize This ### Prerequisites Before using Visualize This, ensure the following requirements are met: * Visualize This is set up in the project * An LLM is configured * The Atoti application is running * The Atoti UI is accessible ### Create a visualization Follow these steps to create a visualization with Visualize This: 1. Start the Atoti application 2. Open the Atoti UI in a browser 3. Locate Visualize This in the interface 4. Type a question or request in natural language 5. Wait for the assistant to generate the visualization The screenshot below shows an example interaction: Visualize This example interaction The assistant can handle the following types of requests: * Create specific chart types such as bar charts, line graphs, and pie charts * Analyze trends over time * Compare values across dimensions * Generate dashboards with multiple visualizations * Explain the variation of a measure between two members with Auto-Explain, and display the interactive Auto-Explain page of that analysis An Auto-Explain analysis that has already run stays retrievable for a while, so the assistant can be asked which analyses are available, and can display the page of one of them without running it again. See [How to keep analyses retrievable from the chat](../developer-guide/enable-ai-tools/auto-explain/configuration#how-to-keep-analyses-retrievable-from-the-chat). ## Related reading * [Set up Visualize This](../developer-guide/enable-ai-tools/configure-and-start/set-up-visualize-this) to configure the feature in a project and add cube context # Atoti Intelligence & workflows documentation Source: https://docs.activeviam.com/atoti-intelligence/atoti-intelligence # How Atoti connects data sources to visualization tools Source: https://docs.activeviam.com/concepts/atoti-and-data-analytics/atoti-data-analytics Connect Atoti to Atoti UI, Excel, Tableau, and Power BI, or build a custom front end using the XMLA endpoint, REST APIs, and WebSocket API for real-time pivot table and dashboard queries. Atoti is designed to fit into any data analytics architecture. It operates between data sources and visualization tools and delivers fast, precise and interactive analytics. Business users can query Atoti using multiple front ends. The recommended interface is Atoti UI, but users can also connect through third-party tools like Excel, Tableau, and Power BI. This flexibility allows users to work with Atoti using the tools they are most comfortable with. ## Use Atoti UI Atoti UI is the native graphical interface for Atoti. It enables users to explore large-scale financial data using advanced pivot tables, interactive dashboards, and customizable visualizations. Atoti UI supports all Atoti features, including context values and real-time updates. It is continuously tested and updated alongside the Atoti platform to ensure full compatibility and reliability. Atoti Python SDK automatically contains Atoti UI. No further set up is required. [Find out how to install Atoti UI for Atoti Java SDK.](/data-visualization/atoti-ui/latest/developer-guide/install-and-start/set-up) ### Prepare Atoti UI for business users Atoti UI can be deployed as soon as it is installed. However, many of our clients choose to extend and personalize the interface. This includes simple tasks like applying your organization's brand colors, as well as more complex ones such as building custom widgets. [Find out more about how to prepare Atoti UI for business users.](/data-visualization/atoti-ui/latest/developer-guide/install-and-start/set-up) ## Use Excel to query Atoti Access Atoti from an Excel pivot table, using the built-in drivers for Microsoft Analysis Services. Find out more about how to do this: * [Atoti Java SDK](/engine/java-sdk/latest/user_guide/querying/front_ends/excel_xmla) * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/guides/connecting_from_excel) The Atoti Excel Add-In provides some additional features for a more powerful and user-friendly experience. It is available for Atoti Java SDK. It requires an additional installation step. ### Advantages of Atoti Excel Add-in * Allow users to drillthrough into special datagrids and widgets in Excel and bypass the Excel row limit * Refresh the pivot table when real-time updates occur * Move through sliced filters more easily using next and previous buttons * View and configure context values * View MDX queries executed by the pivot table ### Related reading Find out how to * [Work with the Atoti Excel Add-In.](https://docs.activeviam.com/products/atoti/excel-addin/latest/docs/overview) * [Install and set up Atoti Excel for business users](https://docs.activeviam.com/products/atoti/excel-addin/latest/docs/overview/#installation) ## Use Tableau to query Atoti Tableau can be used to query Atoti using the Atoti BI Adapter. Users are able to access data and query Atoti using dedicated widgets. The Atoti BI Adapter requires an extra installation step which is carried out by the developer team in your company. Follow this link to find out more about Atoti BI Adapter for Tableau. * [Work with Tableau using the Atoti BI Adapter](/engine/java-sdk/latest/user_guide/querying/front_ends/tableau/tableau_adapter) * [Install and set up Atoti BI Adapter for Tableau](/engine/java-sdk/latest/user_guide/querying/front_ends/tableau/tableau_adapter_how_to) ## Use Power BI to query Atoti Power BI can be used to query Atoti by importing data from Atoti into Power BI. [Find out more about working with Atoti and Power BI.](/engine/java-sdk/latest/user_guide/querying/front_ends/power_bi) ## Prepare a custom front end for business users We recommend using Atoti UI as the front end for business users. However, it is also possible to integrate Atoti into a custom front end. If you are preparing a custom front end for business users you will need to take the following into account. Click on the links to find out more: * [Continuous queries](/engine/java-sdk/latest/cube/continuous_query_engine) * [MDX statements](/engine/java-sdk/latest/mdx/mdx_functions) We make available a series of REST APIs and websockets to help with this: * [XMLA endpoint](/engine/java-sdk/latest/endpoints/xmla) * [Database REST API](/engine/java-sdk/latest/rest-api/database_rest_api) * [Cube REST API](/engine/java-sdk/latest/rest-api/atoti_rest_api) * [Cube Websocket API](/engine/java-sdk/latest/ws-api/pivot_ws_api) * [Data export REST API](/engine/java-sdk/latest/rest-api/dataexport_rest_api) * [ContentServer REST API](/engine/java-sdk/latest/rest-api/cs_rest_api) # What is the Atoti Content Server? Source: https://docs.activeviam.com/concepts/atoti-components/atoti-content-server The Atoti Content Server provides the content service, a required hierarchical key-value store exposed via REST API, storing dashboards, calculated measures, and user settings across embedded or standalone deployments with optional Hibernate-backed relational storage. The content service organizes metadata using a file-system-like structure, with stores as folders and keys as file names. Each file and directory has role-based permissions that control read and write access. This page is intended for readers who want to understand how Atoti persists and shares metadata. * **Atoti Server** * User content data (KPI, calculated members and named sets) * Branch permissions * Content service API version * User locale * **Atoti Admin UI** * User settings * **Atoti UI** * User permissions * User settings * User content data (dashboards, filters...) ## How does the content server work? The content server hosts the content service and exposes it through a REST API. Atoti Server and other components use this API to read and write metadata remotely. The content server organizes data using a file system like structure. Stores are represented as folders. Keys are represented as file names, and values as file content. Each file and directory has permissions that control read and write access by role. Two deployment options are available. * **Embedded content server** Atoti Server acts as the content server. This option requires no additional server and is the default behavior. It is suitable for development and simpler deployments. * **Standalone content server** The content server runs in a separate process. In both deployments, you can choose from several storage implementations. * An in-memory implementation that does not persist data across restarts. * A local H2 database implementation. * An external database implementation persists data in a relational database and supports audit trail capabilities. The content server connects to this database via JDBC using the Hibernate framework. Several Atoti applications can share one content server, in this case prefixes are used to separate their metadata. ## What is the relationship to other Atoti products? The content server is required for all Atoti deployments. It is used by applications built with the Atoti Java SDK or the Atoti Python SDK, and by all Atoti solutions and workflow products. ## Related reading Find out how to set up the content server with: [Atoti Java SDK](/engine/java-sdk/latest/content_server/cs_overview). [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti_jdbc.user_content_storage_config). Atoti UI depends on the content server to persist dashboards, bookmarks, and user settings. The content server URL must be configured together with the Atoti Server URL when setting up Atoti UI. Atoti Admin UI provides a browser-based interface for the content service. It allows administrators to browse and manage stored content, and to initialize the content service for a new Atoti UI deployment. # Introduction to Atoti dimensions and hierarchies Source: https://docs.activeviam.com/concepts/cube/hierarchies How Atoti organizes multidimensional data using dimensions, hierarchies, and levels, including single-level and multi-level hierarchies, slicing hierarchies, derived hierarchies, and data bucketing. Atoti's cube is a bridge between raw data and users. It helps translate complex data structures into familiar business terms. Instead of working with technical table or column names, users access data using concepts they know such as “P\&L,” “VaR,” or “Counterparty.” ## How is multidimensional data organized and queried in Atoti? Atoti provides a semantic layer using an OLAP cube enabling fast aggregation, data access and queries. A cube introduces some key concepts: * **Dimensions**: Categories like time, geography, product, counterparty. * **Hierarchies**: Structures that organize elements within a dimension to enable intuitive data navigation. Common examples include Year → Quarter → Month or Year → Month → Day. * **Levels**: Sets of members with similar properties. For example, Year → Quarter → Month → Date. * **Measures**: Quantitative data like P\&L, VaR, Exposure. Dimensions and hierarchies are central to how data is structured, filtered and analyzed using Atoti. ## What is a hierarchy? A hierarchy contains a list of similar items or members. For example a currency hierarchy may contain the members EUR, GBP, USD, etc. | Currency | | -------- | | AUD | | CHF | | EUD | | GBP | | NOK | | USD | **Table 1: The currency hierarchy and its members** Each hierarchy member is distinct and represents a unique value. ## What’s the difference between a single-level and a multi-level hierarchy? A hierarchy can contain a single level or several levels. * A single-level hierarchy has only one grouping level, such as a currency hierarchy. * A multi-level hierarchy contains more than one level. A date hierarchy is a common example with the levels year, quarter, month, and date. In a multi-level hierarchy, each unique combination of values across the levels defines a member.\ For example, the following are members of a date hierarchy: * 2025 / Q1 / January * 2025 / Q2 / April / 26th * 2025 / Q3 * 2025 A month like “April” appears in the second quarter of every year, but the path “2025 / Q2 / April” is unique within the hierarchy. Multi-level hierarchies express parent-child relationships between the levels. “Year” is the parent of “Quarter”. “Date” is the child of “Month”. **Date hierarchy** | Level | Name | | ----- | ------- | | 1 | Year | | 2 | Quarter | | 3 | Month | | 4 | Date | **Table 2: The multi-level date hierarchy and its levels** ## What is a dimension? A dimension is a group of related hierarchies.\ For example, the hierarchies "Currency", "Date", and "Trader Location" could be grouped into a dimension "Trades". | Dimensions | Hierarchies | | ---------- | --------------- | | Trades | Trader Location | | | Currency | | | Date | **Table 3: The trade dimension and its hierarchies** Most dimensions contain more than one hierarchy. Some of these hierarchies can be multi-level and some hierarchies are single-level.\ A level of a hierarchy can belong to more than multi-level hierarchy, depending on your needs. For example:\ The dates dimension contains two multi-level hierarchies: * YMD with levels for Year, Month and Date * WD with levels for Week, and Day The same data can belong to more than one hierarchy, as in the example above. If this is the case, be careful when using hierarchies to filter data. For example, if data is filtered to show only the months from the YMD hierarchy, the WD hierarchy will still include all weeks and days, regardless of the applied filter. To filter across all hierarchies consistently, apply filters at the dimension level rather than within a specific hierarchy. Data that is filtered to exclude January AND include week 1 will return no results, since week 1 is in January. Find out how to set up dimensions, and single and multi-level hierarchies: * [Atoti Java SDK](/engine/java-sdk/latest/cube/hierarchy_configuration) * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.hierarchies) ## Which kinds of hierarchy are supported by Atoti? Atoti supports specific forms of hierarchies: **By structure:** * **Balanced**: the number of levels for each path is the same, and data exists only at the lowest level * **Unbalanced**: the paths are of differing depths, and data can exist at any level Hierarchy balanced and unbalanced Atoti does not support ragged hierarchies. This is because a member's parent must belong to the level directly above it. Skipping levels for paths is not allowed.\ In the example below, there are three paths of equal depth. However, two paths bypass parent levels. It is unsupported by Atoti. Hierarchy ragged ## What is a slicing hierarchy? A slicing hierarchy replaces the standard top member with a default member. ### When to use a slicing hierarchy The data in a hierarchy can sometimes be sensibly summed or aggregated. For example, sales data in the geography hierarchy can be summed to give a global sum. The aggregated value is in AllMember for a hierarchy. | Member | Value | | --------- | ----- | | AllMember | 120 | | France | 50 | | Hungary | 10 | | Kenya | 40 | | Singapore | 20 | **Table 4: AllMember and other members for the geography hierarchy** Not all hierarchies can be aggregated in this way. Some data cannot be easily summed, for example the sales figures for different currencies cannot be summed without taking into consideration fluctuating exchange rates. In this case, the hierarchy can be set as a slicing hierarchy.\ For non-slicing hierarchies, the AllMember is used as a default for the hierarchy. When no specific member of the hierarchy is selected, AllMember is displayed. For slicing hierarchies, a slicing member is displayed as the default in place of AllMember. | Hierarchy | Default member | Value | | ----------- | ------------------------------- | ------------------------------ | | Non-slicing | AllMember | sum/aggregation of all members | | Slicing | First member of the first level | the value for this member only | **Table 5: Default members for the quarter and currency hierarchies** Common uses of slicing hierarchies include: * currency: retrieve aggregated values for a single currency at a time * date: retrieve the values for AsOfDate (or another date) by default ## Related reading Find out how to set a slicing hierarchy: * [Atoti Java SDK](/engine/java-sdk/latest/cube/hierarchy_configuration#hierarchy-members-allmember-vs-slicing-members) * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.Hierarchy.slicing) ## Where do hierarchy members come from? Hierarchy members come from table fields or from definitions created during cube configuration. There are three ways to create hierarchy members. ### Members from table fields Some hierarchy members come directly from table columns. A **table hierarchy** uses values found in the data model. For example, a Country level can include members such as France, Germany, and Japan if these values appear in a country column. These members support filtering. Selecting the France member limits the analysis to records associated with France. ### Members created from static definitions Some hierarchy members are created using a fixed list of values defined during configuration. The members do not depend on values in the data model. A manual hierarchy stores these predefined members. **Manual hierarchies** are useful when the categories needed for analysis do not exist in the source data and do not change at runtime. Examples include business structures defined by a specific reporting framework. ### Members created programmatic logic Some hierarchy members are defined using logic that evaluates data. These members do not come from table fields and are not part of a fixed list. They are constructed at runtime or during setup. A **derived hierarchy** contains these programmatically defined members. This type of hierarchy is useful when grouping rules require calculations, thresholds, or context values. Examples include: * Maturity buckets that group trades into periods such as less than one week, one month, or one year. * Threshold-based buckets that sort items into low, medium, or high categories. * Groupings based on business logic, such as scenario or simulation parameters that are not present in the data source. Derived hierarchies are useful when grouping logic depends on calculations or changing context and cannot be stored directly in the database. Selecting a member in a derived hierarchy filters the cube to the records that match that computed category. ## What is data bucketing? Data bucketing is a technique used to group detailed raw data into broader categories, or "buckets", to simplify analysis and make patterns easier to detect. Bucketing reduces the complexity of raw data. Instead of analyzing every individual data point, buckets group data into meaningful ranges or categories. * **Time-based buckets**: Data is not analyzed by individual days or months. It is grouped into quarters or years. For example, data from the months can be bucketed into Q1, Q2, Q3, and Q4 to observe seasonal trends. * **Threshold-based buckets**: Buckets group data based on numeric thresholds. For instance, risk categories might be classified as low, medium, or high depending on credit or other ratings. * **Contextual buckets**: Buckets are also defined using business logic. For example, bonds are grouped into short, mid and long term depending on the maturity dates. ## What are the main uses of derived hierarchies? Derived hierarchies support two main use cases. ### Bucket data using runtime logic Some derived hierarchies create categories that depend on context values such as the current analysis date. These values cannot be stored in the database. The hierarchy computes the appropriate bucket at runtime. For example, a maturity bucket might compute whether a trade matures \*\*within one week, one month, or one year based on the current analysis date. ### Drive measure behavior Some derived hierarchies act as parameters for measure logic. These hierarchies do not only filter data. They also influence calculation steps for measures such as profit and loss calculations. # Introduction to measures Source: https://docs.activeviam.com/concepts/cube/measures How Atoti supports aggregated measures, store look-up measures, and user-defined measures, including measure chains, filters, logical-level aggregation, measure shifting, and null handling. Measures are central to how Atoti aggregates and analyzes data. They represent numerical computations based on data available to the cube. A measure can range from simple aggregations like sums to more sophisticated user-defined logic. ## Which types of measures does Atoti support Atoti supports several types of measures, each suited to different analytical needs: ### Aggregated measures Aggregated measures are derived from numerical values in the original table. Common aggregation functions include: * SUM * AVG * MIN * MAX ## Related reading For a full list of available aggregate functions see * [Atoti Java SDK](/engine/java-sdk/latest/cube/aggregation-functions) * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.agg) These functions operate over schema fields and are typically used to compute totals, averages, or other basic statistics. ### Store look-up measures Store look-up measures provide contextual information that supports other calculations within the cube. They are typically used to enrich analytical logic in user-defined measures (see below). * Store look-up measures provide reference data such as conversion rates or classification label, without affecting the core aggregation logic * The reference data is sourced from isolated tables in the database. * These tables are not part of the main fact table but are linked through mappings or relationships.\ For example, in a foreign exchange scenario, a look-up measure finds the exchange rate for the currency used in a financial transaction. ### User-defined measures User-defined measures allow for custom calculations beyond basic aggregations. For example: * Non-linear operations * Conditional logic * A combination of multiple aggregated measures * A combination of aggregated measures, look-up measures and other user-defined measures Each individual measure generates value based on the data in the cube. The values are used by: * Business users to analyze data using Atoti UI or other tools * Other Atoti user-defined measures to create further measures in Atoti's cube Consider a primitive measure such as `pnl.SUM` which is the sum of the pnl field. This measure cannot aggregate correctly on the currency hierarchy. This limitation is one reason why the currency hierarchy is often treated as a slicing hierarchy. See the [hierarchies](./hierarchies.md) documentation page for more details. To address this issue, the following pattern can be used: * Create a measure called `pnl` and make it visible to users. * When the query is filtered to USD, `pnl` delegates directly to `pnl.SUM`. * When the query is filtered to another currency `XxX`, define additional measures: * A lookup measure that retrieves the forex rate between `XxX` and USD from the isolated forex store. * A conversion measure that multiplies `pnl.SUM` by this forex rate. This approach ensures a consistent and correct aggregated result across all currencies. ## How does Atoti combine measures? Measures are combined into a measure chain, where each measure builds upon the previous one. Measures chain Atoti supports core mathematical operations for combining measures, such as: * plus * minus * multiply * divide These operations can be applied across measures to form new ones, enabling flexible and reusable logic. ## Related reading Find out how to create measures using: * [Atoti Java SDK](/engine/java-sdk/latest/copper/copper_measures) * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.measures#atoti.measures.Measures) ## How can measure calculation be refined with Atoti? In Atoti, measures can be refined using filters and conditional logic, logical-level aggregation, and measure shifting. These techniques allow users to tailor calculations to specific data subsets, hierarchy levels, or time periods. This ensures that each measure reflects only the relevant data, helping users exclude outliers, compare time slices, and analyze specific members or groups within a hierarchy. By refining how measures are calculated, users gain more accurate insights without modifying the underlying dataset. ### Filters and conditional logic Measures in Atoti can include filters or conditional logic to control which data is used in calculations. This ensures that each measure reflects only the relevant subset of data. In other words, data from only specific hierarchy levels is used to calculate the value of the measure. In this way, users can create focused, accurate calculations without needing to adjust the underlying dataset. This is useful for: **Excluding data such as:** * Outliers * Test data * Data received after the start of day * Specific members that could cause double counting **Including data such as:** * Only selected members of a hierarchy * Start-of-day data for comparison with intraday updates **Comparing data such as:** * Comparing a subset of members with the total across a hierarchy * Comparing different time slices, like start-of-day versus current values Find out how to apply filters to measures using: * [Atoti Java SDK](/engine/java-sdk/latest/copper/copper_measures#measure-filtering) * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.function.filter) ### Logical-level aggregation Atoti supports logical-level aggregation. Measures can retrieve the value of other measures at a specific level of a hierarchy. This is useful for: * Grand totals: the sum of all the individual member values * Parent values: the sum of all the individual members up to a given level * Percentages or ratios Find out how to apply conditional logic to measures using: * [Atoti Java SDK](/engine/java-sdk/latest/copper/copper_measures#dynamic-aggregationleaf-operation) * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.scope) ### Measure shifting Measure shifting allows for comparisons across time periods or across different hierarchy members. This is useful for: * Day to day differences: the value from day -1 is shifted to day -2 * Comparing risk exposure across business units: credit risk exposure from counterparty A is shifted to counterparty B * Comparing capital allocation by business unit: capital allocation from desk Y is shifted to desk Z Shifting values along dates is also used for building a timeline of prices or values. Find out how to shift measures using: * [Atoti Java SDK](/engine/java-sdk/latest/copper/copper_measures#shift-measures) * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.function.shift#atoti.shift) ## How does Atoti handle null values? Atoti's aggregation functions have consistent null handling behavior: * Null values are ignored in calculations * If all input values are null, the result is empty This default behavior is consistent across both the Java and Python SDKs, ensuring stable and reliable calculations even when working with incomplete datasets. Developers can also implement their own logic within user-defined measures to treat nulls differently, such as substituting a default value. Find out how to manage nulls using: * [Atoti Java SDK](/engine/java-sdk/latest/datastore/datastore_config#default-values) * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.Column.default_value) # What is the database in Atoti? Source: https://docs.activeviam.com/concepts/database/database How Atoti handles fact-level data using an in-memory datastore with columnar storage and indexes, and DirectQuery for external databases, including a hybrid approach for cost and performance optimization. Atoti cubes operate on top of a database. The database is where the fact-level data resides. Facts represent granular records such as financial trades, currency rates, price vectors, and other transactional data. These facts are available for querying in Atoti. ## What are the supported methods for handling fact-level data in Atoti? Fact-level data can be stored in two ways: * **Internal datastore**: Atoti’s in-memory datastore is optimized for fast, multidimensional analytics. It stores data directly in memory, enabling low-latency query responses. * **External databases**: External systems store data persistently. Atoti connects to these sources and queries them dynamically using DirectQuery. ### Cost considerations Using an external database via DirectQuery reduces memory usage and infrastructure costs, especially for large datasets. Performance depends on the external system’s responsiveness and availability. A hybrid approach is possible: keep recent, frequently accessed data in memory and store historical or “cold” data in an external database. ## What is the difference between the internal datastore and DirectQuery? | Feature | Internal datastore (in-memory) | DirectQuery (external) | | ------------------ | ------------------------------------------------------------- | -------------------------- | | Storage location | In memory | External database | | Load performance | Fast, low latency | Depends on external system | | Data freshness | Always up to date thanks to the built-in real-time capability | Depends on external system | | Memory usage | High | Low | | Versioning support | Yes | Limited | ## How Atoti stores data in the Datastore Atoti’s in-memory datastore uses advanced techniques for high performance and compression: * **Columnar storage**: Data is stored by column rather than by row. Searching within a single column is faster than scanning across multiple rows. Less data needs to be scanned, therefore filtering and joining operations execute more quickly and efficiently. Performance is improved. * **Indexes**: Key fields are automatically indexed to accelerate query performance. Indexes enable compression strategies and reduce redundancy in stored data. In addition, data is located and retrieved more quickly with an index. * **Dictionaries**: Columns are dictionarized to reduce memory usage and improve query time. This core architecture is designed for speed, making it ideal for use cases such as intraday risk monitoring, limit management, interactive what-if analysis, and operational workflows. ## How DirectQuery works with external data warehouses DirectQuery enables Atoti to perform analytics on data stored in external warehouses without loading it into memory. * **Benefits**: Reduces in-memory storage requirements and lowers infrastructure costs for large datasets. * **How it works**: Atoti cubes use DirectQuery connectors to translate cube requests into external database queries (mostly SQL). By default, no data is stored in memory. However, aggregate providers can be configured to cache frequently accessed results if needed. This approach leverages the scalability of external storage while minimizing memory usage on the Atoti server. ## How to use the Datastore and DirectQuery together Atoti supports combining its in-memory datastore with DirectQuery connectors to external databases. The tables in the in-memory datastore are not joined with tables accessed through DirectQuery. But the data in the in-memory datastore can be used alongside the data accessed through DirectQuery in the same cube. This hybrid approach allows you to optimize performance without increasing infrastructure costs. Frequently accessed or frequently updated data is stored in memory while less critical data is in the external systems. ### Why use a hybrid approach? * **Faster measure calculations**: Lookup data stored in memory can be accessed instantly during measure calculations, avoiding round-trips to the external database. * **Reduced memory usage**: Fact tables and their related tables remain in the external database, keeping the memory footprint small. ### How does it work? * **In-memory datastore**: Stores lookup tables as isolated stores. These are accessed during measure calculations. * **DirectQuery**: Handles the fact table and tables joined to it. Queries are executed on the external database. ## Related reading Find out more about configuring the datastore in Atoti: * [Atoti Java SDK](/engine/java-sdk/latest/database/database_api) uses a specific API * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.Session.create_table#atoti.Session.create_table) creates the datastore directly from the tables # What is a database schema? Source: https://docs.activeviam.com/concepts/database/database-schema How Atoti database schemas work, including star and snowflake schema structures, table references and joins, isolated tables for lookup data, and supported field types including vectors. The schema defines data tables and how they are are linked together. Schemas often follow a **star schema** structure, where multiple reference tables are connected to a central table using key fields. * A reference table refers to tables that are joined to another table. Database schema A schema defines how data is organized and related within a database. Tables in a schema can be linked using references, which establish relationships between them. A reference maps key fields from one table (the owner) to foreign key fields in another table (the target). This allows data from different tables to be queried together. At the center of each schema is the fact table. This fact table typically contains the main transactional records, such as trades with fields like customer\_name. Other tables can link to the central fact table or to each other through references. This creates a connected structure. In a typical star schema, reference tables act as dimension tables joined to the central fact table. This design simplifies queries and improves performance. More complex schemas include multiple tables, resulting in a snowflake schema or other variations. The additional tables are connected to the fact table at the center of the snowflake schema. Database star schema ## How are tables joined to form a schema? A reference table can link to other tables. For example: * The fact table contains trade records with a `customer_name` field. There is only one fact table for each cube on the database schema. * A reference table maps `customer_county` to `country_name`. This setup allows users to filter or classify trades by country, even though the fact table does not contain country data directly. Database star schema A table can reference another table multiple times, as long as each reference uses a different set of fields. For example: * The fact table contains trade records with `seller` and `buyer` fields. * The fields `seller` and `buyer` map to the key in a table for party records. Database multiple records ## Related reading Find out more about table joins: * [Atoti Java SDK](/engine/java-sdk/latest/copper/copper_join) * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.Table.join#atoti.Table.join) ## Are all tables joined to the schema? **Isolated tables** are part of the datastore but are not joined to the fact table. They are look-up tables that enrich data. Find out more about [store look-up measures](../cube/measures.md#store-look-up-measures). Isolated tables are useful for: * **Lookup and reference data**: Store external values such as currency conversion rates or other market data. * **Supporting calculations**: Provide values that support the calculation of measures. These values can be market reference data or other computed values stored in the isolated table. * **Display purposes**: Help format or translate values for better readability. Database isolated tables ## Related reading Find out more about isolated tables: * [Atoti Java SDK](/engine/java-sdk/latest/copper/copper_join#join-types-in-copper) * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.Session.add_external_table#atoti.Session.add_external_table) ## What kinds of fields are supported by Atoti? Atoti supports a wide range of field types: * **Numerical (native) types**: `int`, `double`, `float`\ Typically used as measures and aggregated by Atoti. * **Strings**\ Used as classifiers, table levels, and filters. * **Dates and times**\ Enable Atoti to interpret and filter by date ranges. * **Vectors** Useful for financial analytics like Value at Risk (VaR).\ Atoti is optimized for storing and aggregating vector-based data structures efficiently. * **Objects** Custom objects can be stored. ## Related reading Find out more about key fields using: * [Atoti Java SDK](/engine/java-sdk/latest/datastore/datastore_config) * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.type) # What is Atoti? Source: https://docs.activeviam.com/concepts/intro Atoti is a real-time analytics platform combining an aggregation engine, an in-memory datastore, and a multidimensional semantic model to deliver fast and consistent analytics across applications and workflows. Atoti is built for teams that need fast aggregation, flexible multidimensional analysis, and consistent business logic across all analytics consumers. The semantic layer is materialized through the **Atoti cube**, which centralizes business logic and defines: * **[Dimensions](./cube/hierarchies.md)** to organize data by business categories * **[Hierarchies](./cube/hierarchies.md#what-is-a-hierarchy)** to define how those categories break down into levels * **[Measures](./cube/measures.md)** to define calculations and aggregations This ensures all users and systems apply the same logic when analyzing data. # Why use Atoti? Atoti provides a platform for fast and flexible analytics at scale. Key benefits include: * Real-time aggregation on granular data. * Analysis of large datasets. * Flexible slicing across any dimension. * Support for non-linear and context aware calculations. * Blended data from in-memory and from external warehouses to optimize costs and maintain speed. * Integrated workflows for scenario analysis, limits, and sign off. * Interfaces for UI, BI tools, Python, Java, and AI agents. # How is Atoti structured? Atoti groups several components that work together. It is organized into three main layers: data sources, the Atoti Server, and client applications. Atoti Server diagram.png ## Data sources The platform ingests data from multiple sources: * External files (Parquet, CSV, Avro, JSON, etc.) * Databases accessed through JDBC * Streaming systems such as Kafka or RabbitMQ * External data warehouses such as Databricks, Snowflake, or ClickHouse Data can either be [loaded into memory](./load-data/load-data.md) or [queried directly from external systems](/concepts/load-data/DirectQuery). ## Atoti Server At the core of the platform is the **Atoti Server**. It contains the aggregation engine and manages data access and calculations. ### Aggregation engine The aggregation engine processes queries and computes results. At the center of the engine is the **Atoti cube**, which defines: * [Dimensions](./cube/hierarchies.md) to organize data * [Measures](./cube/measures.md) to calculate results The engine can work with: * An [in-memory datastore](./load-data/load-data.md) for high-performance analytics * External databases via [DirectQuery](/concepts/load-data/DirectQuery) This allows fast aggregation while keeping large datasets in external systems when needed. The aggregation engine scales across cores and nodes. It can use many CPU cores on one machine and can also run across multiple machines. ### Content server The [content server](./atoti-components/atoti-content-server.md) stores the metadata required for an Atoti Server to run. This includes dashboards, measures, KPIs, and user settings. It can run embedded within Atoti Server or as a separate service. ## Clients and interfaces The results of the aggregation engine are accessed through client applications. These include: * **[Atoti UI](/data-visualization/atoti-ui/latest/introduction-to-atoti-ui)** for an integrated analytical experience * **Custom applications** built on public services * **[AI agents and workflows](/atoti-intelligence/atoti-intelligence)** * **[Business intelligence tools](/engine/java-sdk/latest/user_guide/querying/front_ends/user_guide_querying_front_ends_overview)** (using Atoti BI Adapters) These clients query the aggregation engine and present results to end users or downstream systems. ## Administration and extensibility Atoti is an open and extensible platform. It provides: * Server management through Java. * An [Atoti Java SDK](/engine/java-sdk/latest/intro/overview) and an Atoti Python SDK. * Deployment options for on-premise and cloud environments. * Integration points for BI tools and custom applications. # What is Atoti Enterprise Risk? Atoti Enterprise Risk is a complete risk analytics solution that combines the Atoti Engine, [Atoti Intelligence](/atoti-intelligence/latest/intro/intro), and Atoti solutions into a unified offering. The engine delivers consistent data modeling and aggregation, while the intelligence and solutions layers add advanced analytics capabilities and domain-specific workflows. atoti-solutions.png ## Atoti Intelligence The intelligence layer builds on the output of the query engine and provides reusable capabilities for analytical workflows. It includes: * [Atoti Intelligence](/atoti-intelligence/latest/intro/intro), enabling AI agents to automate tasks and perform analytics * [Scenario analysis](/solutions/libraries/what-if/latest/introduction-to-atoti-what-if) for comparing different situations * [Limits monitoring](/atoti-intelligence/workflows/limits/latest/introduction-to-atoti-limits) with alerts when thresholds are breached * [Sign-off workflows](/atoti-intelligence/workflows/signoff/latest/introduction-to-atoti-signoff) for controlled data updates ## Atoti solutions [Atoti solutions](/solutions) are packaged, configurable applications that use the platform’s components and reference models. They include prebuilt semantic models, measures, calculations, and workflows. Available solutions include: * Atoti for Front Office * Atoti for Market Risk * Atoti for FRTB * Atoti for xVA * Atoti for Counterparty Credit Risk * Atoti for Liquidity Risk * Atoti for Collateral and Margin Optimization Solutions can be used as is or extended with custom data models, calculations, and workflows. # Which use cases does Atoti support? Atoti is frequently used for applications that require real time analytics or complex multidimensional calculations. Common use cases include, and are not limited to: * Real-time risk and P\&L monitoring. * Counterparty credit risk * Liquidity risk * Enterprise risk consolidation * Scenario analysis and stress testing * Regulatory capital calculation and simulation * Collateral and margin optimization * Portfolio and exposure analysis * Operational workflows that require fast validation and adjustments # How DirectQuery connects to external databases Source: https://docs.activeviam.com/concepts/load-data/DirectQuery How DirectQuery connects Atoti to external databases such as Snowflake and BigQuery without loading data into memory, covering data requirements, versioning with native and emulated time-travel, and incremental or full refresh. DirectQuery is a feature in Atoti that allows data to be queried directly from an external database without first loading it into Atoti's in-memory datastore.\ This means Atoti can work with large datasets stored outside the application, reducing memory usage and allowing real-time access to updated data. It is especially useful when working with external systems that already manage data storage, versioning, or access control. ## When is DirectQuery relevant? DirectQuery is useful for users who need: * Interactive access to external data sources * Reduced memory footprint in Atoti applications * Integration with enterprise databases such as Snowflake, BigQuery, ClickHouse, and others ## What assumptions does DirectQuery make about external data? ### Unique keys Tables must define and enforce unique key fields. This is essential for reliable joins and maintaining many-to-one relationships. ### Vector integrity DirectQuery supports vectors stored across columns or rows. Each format has its own constraints: **Column-based vectors:** * Each value must be non-null **Row-based vectors:** * Indexes must start at 0 or 1 * All indexes must be present and consistent * No null values are allowed in primitive types These constraints ensure that vector operations and joins behave efficiently and predictably. ### Native and emulated vector support Some databases, such as ClickHouse, offer native support for vectors through array types and built-in functions. These databases can handle vector operations efficiently without additional configuration. Other databases, like BigQuery, may support array types but lack the necessary aggregation functions for vectors. In these cases, DirectQuery emulates vector behavior to ensure consistent functionality. Emulation includes techniques for storing and processing vectors across multiple columns or rows. When native support is available, DirectQuery avoids emulation to preserve performance. Emulation is only used when necessary to bridge gaps in database capabilities. ### Validation tools DirectQuery includes optional validation interfaces to help confirm that external data meets its operational requirements. These tools can detect: * Duplicated keys * Missing vector indexes * Null values in vector fields * Inconsistent start indexes These validations are manual and resource-intensive, so they are not enabled by default. However, they are useful for diagnosing data quality issues and ensuring reliable query behavior. ## How does DirectQuery connect to external databases? DirectQuery connects Atoti to external databases by delegating queries directly to them. This allows Atoti to retrieve data without storing it in memory, reducing resource usage. To establish this connection, Atoti requires: * A valid connection string or connector configuration * Appropriate permissions to access and query the external database Once connected, DirectQuery can execute queries on the remote database as needed. These queries are generated automatically by Atoti based on the cube’s schema and the operations requested by users. This setup is the starting point for all other DirectQuery features, including versioning, refresh strategies, and performance optimizations. ## How does DirectQuery manage joins and relationship optionality? Stores are joined with key fields. Foreign key field columns in a source table are either optional or mandatory. * **Mandatory:** For example, every trade must be associated with a desk, and a desk can be associated with more than one trade. In this example the desk field in the trade table is mandatory. * **Optional:** For example, the `CreditRatingID` for counterparties is unknown or unnecessary for some contracts. The relationship between the `CreditRatingID` and the trade is optional. DirectQuery joins ## How are data updates in the external database managed? DirectQuery manages data updates by relying on the versioning capabilities of the external database. Versioning allows Atoti to track and query data as it existed at specific points in time, which is essential for maintaining consistency in analytical results when the underlying data changes frequently. Unlike Atoti’s in-memory datastore, DirectQuery does not store historical versions internally. Instead, it depends on the external database to provide access to past states of the data, either through native time-travel features or emulated mechanisms configured by the user. Find out more about Atoti manages [versions](../versions/versions.md) on this page. ### Native time-travel Some databases, such as Snowflake and BigQuery, support native time-travel. This allows DirectQuery to query historical versions of data directly, ensuring that all components of the cube remain synchronized. When native time-travel is available: * DirectQuery automatically uses it by default. This ensures data consistency, minimal memory footprint, and real-time access without extra configuration. * It can be disabled if needed via configuration * Discovery queries are used to determine the latest version of each table ## Related reading Find out more about DirectQuery using: * [Atoti Java SDK](/engine/java-sdk/latest/directquery/connect_to_external/intro) * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/guides/using_directquery) ### Emulated time-travel For databases that do not support native time-travel, DirectQuery with Atoti Java SDK offers an emulated time-travel mechanism. This requires additional setup in the external database: * Tables must include versioning columns (e.g., `valid_from` and `valid_to`) * These columns define the time range during which each row is valid * The data type must support SQL comparisons and be consistent across tables Emulated time-travel ensures consistent query results by filtering rows based on their validity range. However, it introduces additional complexity and may impact performance. ## How does DirectQuery ensure version discovery and consistency? Atoti uses discovery queries to determine the current version of each row. These queries run when a new version is created and help filter out invalid rows. Maintaining version consistency is critical to avoid desynchronization between cube components and the external database. ## How are data changes in the external database synchronized with Atoti? When data in the external database changes, DirectQuery must ensure that the Atoti cube reflects those updates accurately. This synchronization is essential for maintaining consistency between the cube’s internal structures and the source data. DirectQuery supports two approaches to synchronize data: * **Incremental refresh:** Only part of the data is synchronized * **Full refresh:** All of the data is synchronized ## Related reading [Find out more about emulated time-travel with Atoti Java SDK.](/engine/java-sdk/latest/directquery/versioning) # How Atoti manages ETL Source: https://docs.activeviam.com/concepts/load-data/etl How the Atoti Java SDK ETL framework extracts and transforms data using Sources, Channels, and Tuple Publishers, covering CSV, Parquet, JDBC, cloud storage, and column calculators for data enrichment. ## What is the ETL framework in Atoti? The ETL framework in Atoti is available in the Java SDK and provides a built-in mechanism for extracting, transforming, and loading data from external sources into its in-memory datastore. It uses components such as Sources, Channels, and Tuple Publishers to manage data ingestion and transformation efficiently. In contrast, the Atoti Python SDK does not include an ETL framework. Data extraction and transformation are performed using Python tools like pandas before loading the data into an Atoti session. ## How does the ETL pipeline work in Atoti? The ETL pipeline for Atoti Java SDK follows a structured process: * **Extract**: Data is retrieved from various sources such as files, databases, or external APIs. * **Transform**: Business logic, enrichment, and data cleaning are applied. * **Load**: Transformed data is inserted into Atoti’s datastore for fast analytical queries. This pipeline supports real-time updates and ensures consistency across analytical views. ## What is the extraction step? Extraction involves retrieving data from external sources and converting it into an in-memory format suitable for loading into the datastore. ### Supported source types Atoti supports the following data sources: * **CSV files**: Parsed using Atoti’s built-in CSV parser. * **Parquet files**: Parsed using Atoti’s columnar data parser. * **JDBC databases**: Data is extracted using a JDBC driver and query. * **Cloud storage**: CSV and Parquet files can be extracted from: * Amazon S3 * Microsoft Azure Blob Storage * Google Cloud Storage The Cloud Source API provides a unified interface for accessing remote files, including authentication and access logic. ### In-memory sources Some sources can bypass the extraction step and interact directly with the transaction manager: * Message brokers (e.g. Kafka) * In-memory objects (e.g. Arrow table) These sources are already structured and do not require parsing or transformation before loading. ### Extraction components Atoti models extraction using: * **Topics**: Represent a path to a specific collection of data (e.g., file, directory, or database query). * **Sources**: Manage how data is loaded; either as a one-time operation or as a continuous stream. * **Channels**: Route data from sources to specific stores in the datastore. Datastore ETL components ## What is the transformation step? Transformation modifies or enriches data before it is loaded into the datastore. This ensures the data is clean, consistent, and ready for analysis. ### Transformation mechanisms Atoti provides two main mechanisms: * **Tuple publishers**: Manage how data is processed before loading. They can: * Filter records * Stream data in batches or row-by-row * Control transaction behavior * **Column calculators**: Modify or enrich data during ingestion.\ Built-in calculators include: * Constant value insertion * Line index tracking * File metadata (e.g., file name, path) * Empty value insertion Custom calculators are built to answer specific needs. For example, using a numerical date to extract a written month: `12/12/29` becomes `December`. These tools help annotate data with useful metadata or generate unique identifiers. ## Related reading [Find out how to work with tuple publishers and column calculators with Atoti Java SDK.](/engine/java-sdk/latest/sources/how-to/load_a_csv_file#load-a-simple-csv) For the Atoti Python SDK, data extraction and transformation are performed using Python tools. # How to bring data into Atoti Source: https://docs.activeviam.com/concepts/load-data/load-data How to bring data into Atoti's in-memory datastore from CSV, Parquet, JDBC, Kafka, and cloud sources using datastore transactions, or query large external databases without loading via DirectQuery. Data loading is the process of inserting external data into Atoti’s in-memory datastore.\ The datastore enables fast, real-time analytics by keeping data readily accessible for queries and computations. Atoti DirectQuery is an alternative approach that connects to external databases without loading all the data into memory first ## What is data loading in Atoti? Data loading is the process of inserting external data into Atoti’s in-memory datastore.\ The datastore keeps data in memory to support fast analytical queries and computations.\ Loading happens at the end of an extraction and transformation process. ### Which data sources can connect to Atoti? Atoti supports a wide range of external data sources: * **Flat files**: (e.g. CSV, Parquet) * **Relational databases**: via JDBC (e.g., PostgreSQL, Oracle, SQL Server) * **Datawarehouses**: (e.g. BigQuery, Snowflake) * **Messaging systems**: (e.g. Kafka, JMS) * **Custom systems**: bespoke APIs or data platforms ### How is data loaded? Loading is the final step in the data pipeline where transformed data is inserted into the datastore. Atoti uses a transactional model to ensure consistency and isolation during this process. ### What are datastore transactions A datastore transaction refers to a sequence of operations performed on a datastore that are executed as a single, atomic unit. This means either all the operations in the transaction succeed, or none of them succeed. This approach ensures data consistency and integrity. Queries to Atoti only see committed transactions. Find out more about how to load data from these sources with Atoti Java SDK * [CSV](/engine/java-sdk/latest/sources/csv_source) * [JDBC](/engine/java-sdk/latest/sources/jdbc_source) * [Parquet](/engine/java-sdk/latest/sources/parquet_source) Find out more about how to load data with Atoti Python SDK * [CSV](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.data_load.csv_load) * [JDBC](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti_jdbc.jdbc_load#atoti_jdbc.JdbcLoad) * [Parquet](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti_parquet.parquet_load#atoti_parquet.ParquetLoad) * [Arrow, Pandas, NumPy, Spark](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.Table.load) ## What is DirectQuery? DirectQuery connects Atoti to an external database without loading the data into the in-memory datastore.\ Atoti delegates queries to the external system.\ This reduces memory use and enables access to large or frequently updated datasets.\ DirectQuery is suited to enterprise databases such as Snowflake, BigQuery, or ClickHouse. ### How does DirectQuery manage data updates and versioning? DirectQuery relies on the external database for versioning.\ When the database supports native time travel, DirectQuery uses it automatically.\ When it does not, time travel can be emulated through versioning columns. Two refresh strategies are available: * Incremental refresh * Full refresh These strategies ensure that the cube stays aligned with external changes. ## Related reading Find out more about [DirectQuery](./DirectQuery) # How aggregate providers can speed query time Source: https://docs.activeviam.com/concepts/performance/aggregate-providers How Atoti aggregate providers control pre-aggregation strategy, covering the JIT provider for on-demand aggregation, leaf provider for pre-aggregated indexes, and bitmap provider for high-concurrency workloads. Aggregating data at query time can be slow because the system must fetch data from the datastore or an external database (DirectQuery). Aggregate providers allow pre-aggregation, so queries retrieve results from optimized structures instead of recalculating from scratch. Aggregate providers define the strategy for aggregating measures in a cube. They determine whether data is aggregated on demand or pre-aggregated during data loading. This choice directly impacts query speed, memory usage and transaction speed. ## What are the types of aggregate providers and their impact? ### Just-in-time (JIT) provider * **Behavior:** Aggregates data at query time. * **Memory usage for storage:** None. * **Memory usage at query time:** Higher than other aggregate providers * **Query speed:** Slower. * **Use case:** Small datasets or infrequent queries. * **Impact:** No pre-aggregation; queries depend on datastore scans. ### Leaf provider * **Behavior:** Pre-aggregates data during loading at leaf level. * **Memory usage for storage:** Moderate. * **Query speed:** Fast. * **Memory usage at query time:** Moderate. * **Use case:** Balanced performance for most cubes. * **Impact:** Queries retrieve pre-aggregated values using point indexes, reducing computation time. ### Bitmap provider A bitmap aggregate provider pre-aggregates data using a leaf provider. They use a bitmap index for faster data retrieval. * **Behavior:** Pre-aggregates data and builds bitmap indexes. * **Memory usage for storage:** Higher than a leaf provider. * **Query speed:** Fastest. * **Memory usage at query time:** Lower than JIT or leaf. * **Use case:** High query concurrency and large datasets. * **Impact:** Queries use bitmap submasks for instant retrieval of aggregated values. performance-agg-provs.png ## Related reading Find out more about aggregate providers by following the links below: * [Atoti Java SDK](/engine/java-sdk/latest/cube/providers/aggregate_provider) * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.aggregate_provider.aggregate_provider#atoti-aggregateprovider) # How modifying the aggregates cache can speed query time Source: https://docs.activeviam.com/concepts/performance/aggregates-cache How the Atoti aggregates cache stores previously computed measure-location pairs to avoid recalculation, including cache size configuration, caching strategies, and when to enable or avoid the cache. The aggregates cache stores previously computed measure-location pairs. When a query requests the same measure at the same location, the result is retrieved from the cache instead of recalculating from raw data. This reduces query execution time significantly: * Avoid recalculation: Cached results are returned instantly. * Reduce datastore scans: Queries do not need to access the underlying datastore. * Optimize repeated queries: Dashboards and reports that reuse the same measures benefit the most. performance-agg-cache.png ## How can the aggregates cache be modified? * Enable caching: Activate the aggregates cache in the cube configuration. * Set cache size: Define the maximum number of measure-location pairs stored. * Choose caching strategy: * Cache all measures. * Cache only selected measures. * Exclude specific measures from caching. * Clear or resize cache: Adjust cache behavior dynamically based on workload. ## When to use the aggregates cache The aggregates cache is most effective when query patterns are predictable, and data loading is infrequent. It is less useful in real-time environments where data changes often. ### Recommended scenarios * One-off data loading: Data is loaded once and queried repeatedly. * Infrequent intraday updates: Cache remains valid for most queries. * High dashboard reuse: Multiple users run similar queries. ### Avoid using the cache when * Real-time data loading: Frequent updates clear the cache, reducing its benefit. * Highly dynamic queries: If queries rarely repeat, caching adds little value. ## Related reading Find out how to modify the default cache with: * [Atoti Java SDK](/engine/java-sdk/latest/cube/configuration#configure-the-aggregate-cache) * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.aggregate_cache#atoti-aggregatecache) # How to understand the data journey Source: https://docs.activeviam.com/concepts/performance/data-journey How data flows through Atoti from extraction and transformation to loading, including column calculators, tuple publishers, partitioning, NUMA-aware memory allocation, and the impact of each stage on performance. This page introduces the data journey in Atoti, including how data is extracted, transformed, and loaded into the datastore, and how parallelization and NUMA awareness help deliver high performance at scale. **Prerequisites:** A basic understanding of Atoti stores, references, and sessions is recommended before reading this page. Familiarity with Java concepts is also helpful when referring to Java-specific features such as thread-based parsing, column calculators, and tuple publishers. ## Why the data journey matters The data journey determines how efficiently Atoti ingests, prepares, and serves data for analysis. Each stage has direct consequences on performance and scalability: * **Extraction** defines how quickly data enters the system * **Transformation** ensures records are clean and analytically relevant before storage * **Loading** establishes the indexes and structures used by the aggregation engine * **Partitioning and NUMA policies** define how the workload scales across available cores and memory nodes ## What happens during data extraction? The first step of the data journey is to extract data from external sources and then to convert it into an in-memory format suitable for the datastore. Atoti supports a range of source types, including CSV files, Parquet files, JDBC databases, and cloud storage providers such as Amazon S3, Microsoft Azure Blob Storage, and Google Cloud Storage. In the Atoti Java SDK, extraction is handled by dedicated threads that parse incoming data. For CSV files specifically, Atoti uses a built-in CSV parser to read and interpret records during this phase. ## What happens during data transformation? After extraction, the data is transformed before it is loaded into the datastore. Transformation ensures that records are clean, consistent, and enriched with any additional context required for analysis. Atoti Python SDK does not include methods for data transformation. If required, this step is managed with other Python tools and libraries. In the Atoti Java SDK, two mechanisms handle data transformation. * Column calculators * Tuple publishers Column calculators modify or enrich data during ingestion. Built-in calculators handle operations such as inserting constant values, tracking line indexes, attaching file metadata, or inserting empty values. Custom calculators can also be implemented to address specific business requirements. Tuple publishers complement this by controlling how transformed records are submitted to the datastore. Tuple publishers allow data to be filtered, streamed in batches or row-by-row. ## What happens during data loading? Transformed data is then loaded into Atoti's in-memory datastore. In the Atoti Java SDK, tuple publishers govern the flow of data during this phase, translating each record into the internal structures of a store. As data is inserted, Atoti builds indexes to enable fast lookups and analytical queries, and applies duplicate handlers to ensure that key constraints are respected and store integrity is maintained. Reliable data loading depends on how records are processed and how changes are committed to the datastore. Atoti uses transactions to group loading operations so queries always see a consistent state. This consistency holds even when loading happens in parallel. Transactions also enable performance optimizations during the initial load of an application. Partitions are created during data loading, and the datastore routes each record to the correct partition based on the store’s partitioning configuration. For high-cardinality hierarchies, loading time can be further reduced using virtual hierarchies. Instead of populating hierarchy members during loading, a virtual hierarchy defers member retrieval to query time, reducing both load time and memory usage. ## How does Atoti use parallelization and NUMA? Atoti is designed to take full advantage of modern multi-core and multi-processor hardware. Most operations within a partition are single-threaded, but different partitions execute in parallel across multiple CPU cores, enabling efficient use of available processing resources. On Linux servers, Atoti additionally supports Non-Uniform Memory Architecture (NUMA), which provides separate memory banks for each processor or group of processors. By aligning partitions with memory nodes through NUMA node selectors, Atoti reduces memory access latency and maximizes data locality, keeping data close to the cores that will operate on it. ## How does partitioning enable parallelization? Partitioning distributes records across multiple partitions, each of which is processed independently by a separate thread. Partitions are not predefined. They are created dynamically as data is loaded, meaning the order of insertion can influence their assignment and NUMA placement. A well-designed partitioning strategy creates balanced partitions, avoids resource contention, and reduces cross-node memory access. This makes partitioning a critical design decision with direct consequences on both loading and query performance. # How JVM tuning can improve Atoti performance Source: https://docs.activeviam.com/concepts/performance/jvm-tuning How JVM tuning improves Atoti Java SDK performance by sizing heap memory for query execution and off-heap memory for datastore structures, and when to tune to avoid OutOfMemoryError and GC pauses. JVM (Java Virtual Machine) tuning can help Atoti’s performance because the JVM manages memory allocation and garbage collection. * **Avoids memory-related errors:** Insufficient heap or off-heap memory can lead to OutOfMemoryError or failed data loads. * **Reduces application pauses:** Stop-the-world garbage collections can freeze the application during heavy workloads. * **Improves stability:** Balanced memory allocation prevents crashes caused by OS memory limits. ## Which JVM memory areas does Atoti use? ### Heap memory * Used for query execution. * Subject to garbage collection. * Grows and shrinks dynamically. ### Off-heap memory * Stores most of the data structures of the cubes and datastores. * Not managed by garbage collection. * Must be explicitly sized. performance-jvm-memory.png ## When to tune JVM settings JVM tuning is most effective when: * Large datasets require significant off-heap memory. * Frequent queries cause heavy heap usage. * Stop-the-world GCs impact performance during data loading or real-time updates. ### Avoid excessive memory allocation * The sum of heap and off-heap memory must not exceed OS capacity. * Leave room for other processes to prevent JVM crashes. ## Related reading * [How to tune JVM settings with Atoti Java SDK](/engine/java-sdk/latest/configuration/memory_management) * [How to tune JVM settings with Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/getting_started/deployment/deployment_setup#java-options) # How partitioning and NUMA awareness can improve data loading and query time Source: https://docs.activeviam.com/concepts/performance/partitioning How Atoti partitioning distributes data across partitions for parallel processing and partition skipping, NUMA-aware placement on multi-socket servers, modulo and value-based strategies, and partitioning constraints. **Partitioning** controls how Atoti splits data across multiple partitions, enabling parallel processing during both data loading and querying. **NUMA awareness** builds on top of this by controlling where in physical memory each partition resides, minimizing latency on multi-socket servers. Partitioning can be applied without NUMA awareness but understanding both concepts together is key to getting the best performance out of Atoti. ## What is partitioning? Partitioning splits the data in a data structure into independent groups called partitions. This unlocks three key capabilities: 1. **Partition skipping**: When a computation targets specific partitions, Atoti scans only those partitions rather than the entire data structure. 2. **Parallel processing**: Each partition is the base unit of parallelization. When all partitions are involved in a computation, they can be processed concurrently and their results consolidated. This requires partitions to be roughly equal in size. 3. **Faster writes**: Because partitions are independent, multiple partitions can be written to simultaneously without contention. Atoti's two main partitioned data structures are the datastore and the aggregate provider. In the datastore, partitioning is defined per store and is optional, but strongly recommended for stores of importance. Rows are assigned to partitions according to a partitioning function. All operations within a partition are single-threaded. Two common mistakes to avoid are: * Disproportionate partitions: if one partition holds significantly more records than the others, all partitions will wait on that partition to complete. This can be observed during **data loading** as CPU usage briefly peaks near 100% before dropping to single digits while the remaining partition finishes loading. * Too many partitions: if the partition count is an order of magnitude higher than the CPU count, **query performance** will degrade due to context switching. ## What is NUMA awareness? > **Note**: NUMA awareness is only available on Linux servers. NUMA (Non-Uniform Memory Architecture) is a memory architecture used in multi-socket servers. Each CPU socket has its own local memory, and accessing local memory is faster than accessing memory on another socket. When threads read data from remote memory, latency increases and processing slows down. NUMA awareness builds directly on partitioning: * Each partition is assigned to a specific NUMA node * Threads operating on a partition are bound to the same node as the partition. * Memory access is therefore local to the CPU socket and improves query performance. The effectiveness of NUMA awareness depends on the partitioning strategy. A well-designed partitioning keeps related data within the same NUMA node. This limits cross-node memory access and reduces latency during query execution. Atoti provides two NUMA policies. 1. The **placed** policy (default) creates one thread pool per NUMA node. Each thread is bound to its node and performs memory allocation on that node. Data allocated on a node is bound to that node, and all read and write operations are performed by the associated thread pool. This maximizes data locality and minimizes latency. 2. The **free** policy creates a single thread pool spanning the entire system. Threads are managed by the OS and can move between nodes at any time. No effort is made to maximize data locality. ### Further reading: Atoti Java SDK and Atoti Python SDK use the same set up for NUMA awareness and NUMA policies * [Set up NUMA awareness for a Linux server](/engine/java-sdk/latest/concepts/partitioning#installation) * [NUMA policy defined using JVM startup flags](/engine/java-sdk/latest/concepts/partitioning#usage-in-atoti) ## What are the benefits of defining a partitioning strategy? Atoti automatically defines a partitioning strategy for both stores and aggregate providers. This is a best-effort approximation and works for some use cases. In addition, defining an explicit partitioning strategy gives control over the following: * **Multi-core performance**: An even distribution of records across partitions ensures that all cores are kept busy during both loading and querying. * **Parallel query execution**: Work is distributed across partitions, each processed by a separate thread, regardless of whether NUMA is involved. * **Data maintenance**: Updating data is done by partition. For example: removing all records for a given date is done by removing an entire partition instantly rather than scanning all records. * **NUMA locality**: Explicitly mapping partitions to NUMA nodes ensures that threads and their data stay physically co-located in memory, minimizing cross-node latency. * **Long-term stability**: A deliberate partitioning design accounts for how data will grow and evolve, and reduces the risk of skewed partitions or excessive partition counts over time. ## Which partitioning strategies does Atoti offer? ### Modulo-based partitioning * The number of partitions is determined upfront, usually based on the number of machine cores. * Provides an even distribution of data values across partitions. * Not optimal for housekeeping operations, as partitions are not aligned with specific data values. It is good practice to use modulo partitioning on all key fields, as this ensures balanced partitions. ### Value-based partitioning * Each unique value of a chosen field creates a partition. * Partition size depends on the amount of data per value. * Useful when loading data across multiple dates or categories. * Not optimal when the field has high cardinality (many unique values). Value-based partitioning is efficient when housekeeping is important, as entire partitions can be dropped instantly. performance-modulo-value-partitioning.png ## Related reading * [Partitioning with Atoti Java SDK](/engine/java-sdk/latest/concepts/partitioning#partitioning-functions) * [Partitioning with Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.Session.create_table) ## Which constraints affect partitioning? Two constraints must be respected when configuring partitioning. 1. Key field constraints * If a store has key fields, the partitioning fields must be included in those key fields. * If a store has no key fields, it can be partitioned on any of its dictionarized fields. 2. Store reference constraints * When a store references to another store, the partitioning of the referenced store is implied by the partitioning of the owner store. * All records in a given partition of the owner store must reference records in the same partition of the referenced store. * As a result, the referenced store has a number of partitions that is less than or equal to the number of partitions in the owner store. For **modulo partitioning**, the implication rule is as follows: modulo(M) is implied by modulo(N) if and only if N is a multiple of M. ## What is the optimal number of partitions? Atoti recommends configuring at least one partition per logical core. Modern processors use hyper-threading, which provides two logical cores per physical core. For this reason, the recommended minimum is twice the number of physical cores. For NUMA-aware applications, the minimum requirement is one partition per physical processor. However, using one partition per logical core is preferred, as it reduces contention between concurrently running threads. ## When is custom aggregate provider partitioning needed? By default, Atoti partitions aggregate providers to closely follow the datastore partitioning. This supports multithreaded performance at the cube level. There are two cases where overriding this may be necessary. **The optimal partitioning field is not on the base store.** Partitioning constraints require that partitioning fields belong to the base store or its key fields. If the field that would give the best distribution belongs to a referenced store, the base store cannot be partitioned on it directly. Defining a custom partitioning on the aggregate provider allows that field to be used at the cube level, independently of the store partitioning. **Query patterns differ from loading patterns.** A partitioning designed for efficient data loading may not distribute query work evenly across cores. For example, data is partitioned by date for faster loading, but queries consistently target a different dimension than the date dimension. A custom aggregate provider partitioning can better reflect those access patterns. > **Note**: Customizing aggregate provider partitioning adds cost to the commit phase. > Data may need to be scanned and re-routed to match the provider's partition layout, increasing commit time and transient memory usage while committing. # How to optimize Atoti performance Source: https://docs.activeviam.com/concepts/performance/performance-strategies How to identify the right Atoti performance strategy based on whether the bottleneck is in the data journey or query journey, covering aggregate providers, partitioning, virtual hierarchies, JVM tuning, aggregate cache, query plan, and query limits. Performance optimization follows four steps: * Understand the requirements * Understand the context * Understand the problem * Fine-tune the solution ## 1. Understand the requirements Clarify what matters most for the project. This ensures that optimization efforts remain focused. * Faster data loading * Faster query execution * Reduced memory usage * A balanced trade-off constrained by the available hardware Performance constraints ## 2. Understand the context Every Atoti deployment is different. Troubleshooting starts with gaining full visibility into: * The underlying data and data sources * The data model and datastore configuration * The aggregate providers and how the cube is used A solid grasp of this context helps identify potential bottlenecks and prevents unnecessary guesswork. ## 3. Understand the problem Performance issues rarely happen without reason. When performance changes, either suddenly or gradually, investigate what has recently changed: * new code or configuration updates, * increased data volume, * spikes in user activity, or * unexpectedly large or complex queries. Identifying the root cause helps address the actual issue instead of only addressing its symptoms. Performance causes ## 4. Fine‑tune the solution Once the problem is clear, refinements should be made methodically. Atoti tuning is most effective when performed in small, isolated steps: * Change one parameter or configuration at a time, * Test the impact immediately, * Observe the results, * Repeat as needed. This disciplined approach avoids cascading issues and makes it easier to understand exactly how each tuning lever affects performance. ## Which strategies can help optimize performance? The right strategy depends on the type of problem and the context of the project. Hardware constraints, such as available memory and CPU cores, set the boundaries within which all optimization decisions must operate. Most strategies involve a tradeoff between loading speed and query speed. This tradeoff is most visible in two areas covered in the data and query journeys: * **Aggregate providers**: pre-aggregating data during loading reduces the work required at query time. Queries run faster, but loading takes longer. * **Partitioning**: the partitioning strategy affects both how quickly data is written to the datastore and how efficiently queries read it back. Use the table below to identify potential performance optimization strategies. First, determine whether the performance bottleneck lies in the data journey (loading and transformation) or in the query journey (execution and resource usage). | Strategy | What it optimizes | When to use | For more details read the page | | ------------------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------- | ------------------------------ | | Column calculators | Data transformation during ingestion | When records need enrichment or filtering before loading (Java SDK only) | Load data | | Tuple publishers | Data loading flow | When controlling how transformed records are submitted to the datastore (Java SDK only) | Load data | | Partitioning and NUMA awareness | Loading speed and query performance | When data volume is large or query patterns are predictable | Data journey / Query journey | | Virtual hierarchies | Loading time and memory usage | When hierarchies have high cardinality and are not used for slicing or ordering | Virtual hierarchies | | JVM tuning | Memory allocation and garbage collection | When large datasets or frequent queries cause heap pressure or GC pauses (Java SDK only) | JVM tuning | | Aggregate cache | Query execution time | When the same queries are repeated frequently | Query journey | | Aggregates providers | Query execution time | When queries are slow and pre-aggregation during loading is acceptable | Query journey | | Query plan analysis | Query execution visibility | When a specific query is slower than expected | Query journey | | Query limits | Resource usage | When queries consume excessive time or memory | Query journey | # How to understand the query journey Source: https://docs.activeviam.com/concepts/performance/query-journey How Atoti executes MDX queries through GAQs and a computation graph, resolving measures from the aggregate cache, aggregate providers, datastore, or DirectQuery, and how the query plan and query limits affect performance. A query follows several steps before a result is returned. Each step affects performance. Understanding how these steps fit together helps identify where slowdowns occur and which optimizations to apply. **Prerequisites**: A basic understanding of measures, cube structure, and datastore loading is recommended before reading this section. ## How are queries executed by Atoti The primary query type in Atoti is the **MDX query**. When Atoti receives an MDX query, it parses the query and breaks it down into **Get Aggregates Queries (GAQs)**. Each GAQ requests one or more measures at a given set of locations. For each GAQ, Atoti computes a **query plan** that defines how the requested measures will be retrieved or calculated. ### Value retrieval The fastest method is to take the values from the aggregate cache. When this is not possible, the values are computed. #### Aggregate Cache The fastest option is to retrieve the measure value directly from the **Aggregate Cache**. This least-recently-used (LRU) cache stores location-measure combinations that were already computed by a previous query, keyed by cube version. If the requested combination is present in the cache, Atoti returns the result immediately without any further computation. #### Measure Computation If the value is not cached, Atoti computes the measure at the requested locations. Most measures are computed from other, simpler child measures. To do this, the Atoti engine builds a **computation graph** for the requested measure. The leaf nodes of this graph are the simplest possible measures, called **primitive measures**. These are defined as basic aggregations over the fact table. **Primitive measures** are resolved through one of the following: * **Aggregate Providers** — Aggregate Providers are materialized views that store pre-computed primitive measure values at a defined granularity. Unlike the Aggregate Cache, which holds recently used location-measure combinations on demand, Aggregate Providers are updated every time a data load is triggered. A location-measure combination can be resolved by an Aggregate Provider if the requested location is at the same granularity or at a coarser granularity than the provider. In the latter case, the query engine aggregates the relevant rows from the Aggregate Provider to produce the result, leveraging the provider's partitioning to skip irrelevant partitions and parallelize computation. * **Database** \-- **Datastore** — If no Aggregate Provider can resolve the combination, the engine falls back to the **Datastore**. The Datastore engine collects all fact records matching the requested location and aggregates them to produce the result. To locate the relevant records, the Datastore engine can use indexes when available; otherwise, it performs a full row scan. Like Aggregate Providers, the Datastore leverages store partitioning to skip irrelevant partitions and parallelize the operation. \-- **Direct Query** — When using an external database, the connector generates a SQL query to compute the aggregation directly from the external data source. Once all necessary primitive aggregations are available, the cube engine works back up the computation graph, computing each measure in order until all requested measures have been resolved. perf-query-journey.png ### MDX Result Assembly When all GAQs for an MDX query have been computed, the MDX query engine applies any MDX-level computations and assembles the final result as a **Cellset**, which is then returned to the caller. ### Query Plan A significant portion of MDX query execution is captured by the **query plan**. After a query executes, the query plan provides a detailed record of every step taken, including calculation order, execution times, result sizes, and retrieval methods. When a query performs slower than expected, the query plan is the primary diagnostic tool for identifying which step is responsible. ### Query Limits Users can define **limits** to enforce time and size constraints on the query execution process. ## Related reading * [Aggregates cache](./aggregates-cache) * [Aggregate providers](./aggregate-providers) * [Partitioning](./partitioning) * [Query-plan](./query-plan) # How query limits prevent resource overloads Source: https://docs.activeviam.com/concepts/performance/query-limits How Atoti query limits control resource usage by restricting query processing time, intermediate and transient result sizes, and concurrent MDX query counts to prevent overloads and keep dashboards responsive. Query limits help control resource usage by restricting the time and size of query execution. They prevent excessive memory consumption and long‑running queries that can impact overall system performance. ## Why use query limits * Avoid resource overloads: Large queries can consume significant memory and CPU. * Improve stability: Prevents the system from being blocked by expensive queries. * Ensure fairness: Keeps dashboards responsive for all users. ## What query limits can be set You can define limits for: * **Processing time:** Maximum time allowed for a query to run. * **Result size:** * **Intermediate limit:** Maximum number of results per retrieval step. * **Transient limit:** Maximum cumulative results across all steps. * **Concurrent Mdx queries:** Maximum number of Mdx queries that are process at the same time. ## When to use query limits Query limits are most effective when: * Dashboards contain complex widgets that require a high number of queries. * Users run queries with large cross‑joins. * You need to prevent accidental resource overloads. * You need to restrict the resource usage of group of users. Avoid setting limits too low, as this may cause valid queries to fail. ## Related reading * [Set query limits for Atoti Java SDK](/engine/java-sdk/latest/monitoring/monitoring_query_execution#configurable-limits-on-query-results) * [Set query limits for Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.Cube.shared_context#atoti-cube-shared-context) # How the query plan can help troubleshoot slow queries Source: https://docs.activeviam.com/concepts/performance/query-plan How the Atoti query plan records execution steps, dependencies, timing, result sizes, and retrieval methods for each query, and how to use the Atoti Query Analyser to diagnose slow queries. The query plan provides detailed information about how Atoti executes a query. It shows the steps taken, their dependencies, and the time required for each step. This helps identify bottlenecks and optimize query performance. performance-query-plan.png ## Why use the query plan * Diagnose slow queries: Understand which steps take the longest. * Identify dependencies: See how measures depend on each other. * Optimize partitioning: Check if the partitioning strategy is effective. * Detect issues: Spot cyclical measure definitions or excessive result sizes. ## What information does the query plan provide * **Dependencies:** Shows the calculation order for measures. * **Execution times:** * **Start time:** When a step begins. * **Elapsed time:** How long the step takes. * **Result size:** Number of points retrieved at each step. * **Partitioning strategy:** Indicates constant, value, or modulo partitioning. * **Retrieval method:** Whether data comes from cache, datastore, or post-processor. ## How to analyze the query plan * Look for long steps: High elapsed time indicates a bottleneck. * Check result size: Large result sets may explain slow performance. * Review partitioning: Ensure partitioning matches datastore configuration. * Identify retrieval type: * Cache retrieval = fast. * Primitive retrieval = datastore scan (slower). * Post-processor retrieval = additional computation. Use the [Atoti Query Analyser](https://activeviam.github.io/atoti-query-analyser/) to: * Upload query plan output. * Visualize dependencies and timing. * Spot problematic steps quickly. * Check when an aggregate provider is used. * Understand how a query is distributed in a horizontal setup. ## When to use the query plan The query plan is most useful when: * Dashboards or widgets load slowly. * Queries return fewer results than expected. * You suspect inefficient partitioning or retrieval methods. ## Related reading * [Query plan for Atoti Java SDK and Atoti Python SDK](/engine/java-sdk/latest/monitoring/query_execution_plan) # How virtual hierarchies can speed data loading Source: https://docs.activeviam.com/concepts/performance/virtual-hierarchies How Atoti virtual hierarchies reduce data loading time and memory usage by deferring member population to query time, when to use them for high-cardinality fields, and when to avoid them. Virtual hierarchies are an effective way to reduce data loading time and memory usage in Atoti. Instead of populating hierarchy members during data loading, a virtual hierarchy creates an empty structure. Member values are retrieved from the database or from an aggregate provider only when needed in a query. * **Faster data loading:** Large hierarchies with millions of distinct values can slow down loading. Virtual hierarchies skip member population at load time. * **Lower memory consumption:** Regular hierarchies store members in a tree structure. Virtual hierarchies do not build this tree, saving memory for high-cardinality fields. ## When to use virtual hierarchies Virtual hierarchies are best for: * High-cardinality hierarchies with non-repeating strings (e.g., Trade ID). * Hierarchies that are not used for slicing or ordering. * Scenarios where members are only needed for filtering or display in queries. Avoid using virtual hierarchies for: * Date hierarchies (ordering is required). * Slicing hierarchies (need a default member). * Use cases requiring next, previous, or lag operations. ## How to decide Ask these questions: * Does the hierarchy have very high cardinality? * Are the member values non-repeating strings? * Is the hierarchy used for slicing? * Is the order of the members in hierarchy important? * Will users need to filter on this hierarchy outside Atoti UI or Excel? Virtual hierarchies decision flow ## Related reading Find out how to set a hierarchy as a virtual hierarchy using: * [Atoti Java SDK](/engine/java-sdk/latest/concepts/dimensions_and_hierarchies#virtual-hierarchies) * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.Hierarchy.virtual#atoti-hierarchy-virtual) # What are one-off and continuous loading? Source: https://docs.activeviam.com/concepts/versions/one-off-vs-continuous How Atoti supports one-off and continuous data loading, including file-based watching, streaming query updates, long polling, and incremental refresh for DirectQuery, with source-by-source loading capabilities. Atoti supports both one-off and continuous data loading strategies to populate and update the datastore. One-off loading is ideal for static datasets or initial ingestion. Continuous loading ensures that updates are automatically detected and processed in real time or near real time. ## What is the difference between one-off and continuous loading? Understanding the difference between one-off and continuous loading helps choose the right strategy to balance performance and data freshness. | | One-off loading | Continuous loading | | ---------------------------- | ----------------------------------- | ------------------------------------------ | | **Purpose** | Initial ingestion or manual refresh | Automatic updates from changing data | | **Trigger** | Manual or scheduled | Event-driven or polling-based | | **Use cases** | Historical data and static datasets | Streaming dashboards and live monitoring | | **Performance impact** | Depends on dataset size | Depends on update frequency and volume | | **Monitoring and reporting** | Optional parsing reports | Optional parsing reports and stream events | ## How does Atoti detect changes for continuous loading? For file-based sources, Atoti uses a **Watcher service** that listens for file system events and reacts immediately when files are created or modified. This provides low-latency detection of changes. For message-based sources such as Kafka or JMS, data is pushed directly to Atoti as messages arrive, enabling continuous ingestion. ## What sources support continuous loading? Each source has its own capabilities and limitations when it comes to detecting and ingesting changes efficiently. The following categories show which sources support continuous loading, one-off loading, or both: ### One-off loading sources These sources are typically used for initial ingestion or manual refreshes. They do not support automatic detection of changes without external orchestration. * Flat files (e.g. CSV, Parquet): Loaded via fetch operations. * Relational databases (JDBC): Queries are executed to retrieve and load data. * Cloud platforms (e.g. BigQuery, Snowflake): Used for scheduled or batch-based loading. ### Continuous loading sources These sources support automatic updates and are designed for low-latency ingestion. * Flat files (e.g. CSV, Parquet): Monitored using polling or watcher service. * Messaging systems (e.g. Kafka, JMS): Designed for streaming ingestion. * Custom systems (APIs, platforms): Can be integrated to push updates continuously. ### Sources that support both Some sources can be configured for either one-off or continuous loading depending on the use case and integration method. * Flat files: Can be fetched once or monitored continuously. * Relational databases: Support one-off fetch and incremental refresh; continuous loading may require orchestration. * Cloud platforms: Typically used for scheduled loads but can be extended for continuous updates using external triggers. * Custom systems: Behavior depends on the integration; both loading types are possible. ## How does continuous loading work? Continuous loading in Atoti refers to the automatic detection and ingestion of new or updated data without manual intervention. It ensures that the datastore remains synchronized with external data sources in near real time. To help clarify the different mechanisms available, the following numbered list outlines the main approaches supported by Atoti for continuous loading. Each method serves a distinct purpose and applies to different types of data sources and integration patterns. * Atoti Python SDK uses other Python based libraries to manage some continuous loading * Atoti Java SDK has in built APIs ### 1. File-based continuous loading Use this approach when your data is stored in flat files such as CSV or Parquet. Files are monitored using: * **Polling**: Periodically checks file modification timestamps. * **Watcher service**: Listens for file system events and reacts immediately (for example a new file created in a folder). **When to use:** * When working with file-based data pipelines. * When you need low-latency updates and the file system supports event notifications (recommended: watcher service). * When you want a simple setup without external orchestration. > Note: When monitoring files for changes, be aware that Atoti will reload all lines, including those that are unmodified. > This is acceptable if a small percentage of the lines are unchanged. > However, if you only intend to modify or add a few lines, it's more efficient to place these lines in a new file. > This allows the system watcher service to detect its arrival. ### 2. Streaming query updates Use this approach when you need real-time updates to query results, such as in dashboards or alerting systems. Atoti’s Streaming API allows clients to: * Subscribe to a query once. * Receive updates automatically when the result changes. **When to use:** * When building interactive dashboards that must reflect live data. * When you want to avoid polling the server for query results. * When using Atoti UI or custom clients that support WebSocket communication. ### 3. Long polling for remote clients Use this approach when your client cannot maintain a persistent connection, such as in .NET environments or restricted networks. Long polling simulates streaming by: * Submitting a listen request. * Waiting for updates or timeout. * Resubmitting the request immediately. **When to use:** * When WebSocket is not available or not supported by the client. * When integrating with remote systems that require HTTP-based communication. * When you need to multiplex updates from multiple domains over a single connection. ### 4. Incremental refresh from external databases (DirectQuery only) Use this approach when your data is stored in an external database and you want to update specific rows. **Incremental refresh:** * Targets specific changes using conditions (e.g., by date or ID). * Supports multi-table updates. * Can use unknown conditions when precise scopes are not available. **When to use:** * When working with DirectQuery schemas. * When you want to avoid full reloads and reduce database load. ## Related reading Find out more about file based continuous loading by following these links: * **Atoti Java SDK** * [Listening to local files](/engine/java-sdk/latest/sources/csv_source#listen) * [Long polling](/engine/java-sdk/latest/cube/streaming_overview#long-polling) * [Streaming query updates](/engine/java-sdk/latest/cube/streaming_overview) * [Incremental refresh for DirectQuery](/engine/java-sdk/latest/directquery/how_to/incremental-refresh-how-to) * **Atoti Python SDK** uses other Python based libraries * [Listening to local files](https://docs.activeviam.com/engine/python-sdk/latest/guides/watching_local_files) # What are datastore transactions in Atoti? Source: https://docs.activeviam.com/concepts/versions/transactions How Atoti datastore transactions apply changes atomically, lock tables to maintain referential integrity, support isolated table concurrency, and expose timing metrics for monitoring throughput. Datastore transactions in Atoti are the mechanism for loading, updating, and removing data in a controlled and consistent way. They ensure that changes to the datastore are applied atomically and safely, maintaining data integrity across all tables and references. Transactions are essential because they: * Guarantee atomicity, isolation, and consistency. * Prevent partial updates that could leave the datastore in an inconsistent state. * Coordinate updates across joined tables. Without transactions, concurrent updates could lead to data corruption or broken references between tables. This in turn could lead to incorrect query results. ## How do transactions work in Atoti? Transactions allow multiple operations to be grouped into a single unit of work. This ensures: * **Atomicity**: All operations succeed or none do. * **Isolation**: Intermediate states are never visible to other users or processes. * **Consistency**: The datastore moves from one valid state to another. Transactions follow a clear workflow: 1. **Initial state**: All tables are unlocked. 2. **Start transaction**: When a transaction begins, the relevant tables are locked. * If specific tables are named, those tables and their referenced tables are locked. * If no tables are named, all tables in the datastore are locked. 3. **Perform operations**: Data is added, updated, or removed. 4. **Commit transaction**: Changes are flushed, locks are released, and other transactions can start. ### What happens when tables are locked? During a transaction, tables involved in the operation are locked.\ This prevents other transactions from starting on those tables until the current transaction is committed.\ Locking ensures that references between tables remain consistent during updates. ### How do isolated tables behave? * Isolated tables are not joined to the base table. * Transactions on isolated tables do not affect other tables. * Multiple transactions can run concurrently if they involve isolated tables. ## Can transaction timings be monitored? Atoti provides monitoring tools to track transaction performance: * **Transaction timings**: Measure how long transactions take from start to commit. * **Metrics**: Help identify bottlenecks in data loading or updates. Monitoring is essential for optimizing throughput and ensuring smooth real-time updates. ## Related reading Find out more about transactions by following these links: * [Atoti Java SDK](/engine/java-sdk/latest/datastore/datastore_transactions) * [Atoti Python SDK](https://docs.activeviam.com/engine/python-sdk/latest/api/atoti.Session.data_model_transaction) # How Atoti manages data versioning Source: https://docs.activeviam.com/concepts/versions/versions How Atoti manages data versioning for the database and the cube using versions, epochs, and branches in the in-memory datastore, and how DirectQuery versioning depends on external database time-travel support and manual refresh. ## What is a version? A version represents a snapshot of the available data at a specific point in time. Versions allow data from different points in time to be accessed. And therefore helps manage multiple states of data for comparison and simulation. ## How are versions created? Versions are created automatically by Atoti. There is a latest version for the database and a version for the latest version of a cube. * For a **database**: The database stores data. Every time data is loaded, inserted, or deleted, a new version is created. * For a **cube**: The cube queries a set of data in the database. Every time that data is updated, a new version is created. For example; a database contains 10 columns of data. A cube queries only 5 of those columns. When the database is updated, the cube version is updated only if the update affects the 5 columns that the cube queries. Therefore: * When a cube queries all the columns in the database, the cube version is identical to the database version. * When a cube queries only a subset of the columns in the database, the cube version may differ from the database version. * When a database is queried by more than one cube, each cube may have a different version of the database, depending on which columns the cubes query. ## How are different versions of data queried in the cube? Every cube has a dimension that allows users to select the version of data they want to query. This dimension is called the **epoch dimension**. The default value for this dimension is the latest version of the data. Users can select a previous version of the data to query by selecting a different value in the epoch dimension. Atoti allows users to configure the number of versions to keep in the cube. When the maximum number of versions is reached, the oldest version is deleted when a new version is created. ### How can versions be used for simulations? Versions can be used to perform simulations by creating branches of the data. A branch is a copy of a version that can be modified independently of the original version. This allows users to test different scenarios without affecting the original data. Branches are useful for performing simulations: * Testing changes without impacting the original version. * Creating alternative scenarios. ## How are different versions of data managed in the database? Data versioning is implemented differently depending on whether you use the Atoti datastore or access an external database using DirectQuery. * Atoti in-memory datastore natively manages data versioning * With DirectQuery, data versioning is dependent on the external database's native support. ### Versioning in the Atoti datastore When data resides in the Atoti Datastore, versioning is provided natively by Atoti. * Each committed transaction creates a new version of the datastore. The new version can be queried using the epoch dimension. * Epochs allow for auditing and rollback. * Branches are fully supported and provide an isolated workspace for simulations without affecting the main data. * Branches can be compared directly with the base version or with other branches to evaluate the impact of changes, forming the basis of Atoti’s what‑if analysis. ### Versioning with DirectQuery With DirectQuery, Atoti reads data directly from an external database and maintains internal snapshots to support hierarchies and aggregates. Versioning capabilities depend on the external system: * If the external database supports native time travel, Atoti can query historical snapshots. * If the external database does not support native time travel, only the latest snapshot is available. External databases cannot push change events to Atoti, so users must explicitly trigger refreshes. This is managed by the DirectQuery connector. * If the external database supports native time travel: Atoti can query consistent historical snapshots directly, so cube components stay in sync between refreshes. * If the external database does not support native time travel: Atoti relies on its own internal snapshot, so cube components (hierarchies, aggregate providers) can become temporarily out of sync until a refresh is performed. ### Further reading Find out more about data versioning: * [Atoti Java SDK](/engine/java-sdk/latest/concepts/data_versioning) * For an introduction to [DirectQuery](../load-data/DirectQuery.md) read this page. Keep DirectQuery data up to date using Atoti Java SDK: * **Incremental refresh**: A specific scope of data is updated. * **Full refresh**: All the data from the external database is updated. DirectQuery does not support branches. Any simulations that require branches must use the Datastore. ## Summary: Datastore vs. DirectQuery | Capability | Datastore | DirectQuery | | -------------------------------- | ----------------------------------------- | ---------------------------------------------------------------------- | | Historical versions available | ✔️ Natively provides consistent snapshots | ✔️ Only if external DB supports time travel; otherwise latest snapshot | | Epochs within versions | ✔️ Fully supported | ⚠️ Behavior depends on external DB’s capabilities | | Branches for simulations | ✔️ Fully supported | ❌ Not supported | | How changes are ingested | Automatic via transactions | User‑triggered Incremental or full refresh | | Cube availability during updates | ✔️ Yes | ✔️ Yes (during both incremental and full refresh) | | Risk of desynchronization | Low | Medium for non‑time‑travel databases until refresh completes | # How to connect to the Atoti Hub MCP server Source: https://docs.activeviam.com/connect-mcp-server Connection instructions for the Atoti Hub MCP server, covering Claude, Claude Code, Cursor, and VS Code with GitHub Copilot The Atoti Hub houses the documentation for all Atoti products. It is a useful source of information for developers and coding agents working with Atoti products. The Atoti Hub MCP Server is hosted at `https://docs.activeviam.com/mcp`. When connected to an AI coding agent, it enables the agent to search and retrieve documentation content directly. ## Prerequisites * An AI coding tool with MCP support, such as Claude, Claude Code, Cursor, or VS Code with GitHub Copilot * Access to Atoti products * An active internet connection In some environments, the domain `https://docs.activeviam.com` must be added to the network allowlist before the Atoti Hub MCP server can be reached. ## What are the connection details? | Setting | Value | | ---------- | -------------------------------------------------------------- | | Server URL | `https://docs.activeviam.com/mcp` | | Transport | HTTP (also called "streamable HTTP" or "remote" in some tools) | The setup steps are similar across tools: add the server URL as a remote MCP server using the tool's MCP configuration. Refer to each tool's documentation for the specific steps: * [Claude custom connectors](https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp) * [Claude Code MCP](https://code.claude.com/docs/en/mcp) * [Cursor MCP](https://cursor.com/docs/mcp) * [VS Code MCP](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) * For other tools, consult the tool's documentation directly In Claude Code, the Atoti Hub MCP server can be added directly from the terminal: ```bash theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} claude mcp add --transport http activeviam-docs https://docs.activeviam.com/mcp ``` ## How to verify the connection Once connected, ask the agent a question about Atoti products. The response should include content drawn from the documentation on the Atoti Hub, such as page titles or references to docs.activeviam.com. ## What tools does the Atoti Hub MCP Server provide? The Atoti Hub MCP Server exposes two tools that connected agents use automatically: * **Search**: Searches across the documentation to find relevant content, returning snippets with titles and links. Agents use this tool to discover information or find pages matching a query. * **Query docs filesystem**: Reads and navigates the documentation structure using shell-style commands. Agents use this tool to retrieve full page content, browse the docs structure, or extract specific sections. These tools are designed to be used together: the Search tool finds relevant pages, and the Query docs filesystem tool retrieves their full content. ## Next steps and related reading * [Claude custom connectors](https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp) * [Claude Code MCP](https://code.claude.com/docs/en/mcp) * [Cursor MCP](https://cursor.com/docs/mcp) * [VS Code MCP](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) * [Model Context Protocol specification](https://modelcontextprotocol.io) # Atoti Hub Source: https://docs.activeviam.com/index Find user guides, developer guides, API references, tutorials, and more.
# Atoti Hub

Documentation, video tutorials, and other learning resources for Atoti. Everything you need, in one place.

Documentation

# Atoti Limits overview Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/introduction-to-atoti-limits A limits management system for financial services that lets you create, update, and approve risk limits directly within your analytics environment, with tools to investigate and report on breaches. # What is Atoti Limits? Atoti Limits is an optional add-on for Atoti applications. It provides a centralized solution for defining, monitoring, and investigating risk limits. This page is intended for users familiar with Atoti applications and risk management concepts. Atoti Limits is designed for banks, hedge funds, and asset managers. It supports real-time control of limits across all organizational levels. ## Why use Atoti Limits? Managing risk limits across trading desks requires complex aggregation calculations, often evaluated in real time. When a breach alert is raised, the data needed to investigate it is frequently scattered across multiple systems, making analysis slow and increasing operational risk. Atoti Limits addresses both problems in a single solution. Key benefits include: * Centralized definition and monitoring of limits at every aggregation level. * Immediate access to related analytical data during breach investigation. * A configurable workflow that controls limit creation, updates, and approvals. * Support for user-defined limits to enable management by exception. * Integration with existing organizational hierarchies and processes. ## Who is Atoti Limits for? Atoti Limits is used by risk and control teams across the organization. Typical users include: * Operations and control risk teams. * Analysts and traders. * Desk heads and risk managers. Common use cases include: * Monitoring risk limits across desks and asset classes in real time. * Investigating breach alerts by drilling down to underlying data. * Adjusting limits without direct IT involvement. * Ensuring compliance with internal risk policies and regulatory requirements. ## How does Atoti Limits work? Atoti Limits creates a dedicated limits cube within the Atoti application. This cube connects to all other analytical cubes, providing direct access to the relevant data when investigating a breach alert. Limits are evaluated at every aggregation level using the Atoti query engine, ensuring that no potential breach is missed. A configurable workflow system controls who can create, modify, and approve limits. This supports governance while allowing business users to adapt limits as conditions change. ## What is the relationship to other Atoti products? Atoti Limits is an add-on to an existing Atoti application. Atoti Limits is commonly used with: * **Atoti Sign-Off**, which manages end-of-day data validation and approval. * **Atoti Scenario Analysis**, which supports hypothetical and stress testing analysis. Atoti Limits and Atoti Sign-Off are often deployed together. This combination supports both intraday limit monitoring and end-of-day control processes. # Release and upgrades Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases Release and upgrade documentation for Atoti Limits, covering version-specific release notes, changelog entries, and step-by-step migration guidance * [Release notes](./releases/release-notes) * [Changelog](./releases/changelog) * [Migration guide](./releases/migration-guide) # Changelog Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/changelog For user-facing changes, see the [Release notes](./release-notes). For information on upgrading from previous versions, see the [Migration guide](./migration-guide). ### Changed * PIVOT-14310: The incident SSE subscription (`GET /limits/sse/v2/incidents/subscribe/filter`) and the notification service SSE subscription now carry `X-Accel-Buffering: no` and `Cache-Control: no-cache, no-transform` so that reverse proxies do not buffer or compress the event stream. A buffering proxy delivers the incident and notification updates only when the stream ends. ### Removed * PIVOT-14667: The `Dependencies` page has been removed from the release documentation because the dependencies are now aligned with the Atoti Server version. See the [Atoti Server dependencies](https://docs.activeviam.com/products/atoti/server/latest/docs/release/dependencies/) page for the underlying Spring Boot and Java versions. ### Fixed * LIM-2278: Fixed limit evaluation considering only the default member for scopes on a slicing hierarchy (no AllMember level); every matching member, including multi-level Total subtotals, is now evaluated. * LIM-2346: Fixed a limit defined at the `(Total)` of a multi-level hierarchy's first level (for example a dynamic tenor hierarchy) not applying to the Total row, which showed no limit status. * LIM-2352: Fixed the Audit Screen reporting a spurious change (for example `100 → 100`) when an unchanged numeric value was deserialized as a different numeric type, such as `Integer` and `Double`. * LIM-2370: Querying a limit KPI (Goal or Status) on a recently created calculated measure would throw an `IllegalArgumentException: Unknown measure contributors.COUNT`. * LIM-2171: Fixed Limit Structures with no Limits minting a duplicate Scope Value ID instead of reusing the existing "N/A" ID, which could crash the scope cache with a duplicate-key error. * LIM-2366: Fixed the log filling with `ERROR`-level stack traces for every `AccessDeniedException`, which now logs at `DEBUG` while other exceptions still log at `ERROR`. * LIM-2365: Fixed the `Mismatch for scope locations` error not naming which limits caused a limit structure to fail loading; it now names the structure, the two limits, and the missing level. * LIM-2428: Fixed querying a limit KPI (Goal or Status) throwing a `NullPointerException` when the as-of date fell outside the date range of the limits covering the queried location. * LIM-2355: Fixed the Audit Screen showing no entry for a breach review or other workflow-engine task, leaving only the object's creation entry. * LIM-2388: Fixed approving an update or deletion of a limit with an existing attachment failing with an error, which could leave Atoti Limits unable to restart. * LIM-2358: Fixed workflow buttons ("Approve", "Reject", "Review breach") being enabled without the required permission, showing an "Access Forbidden" error on click instead of being disabled. ### Added * LIM-2228: Added a first-class Atoti Limits plugin for the Atoti Python SDK (`atoti-limits`), replacing the existing Atoti Limits Python extension as the way to connect an Atoti Python session to a running Atoti Limits server. * LIM-2350: Fixed a limit's ID being reused by a new limit created with the same scope after a restart, which merged their audit histories. New limits no longer reuse a soft-deleted limit's ID, so their audit histories stay separate. ### Fixed * LIM-2364: Fixed creating a limit structure on a recently created calculated measure failing validation with `Measure ... not in the list of measures for the cube`. * LIM-2348: Fixed the audit history and decision buttons failing to open for expired, deleted-and-recreated, or fully-approved six-eyes limits. Those steps now simply show no available actions. # Migration guide Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/migration-guide Step-by-step migration guidance for upgrading Atoti Limits, covering property changes, dependency updates, data model changes, and configuration updates required for each version # 6.1.23 to 6.2.0 Atoti Limits now requires Java 25. Update your project to build and run with Java 25. Spring Security Kerberos is now published in the `org.springframework.security` group, and released with Spring Security itself. If your project declares a `spring-security-kerberos-*` dependency of its own, for instance to set up [Kerberos machine-to-machine authentication](../dev/dev-extensions/custom-mtm-authentication/custom-kerberos-mtm-authentication), change its `groupId` to `org.springframework.security` and drop its version, which Spring Boot's dependency management now provides. The 2.x releases of the retired `org.springframework.security.kerberos` group are compiled against `org.springframework.security.crypto.codec.Base64`, a class Spring Security 7 removed, so authenticating a request with them fails at runtime with `java.lang.ClassNotFoundException`. No code migration is necessary. # Previous versions Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions Release documentation for previous supported releases of Atoti Limits, including release notes and migration guides Here you can find release notes and migration notes for previous releases of Atoti Limits that are still supported. * [6.1](./previous-versions/6.1) * [4.2](./previous-versions/4.2) * [4.1](./previous-versions/4.1) * [4.0](./previous-versions/4.0) * [3.3](./previous-versions/3.3) * [3.2](./previous-versions/3.2) * [3.1](./previous-versions/3.1) # 3.1 Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/3.1 * [Release notes and changelog](./3.1/release-notes-3.1) * [Migration notes](./3.1/migrate-3.1) # Migration notes Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/3.1/migrate-3.1 This page explains the changes required to migrate to the stated version of the Atoti Limits. ## Migrate to 3.1.0 Upgrading from version *3.0.0*, see the [Atoti Limits 3.1.0 Release Notes](../../release-notes#310). Atoti Limits is using Atoti Server 6.0.9 and Atoti UI 5.1.x. For new features and fixes included in these releases, please see the [Atoti UI documentation](https://docs.activeviam.com/products/atoti/ui/5.1/) and [Atoti UI Migration Notes](https://docs.activeviam.com/products/atoti/ui/5.1/docs/changelog), and the [release notes for Atoti Server](https://docs.activeviam.com/products/atoti/server/6.0.9/docs/release/changelog/index.). ### Headline announcement * **Modified UI settings** : “utilizationDashboards” has been removed. “exceptionAuditTrailNodeColors” has been removed, use “auditTrailNodeColors” instead. * **Custom User Workflow Actions**: Any existing custom user workflow actions may need to be modified. Please see `Adding Customizing Workflow Tasks` for how to do so. * **Upgraded Java version**: We have upgraded the Java version used to compile Atoti Limits to 17. * **Spring Security upgrade**: We have upgraded Spring Security to version 5.8.7 to resolve vulnerabilities and prepare for the upgrade to Spring Security 6.0 (via Spring Boot 3). * **Common Parent POM**: The Atoti Limits module now inherits third-party plugin versions from the Common Parent POM version 1.2.0, in line with other solutions. * **Interface/REST Service method signature changes**: We have upgraded the `IAlertTaskManager` and `LimitsEvaluationRestService` methods to provide a cleaner API. #### Java Upgrade We have upgraded the Java version used to compile Atoti Limits from 11 to 17. You will need to upgrade to Java version 17 or higher, and supply the following jvm arguments when running Atoti Limits: ```shell theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED ``` This is related to the [Atoti Server configuration](https://docs.activeviam.com/products/atoti/server/6.0.9/docs/configuration/java17/#jvm-options). #### Spring Security Upgrade We have upgraded to Spring Security 5.8.7. To do so, we override the version of Spring Security in Spring Boot by importing the `common-dependencies-bom` version 1.2.0 into the parent pom file. The `common-dependencies-bom` overrides the Spring Security version using Spring’s migration guide. You will eventually need to migrate your own custom security configuration(s) in preparation for Spring Security 6.0. We have upgraded our out-of-the-box security configurations to help in this migration. We recommend using your own custom security configuration(s) and referring to the out-of-the-box security configuration provided only as a sample. The default security users and roles have not changed, only the way we implement the security. We have done so by making the following changes: ##### Stop Using `WebSecurityConfigurerAdapter` We have replaced instances of `WebSecurityConfigurerAdapter` with `SecurityFilterChain` beans. ##### Use the new `requestMatchers` methods In Authorize Http Requests, we have replaced invocations of `http.authorizeHttpRequests((authz) -> authz.antMatchers(...))` with `http.authorizeHttpRequests((authz) -> authz.requestMatchers(...))`. ##### Use the new securityMatchers methods We have replaced invocations of `http.antMatchers(...)` with `http.securityMatchers(...)`. As an example of the previous changes, the configuration for accessing the endpoint which exposes the JWT token changed from: ```java theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} @Configuration @Order(1) public static abstract class AJwtSecurityConfigurer extends WebSecurityConfigurerAdapter { @Autowired protected ApplicationContext context; @Autowired @Qualifier(BASIC_AUTH_BEAN_NAME) protected AuthenticationEntryPoint authenticationEntryPoint; @Override protected void configure(final HttpSecurity http) throws Exception { http .antMatcher(JwtRestServiceConfig.REST_API_URL_PREFIX + "/**") // As of Spring Security 4.0, CSRF protection is enabled by default. .csrf().disable() // Configure CORS .cors().and() .authorizeRequests() .antMatchers("/**").hasAnyAuthority(ROLE_USER) .and() .httpBasic().authenticationEntryPoint(authenticationEntryPoint); } } ``` to ```java theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} @Bean @Order(1) public SecurityFilterChain jwtSecurityFilterChain(HttpSecurity http, final ApplicationContext applicationContext){ final AuthenticationEntryPoint basicAuthenticationEntryPoint = applicationContext.getBean(BASIC_AUTH_BEAN_NAME,AuthenticationEntryPoint.class); return http // As of Spring Security 4.0, CSRF protection is enabled by default. .csrf(AbstractHttpConfigurer::disable) // Configure CORS .cors().and() .securityMatcher(url(JwtRestServiceConfig.REST_API_URL_PREFIX,WILDCARD)) .authorizeHttpRequests( auth->auth.requestMatchers(HttpMethod.OPTIONS,url(WILDCARD)) .permitAll() .anyRequest() .hasAnyAuthority(ROLE_USER)) .httpBasic(basic->basic.authenticationEntryPoint(basicAuthenticationEntryPoint)) .build(); } ``` ##### Removed imports of `ActivePivotRemotingServicesConfig` This class imports `org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter`, which may (if used) expose access to [CVE-2016-1000027 in the Spring-web project](https://github.com/spring-projects/spring-framework/issues/24434). #### Common Parent POM The Common Parent POM version 1.2.0 is now a parent of the Atoti Limits module. This parent merely defines plugin management and is used by other solutions. The following dependency versions are now managed by this parent instead of by the Atoti Limits module:
DependencyVersion
exec-maven-plugin3.1.0
lifecycle-mapping1.0.0
maven-assembly-plugin3.6.0
maven-clean-plugin3.3.1
maven-compiler-plugin3.11.0
maven-dependency-plugin3.6.0
maven-deploy-plugin3.1.1
maven-enforcer-plugin3.3.0
maven-jar-plugin3.3.0
maven-javadoc-plugin3.5.0
maven-resources-plugin3.3.1
maven-source-plugin3.3.0
maven-surefire-plugin3.1.2
maven-war-plugin3.4.0
sonar-maven-plugin3.9.1.2184
spring-boot-maven-plugin2.7.16
#### Interface/REST Service Method Signature Changes If you implement or override any of the following interfaces/services, you will have to update your method signatures. ##### IAlertTaskManager
ModificationOld ValueNew ValueDescription
Changed valuevoid addChronFutureJob(KpiAlertTask.KpiTaskKey kpiKey)void addChronFutureJob(LimitStructureDTO limitStructureDTO)Schedule a limit structure to be evaluated.
Changed valueboolean removeChronFutureJob(KpiAlertTask.KpiTaskKey kpiKey)boolean removeChronFutureJob(String futureKey)Remove a scheduled limit structure to be evaluated from the list of scheduled jobs.
Changed valueCsvResult evaluateKpisFor(KpiAlertTask.KpiTaskKey kpiKey, ICondition condition)Collection\ evaluateLimitStructure(LimitStructureDTO limitStructureDTO)Evaluate a limit structure.
Changed valuevoid evaluateKpis(Collection\ kpiAlertTasks)Collection\ evaluateLimitStructures(Collection\ kpiAlertTasks)Evaluate multiple limit structures.
Changed valuevoid evaluateLimits(Collection\ limitAlertTasks)Collection\ evaluateLimits(Collection\ limitAlertTasks)Evaluate multiple limits.
Changed valuevoid writeFile(CsvResult csvResults, String fileName, String serverName)void writeFile(List\ results, String fileName, String serverName)Write the results of an evaluation to file.
Changed valueboolean containsChronFutureJob(KpiAlertTask.KpiTaskKey kpiKey)boolean containsChronFutureJob(String futureKey)Whether or not a scheduled job exists for the given key.
AddedMdxRunner getMdxRunner()Return the MdxRunner used to run MDX queries against the business cube.
AddedIEvaluationErrorHandler getErrorHandler()Return the IEvaluationErrroHandler used to handle errors on evaluation.
Removed\ CsvResult collectCsvResults(Collection\ alertTasks)Collect and handle the result of an evaluation.
### Input file formats #### Modified
ModificationFileFieldDescription
Addedlimit\_structures.csvUtilization Dashboard IDThe column Utilization Dashboard ID has been added between the Exception Workflow and User ID columns.
Addedlegacy\_limits.csvUtilization Dashboard IDThe column Utilization Dashboard ID has been added between the Exception Workflow and User ID columns.
### Configuration files #### Files Modified ##### limits.properties New properties:
Property NameCommentValue
ap.version.mapAny connected server version is now registered by Atoti Limits.
content.server.nameThe name given to the content server used by Atoti Limits.
##### [application.yml](../../../user-ref/properties/property-files/application-yml) New properties:
Property NameCommentValue
limit.evaluation.include-passesIf true, Atoti Limits stores passes (i.e. evaluations that do not result in a breach or warning) in the datastore during limit evaluation. The default value of false prevents a large number of passes from polluting the limit status screen in the UI.false
limit.evaluation.error.include-stacktracetrue if the stack trace should be available in the evaluation response to the UI.false
### Datastores #### Modified stores
ModificationStoreFieldTypeDescription
AddedLimit StructuresUtilization Dashboard IDstringThe ID of a utilization dashboard that may exist for the limit structure. The ID maps to a dashboard ID in the content server.
AddedIncidentsLimit Valuesdouble arrayThe value of the limit (KPI goal) at the time it was evaluated. Note that this may be the value of a temporary limit.
DeletedIncidentsBreach CountintUnused column that previously stored the number of breaches.
UpdatedIncidentsAs of Datelocal dateThe column is now a key field. This is to ensure that incident workflows are distinct for each as of date. The type has also been updated to a local date.
### Cube schema Each hierarchy has been given a suitable dimension, as opposed to having single-level hierarchies where the dimension is of the same name. You can view these in [Dimensions](../../../user-ref/cube/dimensions). The following modifications have also been made: #### Added
CubeDimensionHierarchyLevelsDatastore fieldsDetails
LimitsEvaluationAs Of DateAs Of DateAs Of DateThe cube date for an evaluation.
LimitsEvaluationEvaluation StatusEvaluation StatusIncident TypeThe result of an evaluation.
LimitsEvaluationWorkflow StatusWorkflow StatusStatusThe current status of an evaluation result in the workflow.
LimitsEvaluationEvaluation DateEvaluation DateN/AThe date of an evaluation.
LimitsEvaluationEvaluation KeyEvaluation KeyincidentKeyUnique key to identify an evaluation.
### Measures #### Added
CubeMeasureDetails
LimitsUtilizationThe utilization of a limit on evaluation.
### Context values No changes. # Release notes and changelog Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/3.1/release-notes-3.1 For information on upgrading from previous versions, see the [Atoti Limits Migration Notes](./migrate-3.1) Download the distribution files [here](https://activeviam.jfrog.io/artifactory/activeviam-accelerators-artifacts/limits/3.1.0/) You can download the following zipped distribution files: * **UI source code** * **UI build** * **Source files** to build the module * **Sample bookmarks** * **Maven repository** required to build the project and run the tests. The Atoti Server 6.0.9 Maven repository files can be downloaded from [here](https://artifacts.activeviam.com/share/ActivePivot_stable/6.0.9/). ### Summary * **Improved table filtering** : Filters have been moved to the column headers and have been extended to more columns, including the **Location** and **Scope** of a limit. * **Status screen** : The **Breaches** screen has been renamed **Status**. It has also been enhanced to allow you to view the utilization of passed limits if they are stored. * **Linked dashboards** : A dashboard can be linked to a limit structure to let you view the utilization for a given limit. Viewing the utilization of an incident will apply scope and as of date filters to the dashboard. * **Added Utilization** : The [Utilization measure](../../../user-ref/cube/utilization) has been added to the Limits cube. This measure can be [extended](../../../dev/dev-extensions/custom-utilization) by clients. * **Custom User Workflow Actions Improvements** : We have simplified the addition of custom user actions in workflows. Please see `Adding Customizing Workflow Tasks`. * **Upgraded Java version**: We have upgraded the Java version used to compile Atoti Limits to 17. As a result, we have removed the sample Atoti Server 5.10 from our distribution, as it does not support Java 17. **Atoti Limits is still compatible with this version.** * **Updated Atoti Server and Spring Boot dependency versions**: Updated the version of Atoti Server that Atoti Limits runs on to 6.0.9 and Spring Boot version to 2.7.16. * **Spring Security upgrade** : We have upgraded Spring Security to version 5.8.7 to resolve vulnerabilities and prepare for the upgrade to Spring Security 6.0 (via Spring Boot 3). * **Common Parent POM**: The Atoti Limits module now inherits third-party plugin versions from the Common Parent POM version 1.2.0, in line with other solutions. Details can be found in [the migration notes](./migrate-3.1#common-parent-pom). ### Known issues
Issue KeyDetails
BAS-1330Deleting the last limit value deletes the limit structure. As a workaround, don’t delete all limits on a limit structure unless you are sure that the structure won’t be used again. Alternatively, if you do need to reuse the structure, you can create a limit on it using the endpoint /modules/limits-module/limits/rest/v2/limitDefinition/limits/save. The key of the limit structure will still be visible in the admin-ui.
LIM-846Complex Scopes: Currently, a limit with an aggregated scope and a limit with a non-aggregated scope cannot be created on the same limit structure. As a workaround, create the limits on two separate structures.
LIM-840Complex Scopes: Currently, limits can’t be defined with an aggregated scope location and another scope location. As a workaround, create two separate limits on two separate structures.
LIM-813Managers can incorrectly upload Limit Structures through the REST endpoint.
LIM-594Having email notifications enabled for breaches causes decreased limit evaluation performance. See Configuring the breach email on how to disable breach emails.
LIM-357The Six Eyes workflow is currently not implemented.
LIM-346Limits on calculated measures only work through File Upload, not through the UI.
LIM-320Calculated measures need to be included in Pivot Table Query in order to view a Limit’s KPI in the Pivot Table. See Measures for more on how to create a query for Limits on calculated measures.
### Dependency versions
ComponentVersion
Atoti Server6.0.9
Atoti UI5.1.x
Data Connectors4.0.1-AP6.0
JavaJDK17
UI Components5.0.27
Unlike other solutions or modules, Atoti Limits requires Atoti UI version **5.1.2** or higher. ### Added
Issue KeyDetails
BAS-1514Updated the README.md files in the parent and starter modules.
BAS-1537When attempting to auto-configure Atoti Limits we now only log the connection exception at debug level to avoid polluting the logs.
LIM-823Added utilization dashboard ID field to the limit structure. This allows you to link a limit structure with a dashboard based on its ID in the content server.
LIM-848Updated the version of Atoti Server that Atoti Limits runs on to 6.0.7 and Spring Boot version to 2.7.14 to patch CVE-2023-20883 and CVE-2023-33008.
LIM-863Added the option to store passes when evaluating limits.
LIM-870Added a utilization measure to the Limits cube.
LIM-872Created read-only REST endpoints to get row entries for the Limits Status screen.
LIM-879Created REST endpoints to update non-key fields of a limit structure.
LIM-901Upgraded Java version used to compile Atoti Limits from 11 to 17.
LIM-905Added an endpoint to query the distinct as of dates for limit evaluations.
LIM-907Upgraded to Spring Security 5.8.7 to resolve CVEs and prepare for the upgrade to Spring Security 6.0 (via Spring Boot 3).
LIM-908Added an endpoint to return if the user is storing passes when evaluating limits.
LIM-910Improved support for custom user actions in workflows.
LIM-911Added a hook for custom workflow keys to execute user actions.
LIM-916Upgraded Spring Boot to version 2.7.16 by inheriting from the Common Parent POM version 1.2.0.
LIM-923Workflows for limit evaluations now exist for distinct as-of-dates.
LIM-943Updated the version of Atoti Server that Atoti Limits runs on to 6.0.9.
LIM-946Updated the version of the solutions-tools-bom to 2.0-AS6.0 to support Java 17 and Atoti Server 6.0.9.
LIM-956Added a new endpoint /inventory-structures/filter to reduce the amount of data sent to the limits inventory screen.
UIACL-577Added the action to inspect the utilization from the Inventory and Status screens.
UIACL-592Added ANTD built-in table filtering for the Limits screens.
UIACL-623Renamed the Breaches screen to Status screen and added ability to fetch all passed limits.
UIACL-671Enabled the workflow action button for authorized users only.
UIACL-680Enabled sticky headers in the limits tables.
UIACL-737Results are now cached for a minute inside the Status screen to prevent constant loading when browsing.
### Changed
Issue KeyDetails
LIM-827Changed the limit type from String to an enumeration LimitType that allows only “OFFICIAL” and “TEMPORARY” values.
LIM-912Renamed the LimitWorkflowActionDTO to WorkflowTaskActionDTO and updated it to improve custom workflow actions on the UI.
LIM-934Updated the version of Atoti Server that Atoti Limits runs on to 6.0.9.
UIACL-654Replaced limit column action buttons with icons and a tooltip.
UIACL-659Re-arranged the Status screen columns.
UIACL-690Renamed the Workflow section to Review Process and updated the labels within the limit structure viewer.
UIACL-707Rows are no longer de-selected when changing client-side filters.
UIACL-714When creating a limit structure, the breach when field is disabled when the kpi type is not selected.
### Removed
Issue KeyDetails
UIACL-580Removed the “utilizationDashboards” limit setting. Utilization dashboards can be added to the limit structure directly in the UI instead.
UIACL-640Removed server and cube columns from the Inventory screen.
UIACL-685Removed the “exceptionAuditTrailNodeColors” limit setting. The “auditTrailNodeColors” should be used instead.
### Fixed
Issue KeyDetails
BAS-1437Incident files on deleted limits no longer break the status screen on startup.
BAS-1449Equivalent scope strings now generate the same Limit keys.
BAS-1463UI evaluation now correctly evaluates servers where the server keys don’t equal the server name.
LIM-740Evaluating a limit structure containing only expired limits or structures with no data results in an error.
LIM-815Limit structures loaded without limits will now load successfully, limits loaded without limit structures and incidents loaded without limits will be skipped.
LIM-854The Status screen now shows the value of the active temporary limit, instead of the official limit.
LIM-856The value of the discovery-manager.polling-delay property is now used.
LIM-857Connecting to Atoti Server version 5.x. generated useless logs.
LIM-869An error occurred if the incident directory didn’t exist.
LIM-894Limits of the same structure with mismatching scope levels will now be skipped on loading so they don’t break the limits management screen.
LIM-913New limits can now be correctly created after deleting a complex scoped limit.
LIM-914Incidents that fail workflow validation appear in the status screen.
LIM-922Workflow action buttons are no longer visible for deleted limits.
LIM-925The breach audit history endpoint no longer contains details about limit changes.
LIM-926Fixed a bug which prevented editing limits when the order of scopes posted in the UI request was different to the order retrieved from the datastore.
LIM-927Improved the exception handling on Limit evaluation.
LIM-936Workflow action buttons are no longer returned if they are disabled.
LIM-954Limits evaluated by managers are no longer visible in the status screen.
LIM-955Explicit scope matches on limits are now not over-ruled by temporary limits.
LIM-957Fixed the date-roll endpoint which was not correctly updating the as-of-date.
UIACL-593The limits table was not displayed correctly when a limit structure didn’t contain any limits.
UIACL-669The Select all checkbox now selects all rows across multiple pages.
### For Removal
Issue KeyDetails
LIM-794Support for the Legacy Limits file will be removed in Atoti Limits version 4.0.0
# 3.2 Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/3.2 * [Release notes and changelog](./3.2/release-notes-3.2) * [Migration notes](./3.2/migrate-3.2) * [Updates since 3.2 pre-releases](./3.2/updates-since-3.2-prereleases) # Migration notes Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/3.2/migrate-3.2 This page explains the changes required to migrate to the stated version of the Atoti Limits. Please note that Atoti Server versions 5.9 and 5.10 are now out-of-support. Therefore, we will no longer support connections to servers of these versions as of the next release of Atoti Limits. ## Migrate to 3.2.0 Upgrading from version *3.1.0*, see the [Atoti Limits 3.2.0 Release Notes](../../release-notes#320). Atoti Limits is using Atoti Server 6.0.12-sb3 and Atoti UI 5.1.x. For new features and fixes included in these releases, please see the [Atoti UI documentation](https://docs.activeviam.com/products/atoti/ui/5.1/) and [Atoti UI Migration Notes](https://docs.activeviam.com/products/atoti/ui/5.1/docs/changelog), and the [release notes for Atoti Server](https://docs.activeviam.com/products/atoti/server/6.0.12-sb3/docs/release/changelog/index.). ### Headline announcement * **Atoti Server upgrade** : Atoti Limits has been upgraded to Atoti Server 6.0.12-sb3. * **Spring Boot upgrade** : We have upgraded Spring Boot to version 3.2.0, which uses Spring Framework 6. See [Spring Boot 3 upgrade](#spring-boot-3-upgrade) for more details. * **Common Parent POM and Common Dependencies BOM upgrade**: The Common Parent POM and the Common Dependencies BOM have both been upgraded to version 2.0.0. * **Activiti upgrade** : We have upgraded Activiti to version 8.1.0 to be compatible with Spring Boot 3. See [Activiti upgrade](#activiti-upgrade) for more details. * **Changes to LimitsRetrievalUtil**: The `LimitsRetrievalUtil` class, which previously contained static methods, has been converted to a Spring service name `LimitsRetrievalService`. If used in custom code then the methods of this class will need to be updated. For details, see [Changes to LimitsRetrievalUtil](#changes-to-limitsretrievalutil). * **UI Activation** : An import of `react-query` is required when using `limits-sdk`. See [UI activation](../../../dev/dev-ui-config/ui-activation#activating-atoti-limits) for more details. * **Spotify Code Formatter** : We now use Spotify’s code formatter plugin to format and validate our code. For more details, see [Spotify Code Formatter](#spotify-code-formatter). ### Breaking changes * Upgrades: * The version of Spring Boot has been upgraded to version 3.2.0, which includes breaking changes. See the [Spring migration guide](https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide) for more information. * In order to be compatible with Spring Boot 3.2.0 we have upgraded Activiti to version 8.1.0. This requires including `extension.json` files with each workflow file. See [Activiti upgrade](#activiti-upgrade) for more information. ### Spring Boot 3 upgrade The main change in the Spring Boot 3 upgrade involves migrating `javax.**` imports to `jakarta.xx` imports. #### Limits Auto-Configuration In order for the Limits auto-configuration to work with Atoti Server using Spring 5 and Spring 6, the context path of the application is now derived from Spring’s `server.servlet.context-path` variable instead of from the application runtime. No migration is required unless you specify your context path in another way. If so, we recommend you use the `server.root.url` specified in Auto-configuration properties. ### Activiti upgrade #### Extension JSON files In order to upgrade Activiti, you now need to supply an `**-extensions.json` file for each of your workflows. These extension files externalize information about the workflow and provide it to Activiti’s runtime engine. An example of some of the contents in the `**-extension.json` file may look as follows: ```json theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} { "id": "PROCESS", "name": "PROCESS", "extensions": { "limit-process-instance.straight-through": { "properties": {}, "mappings": { "start.event": { "mappingType": "MAP_ALL" }, "approvedUserTask": { "mappingType": "MAP_ALL" }, "deletedServiceTask": { "mappingType": "MAP_ALL" }, "flow1": { "mappingType": "MAP_ALL" } }, "constants": {} } } } ``` In the example above: * `limit-process-instance.straight-through` corresponds to the ID of a process definition. This maps to a single BPMN file. * `start.event` corresponds to the ID of a Start Event. * `approvedUserTask` corresponds to the ID of a User Task. * `deletedServiceTask` corresponds to the ID of a Service Task. * `flow1` corresponds to the ID of a Sequence Flow. * `"mappingType": "MAP_ALL"` tells Activiti to map all input and output variables throughout the workflow. When upgrading, we added mappings for all Start Events, User Tasks, Service Tasks and Sequence Flows, and you will have to do the same for any custom workflows or customizations to our default workflows. #### Custom Task Action Delegator If you are customizing the `IWorkflowTaskActionDelegator` as outlined in `Executing the Java Task`, you may need to reload the `LimitStructureDTO`. Please see the `DefaultWorkflowTaskActionDelegator::executeTaskActionForTaskActionKey` method for an example of how this is done. ### Changes to LimitsRetrievalUtil The `LimitsRetrievalUtil` class has been converted to a Spring service named `LimitsRetrievalService`, which implements the `ILimitsRetrievalService` interface, to make our code more Spring-compliant. If you have custom code that used this class, you will need to update that code. A summary of the changes are as follows: 1. Many of the methods have been replaced by their corresponding new methods in `ILimitsRetrievalService`. The most commonly used methods are: * `getLimitStructures()`/`getLimits()` - to get the limit structures/limits. * `getLimitStructure(int limitStructureKey)`/`getLimit(int limitKey)` - to get a specific limit structure/limit by its key. * `getLimitStructure(LimitsQueryPayload limitsQueryPayload)`/`getLimit(LimitsQueryPayload limitsQueryPayload)` - to get a specific limit structure/limit filtered by a payload object. * `getLimitStructures(LimitsQueryPayload limitsQueryPayload)`/`getLimits(LimitsQueryPayload limitsQueryPayload)` - to get limit structures/limits filtered by a payload object. 2. We have added a new `LimitsQueryPayload` class to allow for more complex filtering of limits and limit structures. This class is used in the new methods mentioned above. 3. The methods have been made non-static. As such, to access the methods, inject the service where you need it and publicly invoke the methods. For cases when injection is not possible, for example in code outside your control, we have added the `ApplicationContextProvider` bean, which allows you to statically retrieve the service. See the `LimitsLoadDataTxControllerTask::initializeSpringBeans` method as an example of how you may do so. 4. The `datastoreVersion` parameter is now specified by assigning a value to the `branchName` field in `LimitsQueryPayload`. 5. The term `limitDefinition` present in some methods has been renamed to `limitStructure`, to update old terminology. For example, the `getLimitDefinitions()` method is now named `getLimitStructures()`. 6. The term `limitEvaluation` present in some methods has been renamed to `limit`, to update old terminology. For example, the `getLimitEvaluations()` method is now named `getLimits()`. 7. When implementing a custom [`IAlertTaskManager`](../../../dev/evaluation-tasks#the-ialerttaskmanager), you now need to override the `getLimitsRetrievalService()` method. ### WebClientService All HTTP requests made by Atoti Limits have been extracted into `WebClientService` and use Spring’s [RestClient](https://docs.spring.io/spring-framework/reference/integration/rest-clients.html#rest-restclient) ### Property relocation The workflow properties that were previously defined in the [UI settings](../../../dev/dev-ui-config/ui-settings#limits-settings) have now been moved to the server side in `application.yml`, namely: * `exceptionWorkflowParticipants` * `limitsWorkflowParticipants` * `roles` Please see [below](#files-modified) for the new properties. ### Input file formats #### Modified
ModificationFileFieldOptionalDescription
Addedlimits\_approve.csvPrecedenceYNumerical value to override which limit in a limit structure should be used for evaluation. A higher value indicates higher precedence.
Field moved from the limit\_structures.csv input file.
Deletedlimit\_structures.csvPrecedenceYNumerical value to override which limit in a limit structure should be used for evaluation. A higher value indicates higher precedence.
Field moved to the limits\_approve.csv input file.
### Configuration files #### Files Modified ##### [application.yml](../../../user-ref/properties/property-files/application-yml) New properties:
Property NameCommentValue
limits.limitWorkflows.StraightThrough.keyRenamed from limits.workflow-types.StraightThroughlimit-process-instance.straight-through
limits.limitWorkflows.FourEyes.keyRenamed from limits.workflow-types.FourEyeslimit-process-instance.four-eyes
limits.limitWorkflows.SixEyes.keyRenamed from limits.workflow-types.SixEyeslimit-process-instance.six-eyes
limits.exceptionWorkflows.Exception.keyRenamed from limits.workflow-types.Exceptionlimit-process-instance.exception
limits.limitWorkflows.FourEyes.participantsContains a comma-separated list of reviewers for the FourEyes workflowApprovers
limits.limitWorkflows.SixEyes.participantsContains a comma-separated list of reviewers for the SixEyes workflowExaminers,Approvers
limits.rolesContains a comma-separated list of security roles, applicable to any workflowROLE\_USERS,ROLE\_MANAGERS
Deleted properties:
Property NameComment
limits.workflow-types.StraightThroughProperty has been replaced with object containing the workflowKey and list of participants. See the new property structure here, application.yml
limits.workflow-types.FourEyesProperty has been replaced with object containing the workflowKey and list of participants. See the new property structure here, application.yml
limits.workflow-types.SixEyesProperty has been replaced with object containing the workflowKey and list of participants. See the new property structure here, application.yml
limits.workflow-types.ExceptionProperty has been replaced with object containing the workflowKey and list of participants. See the new property structure here, application.yml
limits.workflow-types.DeletionProperty has been removed because the Deletion is not a supported workflow.
limit.csv.load.modeThe legacy file upload was removed, so this property is no longer required.
### Datastores #### Modified stores
ModificationStoreFieldTypeDescription
DeletedLimit StructuresException CategoryStringRemoved this unused field.
DeletedLimit StructuresException CommentStringRemoved this unused field.
DeletedIncidentsCommentStringRemoved this unused field.
DeletedLimit StructuresPrecedenceintMoved this field to the Limits store.
AddedLimitsPrecedenceintMoved this field from the Limit Structures store.
RenamedIncidentsNoneNoneRenamed IncidentsStore to Incidents
RenamedAsOfDateNoneNoneRenamed AsOfDateStoreName to AsOfDate
RenamedScope KeysNoneNoneRenamed ScopeKeysStore to ScopeKeys
RenamedScope ValuesNoneNoneRenamed ScopeValuesStore to ScopeValues
### Cube schema #### Added
CubeDimensionHierarchyLevelsDatastore fieldsDetails
LimitsLimitScope (Full)Scope (Full)N/AThe full string representation of the scopes present in the cube, which will include dimension and hierarchy information.
### Measures #### Removed
CubeMeasureDetails
LimitsScopeThis scope measure has been replaced with the Scope level.
### Context values No changes. ### Other changes #### Spotify Code Formatter We now use Spotify’s code formatter plugin to format and validate our code. To format your code you, may use the `format` Maven profile, for example by running `mvn clean install -P format`. To validate that your code is correctly formatted as per the plugin, which uses Google’s code standards, you may use the `validate` Maven profile, for example by running `mvn clean install -P validate`. #### Changes to ILimitsProcessInstanceWorkflowService If you implement a custom `ILimitsProcessInstanceWorkflowService`, modify the `initiate` method to match the new signature.
Old signatureNew signature
AHistoryRecordDTO initiate(LimitsProcessInstanceDTO object, String comment, boolean refreshKpis)AHistoryRecordDTO initiate(LimitsProcessInstanceDTO instanceObject, String comment, boolean publishTuples, boolean refreshKpis)
The new `publishTuples` parameter determines if updated tuples should be published immediately to the datastore. If false, the invoker of this method should manually publish tuples after the method completes. This is more performant for large updates. # Release notes and changelog Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/3.2/release-notes-3.2 For information on upgrading from previous versions, see the [Atoti Limits Migration Notes](./migrate-3.2) Download the distribution files [here](https://activeviam.jfrog.io/artifactory/activeviam-accelerators-artifacts/limits/3.2.0/) You can download the following zipped distribution files: * **UI source code** * **UI build** * **Source files** to build the module * **Sample bookmarks** * **Maven repository** required to build the project and run the tests. The Atoti Server 6.0.12-sb3 Maven repository files can be downloaded from [here](https://artifacts.activeviam.com/share/ActivePivot_stable/6.0.12-sb3/). ### Summary * **Atoti Server upgrade** : Atoti Limits has been upgraded to Atoti Server 6.0.12-sb3. * **Spring Boot upgrade** : We have upgraded Spring Boot to version 3.2.0, which uses Spring Framework 6. * **Common Parent POM and Common Dependencies BOM upgrade**: The Common Parent POM and the Common Dependencies BOM have both been upgraded to version 2.0.0. * **Activiti upgrade** : We have upgraded Activiti to version 8.1.0 to be compatible with Spring Boot 3. * **Added Custom Exception Handling on the UI** : The Atoti Limits UI now parses custom exception responses in a consistent manner. See [Adding Custom UI Exceptions](../../../dev/dev-extensions/custom-ui-exceptions) for more details. * **UI Activation** : An import of `react-query` is required when using `limits-sdk`. See [UI activation](../../../dev/dev-ui-config/ui-activation#activating-atoti-limits) for more details. ### Known issues
Issue KeyDetails
BAS-1330Deleting the last limit value deletes the limit structure. As a workaround, don’t delete all limits on a limit structure unless you are sure that the structure won’t be used again. Alternatively, if you do need to reuse the structure, you can create a limit on it using the endpoint /modules/limits-module/limits/rest/v2/limitDefinition/limits/save. The key of the limit structure will still be visible in the admin-ui.
LIM-846Complex Scopes: Currently, a limit with an aggregated scope and a limit with a non-aggregated scope cannot be created on the same limit structure. As a workaround, create the limits on two separate structures.
LIM-840Complex Scopes: Currently, limits can’t be defined with an aggregated scope location and another scope location. As a workaround, create two separate limits on two separate structures.
LIM-813Managers can incorrectly upload Limit Structures through the REST endpoint.
LIM-594Having email notifications enabled for breaches causes decreased limit evaluation performance. See Configuring the breach email on how to disable breach emails.
LIM-357The Six Eyes workflow is currently not implemented.
LIM-346Limits on calculated measures only work through File Upload, not through the UI.
LIM-320Calculated measures need to be included in Pivot Table Query in order to view a Limit’s KPI in the Pivot Table. See Measures for more on how to create a query for Limits on calculated measures.
### Dependency versions
ComponentVersion
Atoti Server6.0.12-sb3
Atoti UI5.1.x
Common Dependencies BOM2.0.0 (com.activeviam.apps)
Common Parent POM2.0.0 (com.activeviam.apps)
Data Connectors4.1.0-AP6.0-sb3
JavaJDK17
UI Components5.0.34
### Added
Issue KeyDetails
LIM-899Upgraded to Atoti Server 6.0.12-sb3, including Spring Boot 3.2.0.
LIM-967Upgraded deprecated Atoti Server classes in preparation for upgrade to Atoti Server 6.1.
LIM-976Replaced the Scope measure with a Scope level and added a Scope (Full) level.
LIM-986Updated the version of Atoti Server that Atoti Limits runs on to 6.0.10.
LIM-990If the input.data.root.dir.path or csvSource.dataset properties are not set correctly, Atoti Limits automatically generates the correct file structure.
LIM-1021Added generic catch in LimitAutoConfig for greater error handling.
LIM-1027Added custom UI exception handling for ProblemDetail responses.
LIM-1056Added the action property to the ProblemDetails error response. See Adding Custom UI Exceptions.
LIM-1060Updated the version of Admin UI that Atoti Limits uses to 5.1.7.
LIM-1080Added a new ILimitsRetrievalService interface and LimitsQueryPayload object
LIM-1086Added the lombok-maven-plugin to ensure the decompilation of the source code matches the Lombok annotated classes.
LIM-1089Added performance enhancements when loading structures and limits from files and when evaluating limits.
LIM-1090Added Spotify code formatter plugin to Atoti Limits.
LIM-1129Upgraded Data Connectors to version 4.1.0-AP6.0-sb3.
UIACL-783Replaced the Ant Design table component with the “bas-table” in the Limits screens.
### Changed
Issue KeyDetails
LIM-706Moved the roles setting from the UI’s LimitsSettings to the server settings in application.yml.
LIM-795Precedence was moved from the LimitStructuresDTO to the LimitDTO.
LIM-959The LimitsRetrievalUtil class has been converted into a Spring service and is now named LimitsRetrievalService.
LIM-962Moved the limitsWorkflowParticipants and exceptionWorkflowParticipants settings from the UI’s LimitsSettings to the server settings in application.yml.
LIM-989Polling Frequency and KPI Type are now represented as enums in the LimitsStructureDTO.
LIM-997Removed the unused EvaluationTimestamp store and added documentation for the AsOfDate store.
LIM-1007Centralized all HttpRequests in limits-activeviam and limits-stater modules to the WebClientService Spring service and migrated them to the RestClient API.
LIM-1075Upgraded Atoti Server to 6.0.12-sb3.
LIM-1084Migrated HttpClient invocations in limits-atoti-server/limits-atoti-server-60 modules and all test classes to RestClient API.
UIACL-931React-query is now handled as a peer dependency. See UI activation for more details.
Issue KeyDetails
LIM-794Removed support for the legacy limits file.
LIM-984Removed the obsolete “Exception Category” and “Exception Comment” fields from the limit structure store and cube and the obsolete “comment” field from the incident store.
LIM-1038Removed unused declarations of classes, fields, methods and variables.
### Fixed
Issue KeyDetails
LIM-921Fixed an error on discovery when an Atoti Server 6.0.x cube description contained the word “data” by using versioned REST services in the DiscoveriesManager, which is now a Spring component.
LIM-988Fixed the incorrect logger in AsOfDateTuplePublisher.
LIM-1018Fixed an issue where transactions were unnecessarily being started on the Incidents store in LimitsDatastoreService.
LIM-1066Fixed an issue where uses were unable to approve/reject a limit if another limit in the same structure was rejected.
LIM-1085Fixed an issue where limits defined with a time period that did not include the as-of-date were sometimes evaluated incorrectly from the UI.
LIM-1087Fixed a file loading issue that would cause the UI to break due to missing a scope.
LIM-1092Attempting to modify key fields now results in a meaningful HTTP 400 response instead of a generic 500 one.
LIM-1125Fixed an issue where the starter jar didn’t start from the command line, by reverting to the CLASSIC loader implementation for Spring’s Nested Jar Support.
# Updates since 3.2 pre-releases Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/3.2/updates-since-3.2-prereleases This page lists the [changes since 3.2.0-BETA](#changes-between-320-beta-and-320-rc1), and explains any changes required to [migrate from 3.2.0-BETA](#migrate-to-320-from-beta) to the stated version of Atoti Limits. Please note that Atoti Server versions 5.9 and 5.10 are now out-of-support. Therefore, we will no longer support connections to servers of these versions as of the next release of Atoti Limits. ## Changes since 3.2.0-RC1 ### Changes to ILimitsProcessInstanceWorkflowService If you implement a custom `ILimitsProcessInstanceWorkflowService`, modify the `initiate` method to match the new signature.
Old signatureNew signature
AHistoryRecordDTO initiate(LimitsProcessInstanceDTO object, String comment, boolean refreshKpis)AHistoryRecordDTO initiate(LimitsProcessInstanceDTO instanceObject, String comment, boolean publishTuples, boolean refreshKpis)
The new `publishTuples` parameter determines if updated tuples should be published immediately to the datastore. If false, the invoker of this method should manually publish tuples after the method completes. This is more performant for large updates. ### Added
Issue KeyDetails
LIM-1127Added a performance improvement when uploading limits through the UI.
LIM-1129Upgraded Data Connectors to version 4.1.0-AP6.0-sb3.
### Fixed
Issue KeyDetails
LIM-1125Fixed an issue where the starter jar didn’t start from the command line, by reverting to the CLASSIC loader implementation for Spring’s Nested Jar Support.
## Changes between 3.2.0-BETA and 3.2.0-RC1 ### Added
Issue KeyDetails
LIM-1056Added the action property to the ProblemDetails error response. See Adding Custom UI Exceptions.
LIM-1060Updated the version of Admin UI that Atoti Limits uses to 5.1.7.
LIM-1080Added a new ILimitsRetrievalService interface and LimitsQueryPayload object
LIM-1086Added the lombok-maven-plugin to ensure the decompilation of the source code matches the Lombok annotated classes.
LIM-1089Added performance enhancements when loading structures and limits from files and when evaluating limits.
LIM-1090Added Spotify code formatter plugin to Atoti Limits.
### Changed
Issue KeyDetails
LIM-1007Centralized all HttpRequests in limits-activeviam and limits-stater modules to the WebClientService Spring service and migrated them to the RestClient API.
LIM-1075Upgraded Atoti Limits to 6.0.12-sb3
LIM-1084Migrated HttpClient invocations in limits-atoti-server/limits-atoti-server-60 modules and all test classes to RestClient API.
UIACL-931React-query is now handled as a peer dependency. See UI activation for more details.
### Removed
Issue KeyDetails
LIM-1038Removed unused declarations of classes, fields, methods and variables.
### Fixed
Issue KeyDetails
LIM-1066Fixed an issue where users were unable to approve/reject a limit if another limit in the same structure was rejected.
LIM-1085Fixed an issue where limits defined with a time period that did not include the as-of-date were sometimes evaluated incorrectly from the UI.
LIM-1087Fixed a file loading issue that would cause the UI to break due to missing a scope.
LIM-1092Attempting to modify key fields now results in a meaningful HTTP 400 response instead of a generic 500 one.
### Fixed issues introduced in 3.2.0-BETA None. ## Migrate to 3.2.0 from Beta Upgrading from version 3.2.0-beta, see [Atoti Limits 3.2 Release Notes](../../release-notes#320-rc1). Atoti Limits uses Atoti Server 6.0.12-sb3 and Atoti UI 5.1.x. For new features and fixes included in these releases, please see the [Atoti UI documentation](https://docs.activeviam.com/products/atoti/ui/5.1/) and [Atoti UI Migration Notes](https://docs.activeviam.com/products/atoti/ui/5.1/docs/changelog), and the [release notes for Atoti Server](https://docs.activeviam.com/products/atoti/server/6.0.12-sb3/docs/release/changelog/index.). ### Breaking Changes None. ### Summary * **UI Activation** : An import of `react-query` is required when using `limits-sdk`. See [UI activation](../../../dev/dev-ui-config/ui-activation#activating-atoti-limits) for more details. * **Spotify Code Formatter** : We now use Spotify’s code formatter plugin to format and validate our code. For more details, see [Spotify Code Formatter](#spotify-code-formatter). ### Input file formats No changes. ### Configuration files No changes. ### Datastores No changes. ### Cube schema No changes. ### Measures No changes. ### Context values No changes. ### Other changes #### Spotify Code Formatter We now use Spotify’s code formatter plugin to format and validate our code. To format your code you, may use the `format` Maven profile, for example by running `mvn clean install -P format`. To validate that your code is correctly formatted as per the plugin, which uses Google’s code standards, you may use the `validate` Maven profile, for example by running `mvn clean install -P validate`. # 3.3 Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/3.3 * [Release notes and changelog](./3.3/release-notes-3.3) * [Migration notes](./3.3/migrate-3.3) * [Updates since 3.3 Beta](./3.3/updates-since-3.3-beta) # Migration notes Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/3.3/migrate-3.3 This page explains the changes required to migrate to the stated version of the Atoti Limits. ## Migrate to 3.3.1 No migration needed. ## Migrate to 3.3.0 Upgrading from version *3.2.0*, see the [Atoti Limits 3.3.0 Release Notes](../../release-notes#330). Atoti Limits is using Atoti Server 6.0.14-sb3 and Atoti UI 5.1.x. For new features and fixes included in these releases, please see the [Atoti UI documentation](https://docs.activeviam.com/products/atoti/ui/5.1/) and [Atoti UI Migration Notes](https://docs.activeviam.com/products/atoti/ui/5.1/docs/changelog), and the [release notes for Atoti Server](https://docs.activeviam.com/products/atoti/server/6.0.14-sb3/docs/release/changelog/index.). ### Headline announcement * **Persistence** : Atoti Limits can now work with persistent data sources. See [the migration guide](../../../dev/persistence/limits-data-migration) for more information on how to migrate your limits. * **Migration to Configuration Properties** : All properties previously retrieved via `@Value` annotations have been migrated to `@ConfigurationProperties` classes. For details, see [Configuration Properties](../../../user-ref/properties/config-properties). * **Custom validators and validation error handling**: `IValidator` subinterfaces have been created to make swapping the default validator(s) easier for a custom solution. `IValidationError` and `IValidationErrorHandler` have been created to allow for creating custom errors and custom behavior when handling validation errors. See [Adding Custom Validation](../../../dev/dev-extensions/custom-validation) for more details and information on how to implement these. * **Validation error reporting**: The default behavior for validation errors has been updated to produce a summary of the validation errors that occurred, including line numbers and column indexes if the source is a file. * **DLC Configuration Properties** : Data Load Controller property names have been updated, and are now handled by Spring via `@ConfigurationProperties`. See [DLC Configuration Properties](#dlc-configuration-properties). * **Custom data-loading** : Interfaces have been introduced to facilitate overriding the default Data Load Controller and CSV Source configuration beans. Interfaces were also added to facilitate overriding the default Tuple Publisher implementations. * **Atoti Server upgrade** : Atoti Limits has been upgraded to Atoti Server 6.0.14-sb3. * **Custom Evaluations** : The `IEvaluationService` and `IEvaluationTaskManager` interfaces have been introduced to facilitate custom evaluation logic. See [Adding Custom Evaluation Logic](../../../dev/dev-extensions/custom-evaluation) for more information. * **Migration scripts** : We have added a new `limits-migrations` module for migrating CSV files. See [CSV and properties migrations to 3.3.0](#csv-and-properties-migrations-to-330). ### Breaking changes Please note that Atoti Server versions 5.9 and 5.10 are now out-of-support. Therefore, we no longer support connections to servers of these versions starting with this release of Atoti Limits. #### Managed Object ID behavior The behavior has changed for how IDs are used in Atoti Limits. Previously, for each structure, limit, or incident, a `*key` field was generated using a hash of that object’s key fields. Now we expect the following: * when the user creates a structure/limit/incident using the DLC or the UI file upload, we expect the ID to be populated in the file. * when the user creates a structure/limit/incident, we don’t expect the ID to be populated and will auto-generate it. This behavior was introduced to simplify the user experience, to enhance data integrity, and to prevent potential hash-collisions. #### ConfigurationProperties New properties have been added as Spring `@ConfigurationProperties` with defaults. This means that the properties may not appear in the [application.yml](../../../user-ref/properties/property-files/application-yml) but have a value. The value can be overridden by adding your own value in the [application.yml](../../../user-ref/properties/property-files/application-yml) file. #### Datasource configurations We have updated the default datasource configurations for the `limits application`, `activiti`, the `audit log` and the `workflow processes` to point to the same `limits-application` datasource. #### Key generation Previously, a hash function was used to generate the key fields mentioned in the previous section. This could result in hash collisions. We now use an auto-incrementing `IIdentityGenerator` to generate these IDs. The classes in the previous section now implement a `getDeterminator` function that returns a unique string for each object. #### Entity field type changes The following entity fields have been converted from arrays to singular values:
EntityFieldOld TypeNew Type
LimitEntitylimitValueDouble ArrayDouble
LimitsWorkflowProcessInstanceEntitylimitValuesDouble ArrayDouble
LimitsWorkflowProcessInstanceEntityscopeArrayString ArrayString
If you persist these in a database then the column type should be updated accordingly. #### Split of `IAlertTaskManager` The `IAlertTaskManager` interface has been replaced with two interfaces to separate evaluation logic from scheduling logic. If you have a custom implementation of `IAlertTaskManager`, you will need to replace it with implementations of one or both of `IEvaluationService` and `IEvaluationTaskManager`. For more information on the new interfaces and how to implement them, see [Adding Custom Evaluation Logic](../../../dev/dev-extensions/custom-evaluation). #### `*ActivePivot*` classes renamed to `*AtotiServer*` Classes that follow the naming convention `*ActivePivot*` have been renamed to match `*AtotiServer*`. If you have any custom code that references these classes, you will need to update them. #### UI Settings change The `availableApplicationServers` setting has changed from a record to an array of server keys. AsOfDate settings that used to sit under this property are now supplied by the server, and therefore no longer need to be provided in the UI settings. ### CSV and properties migrations to 3.3.0 The migration script migrates the `limit_structures.csv` files and `limits.csv` files from Atoti Limits 3.2.0 to 3.3.0. It also migrates old properties to their new format and outputs them to the properties directory with the name `application-3-3.yml`. It does not add new properties or remove old properties. You can use this new properties file as the starting point for your `application.yml`. #### How it works This script expects the following program arguments (in this order): 1. The target version of Atoti Limits (should be `3.3.0`). 2. The source limit structures input file path. 3. The target limit structures output file path. 4. The source limits input file path. 5. The target limits output file path. 6. The path to the directory storing `*.properties`, `*.yaml` and `*.yml` property files. #### Steps 1. Run `mvn clean install` on `limits-migrations`. 2. Run `java -jar path/to/limits-migrator-tool-exec.jar 3.3 path/to/source/structures.csv path/to/target/structures.csv path/to/source/limits.csv path/to/target/limits.csv path/to/properties/folder`. Your files are now converted to the new format and can be found in the target directory. The output directory must already exist, but the file will be created. ### Input file formats #### Modified
ModificationFileFieldOptionalDescription
Removed fieldlimit\_structures.csvUser IDNUser ID has been removed from all input files. Please remove the User ID column from your limit\_structures.csv files.
Renamed fieldlimit\_structures.csvReference IDNReference ID has been renamed to Structure ID. Please update the Reference ID column in your limit\_structures.csv files.
Renamed fieldlimit\_approve.csvStructure Reference IDNStructure Reference ID has been renamed to Structure ID. Please update the Structure Reference ID column in your limit\_approve.csv files.
Renamed fieldlimit\_approve.csvparentLimitKeyNparentLimitKey has been renamed to Source Limit ID. Please update the parentLimitKey column in your limit\_approve.csv files.
### Configuration #### Configuration properties ##### Properties modified Updated property names: ###### DLC Configuration Properties
Old Property NameNew Property NameDescriptionDefault Value
input.data.root.dir.pathlimits.dlc.root-dirDirectory path to the data files../src/test/resources/data-samples
csvSource.subdirectory.datasetlimits.dlc.sub-directory-paths.rootPath extension to specific server data directories./data
csvSource.subdirectory.dataset.whatiflimits.dlc.sub-directory-paths.whatifPath extension to directory containing the What-If CSV files./whatif
csvSource.subdirectory.dataset.stagelimits.dlc.sub-directory-paths.stagePath extension to directory containing the Stage CSV files./stage
default.csvSource.parser.threadslimits.dlc.parser-threadsSpecifies the number of threads to be used for data loading, used for configuring the DlcCSVSourceConfiguration.4
default.csvSource.buffer.sizelimits.dlc.buffer-sizeCSV buffer size in KB, used for configuring the DlcCSVSourceConfiguration.1024
as.of.date.file.path.matcherlimits.dlc.path-matchers.asofdateRegular expression to match as\_of\_date.csv files.glob:\*\*/\*as\_of\_date\*.csv
limits.definitions.file.path.matcherlimits.dlc.path-matchers.limitstructuresRegular expression to match limit\_structures.csv files.glob:\*\*/\*limit\_structures\*.csv
limits.approve.parameters.file.path.matcherlimits.dlc.path-matchers.limitsRegular expression to match limits\_approve.csv files.glob:\*\*/\*limits\_approve\*.csv
alerts.definitions.file.path.matcherlimits.dlc.path-matchers.incidentsRegular expression to match incident.csv files.glob:\*\*/\*incident\*.csv
###### Connected Atoti Server Properties The following properties are set on the connected Atoti server and are used to configure the connection to Atoti Limits.
Old Property NameNew Property NameDescriptionDefault Value
ap.urllimits-connected-server.urlThe URL of the Atoti server’s cube discovery
ap.authlimits-connected-server.authThe base-64 encoded authentication used to auto-configure the authorization for the module to connect to the Atoti server.
ap.auth.usernamelimits-connected-server.usernameThe username used to auto-configure the authorization for Atoti Limits to connect to the Atoti server.
ap.configuration.kpi.pathlimits-connected-server.kpi-pathThe path to get the KPI permissions.
ap.asOfDate.dimlimits-connected-server.as-of-dateThe slicing date dimension present in the Atoti Server cube. Notation is Level\@Hierarchy\@Dimension.
level-path.urllimits-connected-server.level-path-urlThe URL of the level path rest service.
limits.connect.fixed.delaylimits.connection.delayThe time delay in milliseconds between consecutive attempts to connect to the module.10000
limits.connect.attemptslimits.connection.attemptsThe number of attempts to connect to the module before quitting. If less than zero, the Atoti server will continuously try to connect. The Atoti server will also try to reconnect if Atoti Limits is stopped and restarted.-1
auto-config.enabledlimits.auto-config-enabledIf false, the auto-configuration methods will not be fired.true
atoti.server.versionlimits-connected-server.atoti-server-versionThe version of Atoti Server the connected server is running.
The following properties are used by Atoti Limits to manage connections to connected Atoti servers. These can be auto-configured if `limits.auto-config-enabled` is true. If you manually configure the connection between Atoti Limits and a connected Atoti server, you will need to update these properties.
Old Property NameNew Property NameDescriptionDefault Value
ap.url.maplimits.connected-server.url.mapMap of the Solution name to http url.
ap.version.maplimits.connected-server.version.mapMap of the Solution name to its server version: \{ \< server name >: \< version >, … }.
ap.configuration.kpi.path.maplimits.connected-server.kpi-path.mapAtoti Server configuration KPI path to get the KPI permissions used during startup to delete the stale KPIs
ap.auth.maplimits.connected-server.auth.mapMap of the Solution name to authentication token.
ap.asOfDate.dim.maplimits.connected-server.as-of-date.mapMap of the Solution name to AsOfDate cube location.
level-path.urllimits.connected-server.level-path.mapMap of the Solution name to Level Path REST endpoint URL.
#### Property files ##### Files Modified ###### [application.yml](../../../user-ref/properties/property-files/application-yml) New properties:
Property NameCommentValue
limits.application.datasourceProperties prefixed by this are related to the datasource for the limits application
limits.application.datasource.urlConnection urljdbc:h2:mem:limits-application;DB\_CLOSE\_DELAY=-1;
limits.application.datasource.usernameConnection usernameapp
limits.application.datasource.passwordConnection password
limits.application.datasource.properties.hibernate.dialectHibernate dialectorg.hibernate.dialect.H2Dialect
limits.application.datasource.properties.hibernate.format\_sqlEnables formatting of SQL logged to the console.false
limits.application.datasource.properties.hibernate.hbm2ddl.autoSetting for how Spring should handle the database table on startup. Potential values include: create, create\_drop, none, validate, update, drop, validate and truncate.update
limits.application.datasource.properties.hibernate.globally\_quoted\_identifiersEscapes all database identifiers, so we don’t have to put column and table names in quotations.true
limits.application.datasource.hikari.connectionTimeoutMaximum timeout in milliseconds user will wait for a connection from connection pool.30000
limits.application.datasource.hikari.idleTimeoutMaximum time a connection can remain idle in connection pool.60000
limits.application.datasource.hikari.minimumIdleMinimum number of idle connections in a connection pool.1
limits.application.datasource.hikari.maximumPoolSizeMaximum size of the connection pool, including both idle and in-use connections.10
limits.application.datasource.hikari.poolNameName of the connection pool.limits-application
application.datasourceProperties prefixed by this are related to the datasource for the limits workflow processes
application.datasource.urlConnection urljdbc:h2:mem:limits-application;DB\_CLOSE\_DELAY=-1
application.datasource.usernameConnection usernameapp
application.datasource.passwordConnection password
application.datasource.properties.hibernate.dialectHibernate dialectorg.hibernate.dialect.H2Dialect
application.datasource.properties.hibernate.format\_sqlEnables formatting of SQL logged to the console.false
application.datasource.properties.hibernate.hbm2ddl.autoSetting for how Spring should handle the database table on startup. Potential values include: create, create\_drop, none, validate, update, drop, validate and truncate.update
application.datasource.properties.hibernate.globally\_quoted\_identifiersEscapes all database identifiers, so we don’t have to put column and table names in quotations.true
application.datasource.hikari.connectionTimeoutMaximum timeout in milliseconds user will wait for a connection from connection pool.30000
application.datasource.hikari.idleTimeoutMaximum time a connection can remain idle in connection pool.60000
application.datasource.hikari.minimumIdleMinimum number of idle connections in a connection pool.1
application.datasource.hikari.maximumPoolSizeMaximum size of the connection pool, including both idle and in-use connections.10
application.datasource.hikari.poolNameName of the connection pool.application-process-instance
limits.structure.templatesA map of LimitStructureTemplate definitions by templateName. See Adding Custom Limit Structure Templatessee application.yml
spring.h2.console.enabledTrue if the H2 console is available. This is useful for investigating JDBC connections.false
spring.data.rest.base-pathThe base URL for Spring Data REST services which are autoconfigured for JPA repositories.limits/rest/v2/spring/jpa
spring.liquibase.enabledTrue if Liquibase database schema migrations listed in limits-starter/src/main/resources/liquibase/master-changelog.yaml should be applied on startup.false
spring.liquibase.change-logThe location of the changelog file if Liquibase database schema migrations are applied on startup.classpath:/liquibase/master-changelog.yaml
#### Files Deleted The following `*.properties` property files have been deleted. Properties still in use have been moved to [`@ConfigurationProperties` classes](../../../user-ref/properties/config-properties/limits-activeviam) or [application.yml](../../../user-ref/properties/property-files/application-yml): * `env-default.properties` * `hibernate.properties` * `jwt.properties` * `limits.properties` * `limits_test.properties` * `tracing.properties` ### Datastores #### Modified stores
ModificationStoreFieldTypeDescription
DeletedLimit StructuresUserIdStringThe field has been deleted. It contained the ID or name of the user who created a given limit structure.
RenamedLimit StructuresReference IDstringReference ID has been renamed to Structure ID.
DeletedLimit StructuresstructureKeystringstructureKey has been deleted. Structure ID will be used instead.
RenamedLimitsReference IDstringReference ID has been renamed to Structure ID.
RenamedLimitsparentLimitKeystringparentLimitKey has been renamed to Source Limit ID.
DeletedLimitslimitKeystringlimitKey has been deleted. Limit ID will be used instead.
DeletedLimitsstructureKeystringstructureKey has been deleted. Structure ID will be used instead.
DeletedLimitsLimit NamestringThe unused Limit Name column has been deleted.
RenamedIncidentsincidentKeystringincidentKey has been renamed to Incident ID.
RenamedIncidentslimitKeystringlimitKey has been renamed to Limit ID.
### Cube schema The `limitKey` hierarchy has been renamed to [`limitId`](../../../user-ref/cube/limitid). ### Measures No changes. ### Context values No changes. ### Other changes #### Changes to ILimitsProcessInstanceWorkflowService If you implement a custom `ILimitsProcessInstanceWorkflowService`, please implement the new `decorateWorkflowObject` method. This is intended to decorate the `LimitDTO` and `IncidentDTO` objects with the values of workflow variables. You will also need to modify the `update` method to the new signature which includes the additional `publishTuples` and `refreshKpis` parameters. #### Custom data-loading These classes were moved from the `limits-starter` module to the `limits-activeviam` module: * `LimitsDlcConfigurationProperties` * `CSVSourceConfig` * `ACSVSourceConfig` * `DataLoadControllerConfig` * `InitialLoad` * `LimitTuplePublisher` * `AsOfDateTuplePublisher` * `IncidentTuplePublisher` If you have customized any of these classes, you need to migrate your code. Interfaces have been provided to override all classes listed above except`LimitsDlcConfigurationProperties` and `InitialLoad`. # Release notes and changelog Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/3.3/release-notes-3.3 For information on upgrading from previous versions, see the [Atoti Limits Migration Notes](./migrate-3.3) Download the distribution files [here](https://activeviam.jfrog.io/artifactory/activeviam-accelerators-artifacts/limits/3.3.1/) You can download the following zipped distribution files: * **UI source code** * **UI build** * **Source files** to build the module * **Sample bookmarks** * **Maven repository** required to build the project and run the tests. The Atoti Server 6.0.14-sb3 Maven repository files can be downloaded from [here](https://artifacts.activeviam.com/share/ActivePivot_stable/6.0.14-sb3/). ### Summary This release includes artifacts for connecting with instances of Atoti Server on version `6.0.x` using Java 11, in addition to the already supported `6.0.x-sb3` version using Java 17. There have been no other changes. The artifact changes are as follows:
Old NameNew NameComment
lookup-post-processor-ap60lookup-post-processor-ap60-sb3The old artifact has been renamed and requires Java 17.
N/Alookup-post-processor-ap60This new artifact is compatible with Java 11.
limits-auto-config-ap60limits-auto-config-ap60-sb3The old artifact has been renamed and requires Java 17.
N/Alimits-auto-config-ap60This new artifact is compatible with Java 11.
limits-atoti-server-60limits-atoti-server-60-sb3The old artifact has been renamed and requires Java 17.
N/Alimits-atoti-server-60This new artifact is compatible with Java 11.
### Known issues
Issue KeyDetails
BAS-1330Deleting the last limit value deletes the limit structure. As a workaround, don’t delete all limits on a limit structure unless you are sure that the structure won’t be used again. Alternatively, if you do need to reuse the structure, you can create a limit on it using the endpoint /modules/limits-module/limits/rest/v2/limitDefinition/limits/save. The key of the limit structure will still be visible in the admin-ui.
LIM-846Complex Scopes: Currently, a limit with an aggregated scope and a limit with a non-aggregated scope cannot be created on the same limit structure. As a workaround, create the limits on two separate structures.
LIM-840Complex Scopes: Currently, limits can’t be defined with an aggregated scope location and another scope location. As a workaround, create two separate limits on two separate structures.
LIM-813Managers can incorrectly upload Limit Structures through the REST endpoint.
LIM-594Having email notifications enabled for breaches causes decreased limit evaluation performance. See Configuring the breach email on how to disable breach emails.
LIM-357The Six Eyes workflow is currently not implemented.
LIM-346Limits on calculated measures only work through File Upload, not through the UI.
LIM-320Calculated measures need to be included in Pivot Table Query in order to view a Limit’s KPI in the Pivot Table. See Measures for more on how to create a query for Limits on calculated measures.
### Dependency versions
ComponentVersion
Atoti Server6.0.14-sb3
Atoti UI5.1.x
Common Dependencies BOM2.0.1 (com.activeviam.apps)
Common Parent POM2.0.1 (com.activeviam.apps)
Data Connectors4.1.0-AP6.0-sb3
JavaJDK17
UI Components5.0.42
### Added
Issue KeyDetails
LIM-1299Added connector artifacts on Java 11.
Download the distribution files [here](https://activeviam.jfrog.io/artifactory/activeviam-accelerators-artifacts/limits/3.3.0/) You can download the following zipped distribution files: * **UI source code** * **UI build** * **Source files** to build the module * **Sample bookmarks** * **Maven repository** required to build the project and run the tests. The Atoti Server 6.0.14-sb3 Maven repository files can be downloaded from [here](https://artifacts.activeviam.com/share/ActivePivot_stable/6.0.14-sb3/). Please note that Atoti Server versions 5.9, 5.10 and 5.11 are now out-of-support. Therefore, we no longer support connections to servers of these versions starting with this release of Atoti Limits. ### Summary * **Limit Persistence** : Atoti Limits can now work with persistent data sources. See [Persistence](../../../dev/persistence) for more information. * **Real-time Incidents** : Incidents are now updated in real-time in the UI via server-sent events. They can be disabled with the action button above the data table in the **Status screen**. For more information, see [Real-time updates](../../../user-ref/manage-incidents/status-screen) * **Workflow Attachment Links** : You can now add a navigable attachment link in the UI to a limit or incident when moving it along its workflow. For more see the section on [Managing Limits and Incidents](../../../user-ref/using-limits). * **Resizable limits structure drawer**: The **Limit Structure** drawer is now resizable. Atoti Limits remembers the size and whether it was open, the next time you start the module. By default, the drawer is open. * **Limit Structure Templates** : You can now create custom templates to pre-populate fields when creating limit structures via the UI. See [Adding Custom Limit Structure Templates](../../../dev/dev-extensions/custom-limit-structure-templates) for more information and implementation details. * **Migration to Configuration Properties** : All properties previously retrieved via `@Value` annotations have been migrated to `@ConfigurationProperties` classes. For details, see [Configuration Properties](../../../user-ref/properties/config-properties). * **Extendable Validation**: It is now easier for users to add custom validation and validation error handling. See [Adding Custom Validation](../../../dev/dev-extensions/custom-validation). * **Extendable CSV Source Configuration** : Adding and overriding DLC and CSV data loading configuration has been made easier. * **Atoti Server upgrade** : Atoti Limits has been upgraded to Atoti Server 6.0.14-sb3. * **Removed Atoti Server 5.9 and 5.10 support** : Atoti Server versions 5.9 and 5.10 are now out of support, and are no longer supported within Atoti Limits. * **Updated UI settings**: The `restrictedScopes` setting is now keyed by cube name. The `availableApplicationServers` setting has changed from a record to an array of server keys. AsOfDate settings under this property are now supplied by the server. * **Custom Evaluations** : The `IEvaluationService` and `IEvaluationTaskManager` interfaces have been introduced to facilitate custom evaluation logic. See [Adding Custom Evaluation Logic](../../../dev/dev-extensions/custom-evaluation) for more information. * **Migration Scripts** : We have added a new `limits-migrations` module for migrating CSV files. See [CSV and properties migrations to 3.3.0](./migrate-3.3#csv-and-properties-migrations-to-330). ### Known issues
Issue KeyDetails
BAS-1330Deleting the last limit value deletes the limit structure. As a workaround, don’t delete all limits on a limit structure unless you are sure that the structure won’t be used again. Alternatively, if you do need to reuse the structure, you can create a limit on it using the endpoint /modules/limits-module/limits/rest/v2/limitDefinition/limits/save. The key of the limit structure will still be visible in the admin-ui.
LIM-846Complex Scopes: Currently, a limit with an aggregated scope and a limit with a non-aggregated scope cannot be created on the same limit structure. As a workaround, create the limits on two separate structures.
LIM-840Complex Scopes: Currently, limits can’t be defined with an aggregated scope location and another scope location. As a workaround, create two separate limits on two separate structures.
LIM-813Managers can incorrectly upload Limit Structures through the REST endpoint.
LIM-594Having email notifications enabled for breaches causes decreased limit evaluation performance. See Configuring the breach email on how to disable breach emails.
LIM-357The Six Eyes workflow is currently not implemented.
LIM-346Limits on calculated measures only work through File Upload, not through the UI.
LIM-320Calculated measures need to be included in Pivot Table Query in order to view a Limit’s KPI in the Pivot Table. See Measures for more on how to create a query for Limits on calculated measures.
### Dependency versions
ComponentVersion
Atoti Server6.0.14-sb3
Atoti UI5.1.x
Common Dependencies BOM2.0.1 (com.activeviam.apps)
Common Parent POM2.0.1 (com.activeviam.apps)
Data Connectors4.1.0-AP6.0-sb3
JavaJDK17
UI Components5.0.41
### Added
Issue KeyDetails
LIM-235Added a @ConfigurationProperties class to handle properties from the hibernate.properties file.
LIM-834Added an auto-incrementing IIdentityGenerator to support replacing limitStructureKey, limitKey and incidentKeys with user-defined IDs.
LIM-979Added the ability to load limits from a persistent data source.
LIM-1002Added Liquibase changesets to facilitate database migrations.
LIM-1006Server-sent events have been implemented to update incidents in real time.
LIM-1010Implemented a persistence layer to manage datastore and external database transactions.
LIM-1050Added an Attachment Link task input field for including a link in the limit and incident audit trails.
LIM-1058Updated the usage of the draftLimit to instead use workflow variables.
LIM-1077Added the ability to pre-populate fields of the UI form when creating a new Limit Structure.
LIM-1094Added the maxScopeMembersQueryResult setting to retrieve more members before having to resort to a search.
LIM-1119IValidator subinterfaces have been created to make swapping the default validator(s) easier for a custom solution.
LIM-1126Added a @ConfigurationProperties class to handle DLC properties
LIM-1147Added a defaultValue field for workflow action input fields.
LIM-1148Updated usages of the LimitsCrudService and IncidentCrudService to instead use the LimitsAppCrudService.
LIM-1149Added a preValidation method to the IValidator interface.
LIM-1154Upgraded admin-ui to version 5.1.8.
LIM-1157Evaluations on the status screen can now be updated in real-time.
LIM-1177Added Spring JPA REST services and migration endpoints.
LIM-1168Converted the limitStructureKey, limitKey and incidentKeys to strings.
LIM-1172Added a method for users to load their own JPA Repositories in LimitsJpaConfig.
LIM-1173ID’s are now required fields in the limit\_structures.csv and limit\_approve.csv files.
LIM-1196Limit files can now be previewed in a table before uploading. Any error when uploading will be shown in the table.
LIM-1209Upgraded Atoti Server to 6.0.14-sb3.
LIM-1210Real-time updates can now be disabled/enabled in the UI.
LIM-1215Column index is now reported for validation errors.
LIM-1236Added a new limits-migrations module for migrating CSV files. See CSV migrations to 3.3.0.
LIM-1239Atoti Limits now sends the business server’s asOfDate dimension in the limits /settings endpoint.
UIACL-984Unsaved limit structures and limits are now persisted if you navigate away from the page without saving.
### Changed
Issue KeyDetails
BAS-1879Renamed KpiAlertTask and LimitAlertTask to LimitStructureEvaluationTask and LimitEvaluationTask respectively.
LIM-1116Migrated properties previously retrieved via @Value annotations to @ConfigurationProperties classes.
LIM-1136Validation errors are now collected and reported with line numbers (if applicable) instead of failing immediately.
LIM-1142Moved the default cube configuration classes into the limits-activeviam module. Added beans to allow clients to override the cube configuration. See Custom Cube Configuration
LIM-1143Moved the DLC and CSV Source configuration classes into the limits-activeviam module. Created interfaces to override DataLoadControllerConfig and CSVSourceConfig.
LIM-1144Moved tuple publisher classes into the limits-activeviam module. Created interfaces to override the default tuple publishers.
LIM-1146Replaced IAlertTaskManager with new interfaces to separate evaluation and scheduling logic. See Adding Custom Evaluation Logic for more information.
LIM-1150Refactored the exceptions thrown in DefaultLimitTuplePublisher to be handled by the IValidationErrorHandlers.
LIM-1151Changed the behavior of the asOfDate filter in the Status screen. If there were no incidents present in the Status screen, the asOfDate filter would set the filter date to the current date. Now if there are no incidents present, the asOfDate filter will not be applied by default.
LIM-1161The Limit Structure drawer is now resizable.
LIM-1166Changed the default value of the isLiveOnly argument to true in LimitsDefinitionCrudRestService.
LIM-1171Upgraded the common-dependencies-bom and common-parent-pom versions to 2.0.1. This bumps Spring Boot to version 3.2.4, inheriting bug fixes and improvements.
LIM-1186Improved performance and UX when creating limits. Nodes from the scope tree will now be lazy-loaded when a scope is being selected.
LIM-1195Updated default validation behavior to be non-blocking for limits loaded through the DLC. Loading through REST, like file upload, is still an atomic operation.
LIM-1197Moved REST constants to a dedicated LimitsRestServiceConstants class.
LIM-1198Moved datastore constants to a dedicated LimitsDatastoreConstants class.
LIM-1208Expanded support for reporting line numbers in the default validators.
LIM-1218Improved UX for the Create Limit Structure button on the Limit Structure screen.
LIM-1222The restrictedScopes setting is now keyed by cube.
LIM-1240The availableApplicationServers setting has changed from a record to an array of server keys. AsOfDate settings that used to sit under this property are now supplied by the server.
### Removed
Issue KeyDetails
LIM-36The User ID field has been removed from the datastore configuration, the LimitStructureDTO object, and all input files.
LIM-499Removed all \*.properties files from Atoti Limits. Removed CsvDataExtractionEngineConfig from the default configuration.
LIM-1044Removed the includeUIWorkflowActions and excludePasses arguments from implementation and invocations of the IncidentCrudService.
LIM-1105Removed support for Atoti Server versions 5.9 and 5.10 as they are no longer supported by ActiveViam.
### Fixed
Issue KeyDetails
LIM-570Fixed a performance issue on startup when reloading workflows.
LIM-1138Fixed a data quality issue by preventing multiple limit structures with the same name to be created.
LIM-1141Incident files are now written when evaluating limits without evaluating the structure.
LIM-1156Fixed issue where incident files included all incidents, regardless of the KPI in the file name.
LIM-1190Fixed bug where copying and saving a limit structure cleared the limit structure form.
LIM-1220Fixed a bug which prevented the user from dragging table columns to the last position in the config panel.
LIM-1223Made the order of incidents in the status screen consistent between realtime-enabled and disabled modes.
LIM-1225Fixed the styling of links on the Status screen.
LIM-1226Real time incidents can now be filtered by multiple dates.
LIM-1244Fixed issue where incidents could be reviewed multiple times.
LIM-1253Fixed an issue that prevented Atoti Limits from starting in persistent mode due to null workflow statuses.
LIM-1256The Inventory now generates limit structure creation templates according to server keys derived by checking the names coming from the server settings endpoint against server keys supplied to LimitsModuleSettings.availableApplicationServerKeys.
### For Removal
Issue KeyDetails
LIM-1230Manual configuration has been deprecated in favor of auto-configuration and will be removed in the next version of Atoti Limits.
# Updates since 3.3 Beta Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/3.3/updates-since-3.3-beta This page lists the [changes since 3.3.0-BETA](#changes-since-330-beta), and explains any changes required to [migrate from 3.3.0-BETA](#migrate-to-330-from-beta) to the stated version of Atoti Limits. Please note that Atoti Server versions 5.9 and 5.10 are now out-of-support. Therefore, we no longer support connections to servers of these versions starting with this release of Atoti Limits. ## Changes since 3.3.0-beta ### Added
Issue KeyDetails
LIM-1002Added Liquibase changesets to facilitate database migrations.
LIM-1094Added the maxScopeMembersQueryResult setting to retrieve more members before having to resort to a search.
LIM-1149Added a preValidation method to the IValidator interface.
LIM-1173ID’s are now required fields in the limit\_structures.csv and limit\_approve.csv files.
LIM-1196Limit files can now be previewed in a table before uploading. Any error when uploading will be shown in the table.
LIM-1209Upgraded Atoti Server to 6.0.14-sb3.
LIM-1210Real-time updates can now be disabled/enabled in the UI.
LIM-1215Column index is now reported for validation errors.
LIM-1236Added a new limits-migrations module for migrating CSV files. See CSV migrations to 3.3.0.
LIM-1239Atoti Limits now sends the business server’s asOfDate dimension in the limits /settings endpoint.
### Changed
Issue KeyDetails
BAS-1879Renamed KpiAlertTask and LimitAlertTask to LimitStructureEvaluationTask and LimitEvaluationTask respectively.
LIM-1142Moved the default cube configuration classes into the limits-activeviam module. Added beans to allow clients to override the cube configuration. See Custom Cube Configuration
LIM-1146Replaced IAlertTaskManager with new interfaces to separate evaluation and scheduling logic. See Adding Custom Evaluation Logic for more information.
LIM-1150Refactored the exceptions thrown in DefaultLimitTuplePublisher to be handled by the IValidationErrorHandler.
LIM-1171Upgraded the common-dependencies-bom and common-parent-pom versions to 2.0.1. This bumps Spring Boot to version 3.2.4, inheriting bug fixes and improvements.
LIM-1186Improved performance and UX when creating limits. Nodes from the scope tree will now be lazy-loaded when a scope is being selected.
LIM-1195Updated default validation behavior to be non-blocking for limits loaded through the DLC. Loading through REST (i.e. file upload) is still an atomic operation.
LIM-1197Moved REST constants to a dedicated LimitsRestServiceConstants class.
LIM-1198Moved datastore constants to a dedicated LimitsDatastoreConstants class.
LIM-1208Expanded support for reporting line numbers in the default validators.
LIM-1218Improved UX for the Create Limit Structure button on the Limit Structure screen.
LIM-1240The availableApplicationServers setting has changed from a record to an array of server keys. AsOfDate settings that used to sit under this property are now supplied by the server.
### Removed
Issue KeyDetails
LIM-499Removed all \*.properties files from the Atoti Limits. Removed CsvDataExtractionEngineConfig from the default configuration.
### Fixed
Issue KeyDetails
LIM-570Fixed a performance issue on startup when reloading workflows.
LIM-1138Fixed a data quality issue by preventing multiple limit structures with the same name to be created.
LIM-1223Made the order of incidents in the status screen consistent between realtime-enabled and disabled modes.
LIM-1226Real time incidents can now be filtered by multiple dates.
LIM-1244Fixed issue where incidents could be reviewed multiple times.
LIM-1248On evaluation, incident CSV files will now only be written in the CSV data load mode.
LIM-1253Fixed an issue that prevented Atoti Limits from starting in persistent mode due to null workflow statuses.
LIM-1256The Inventory now generates limit structure creation templates according to server keys derived by checking the names coming from the server settings endpoint against server keys supplied to LimitsModuleSettings.availableApplicationServerKeys.
### For Removal
Issue KeyDetails
LIM-1230Manual configuration has been deprecated in favor of auto-configuration and will be removed in the next version of Atoti Limits.
### Fixed issues introduced in 3.3.0-BETA
Issue KeyDetails
LIM-1190Fixed bug where copying and saving a limit structure cleared the limit structure form.
## Migrate to 3.3.0 from Beta Upgrading from version 3.3.0-beta, see [Atoti Limits 3.3 Release Notes](../../release-notes#330). Atoti Limits uses Atoti Server 6.0.14-sb3 and Atoti UI 5.1.x. For new features and fixes included in these releases, please see the [Atoti UI documentation](https://docs.activeviam.com/products/atoti/ui/5.1/) and [Atoti UI Migration Notes](https://docs.activeviam.com/products/atoti/ui/5.1/docs/changelog), and the [release notes for Atoti Server](https://docs.activeviam.com/products/atoti/server/6.0.14-sb3/docs/release/changelog/index.). ### Summary * **Validation API Improvements** : Additional methods have been added to `IValidator` to make it easier to interact with the validators. For more details, see [IValidator changes](#ivalidator-changes). * **Modified Default Validation Behavior** : The default validation behavior has been updated to be non-blocking for limits loaded through the DLC. Loading through REST (i.e. file upload) is still an atomic operation. * **Custom Evaluations** : The `IEvaluationService` and `IEvaluationTaskManager` interfaces have been introduced to facilitate custom evaluation logic. See [Adding Custom Evaluation Logic](./migrate-3.3#csv-and-properties-migrations-to-330) for more information. * **Migration scripts** : We have added a new `limits-migrations` module for migrating CSV files. See [CSV and properties migrations to 3.3.0](#csv-and-properties-migrations-to-330). ### Breaking Changes #### Managed Object ID behavior The behavior has changed for how IDs are used in Atoti Limits. Previously, for each structure, limit, or incident, a `*key` field was generated using a hash of that object’s key fields. Now we expect the following: * when the user creates a structure/limit/incident using the DLC or the UI file upload, we expect the ID to be populated in the file. * when the user creates a structure/limit/incident, we don’t expect the ID to be populated and instead we will auto-generate it on the server using implementations of `IIdentityGenerator`. This behavior was introduced to simplify the user experience, to enhance data integrity, and to prevent potential hash-collisions. #### Starter customizations If you previously modified the data loading or cube configuration code in the `limits-starter` module then you will have to migrate that code. Please see [the dev extensions](../../../dev/dev-extensions) section for how to do so. #### Split of `IAlertTaskManager` The `IAlertTaskManager` interface has been replaced with two interfaces to separate evaluation logic from scheduling logic. If you have a custom implementation of `IAlertTaskManager`, you will need to replace it with implementations of one or both of `IEvaluationService` and `IEvaluationTaskManager`. For more information on the new interfaces and how to implement them, see [Adding Custom Evaluation Logic](../../../dev/dev-extensions/custom-evaluation). #### Entity field type changes The following entity fields have been converted from arrays to singular values:
EntityFieldOld TypeNew Type
LimitEntitylimitValueDouble ArrayDouble
LimitsWorkflowProcessInstanceEntitylimitValuesDouble ArrayDouble
LimitsWorkflowProcessInstanceEntityscopeArrayString ArrayString
If you persist these in a database then the column type should be updated accordingly. #### `*ActivePivot*` classes renamed to `*AtotiServer*` Classes that follow the naming convention `*ActivePivot*` have been renamed to match `*AtotiServer*`. If you have any custom code that references these classes, you will need to update them. #### UI Settings change The `availableApplicationServers` setting has changed from a record to an array of server keys. AsOfDate settings that used to sit under this property are now supplied by the server, and therefore no longer need to be provided in the UI settings. ### CSV and properties migrations to 3.3.0 The migration script migrates the `limit_structures.csv` files and `limits.csv` files from Atoti Limits 3.2.0 to 3.3.0. For details on how it works, see [the 3.3.0 Migration Notes](./migrate-3.3#csv-and-properties-migrations-to-330). ### Input file formats No changes. ### Configuration files The following `*.properties` property files have been deleted. Properties still in use have been moved to [`@ConfigurationProperties` classes](../../../user-ref/properties/config-properties/limits-activeviam) or [application.yml](../../../user-ref/properties/property-files/application-yml): * `env-default.properties` * `jwt.properties` * `limits.properties` * `limits_test.properties` * `tracing.properties` #### Files Modified ##### [application.yml](../../../user-ref/properties/property-files/application-yml) New properties:
Property NameCommentValue
spring.liquibase.enabledTrue if Liquibase database schema migrations listed in limits-starter/src/main/resources/liquibase/master-changelog.yaml should be applied on startup.false
spring.liquibase.change-logThe location of the changelog file if Liquibase database schema migrations are applied on startup.classpath:/liquibase/master-changelog.yaml
### Datastores #### Modified stores
ModificationStoreFieldTypeDescription
RenamedLimit StructuresReference IDstringReference ID has been renamed to Structure ID.
DeletedLimit StructuresstructureKeystringstructureKey has been deleted. Structure ID will be used instead.
RenamedLimitsReference IDstringReference ID has been renamed to Structure ID.
RenamedLimitsparentLimitKeystringparentLimitKey has been renamed to Source Limit ID.
DeletedLimitslimitKeystringlimitKey has been deleted. Limit ID will be used instead.
DeletedLimitsstructureKeystringstructureKey has been deleted. Structure ID will be used instead.
DeletedLimitsLimit NamestringThe unused Limit Name column has been deleted.
RenamedIncidentsincidentKeystringincidentKey has been renamed to Incident ID.
RenamedIncidentslimitKeystringlimitKey has been renamed to Limit ID.
### Cube schema The `limitKey` hierarchy has been renamed to [`limitId`](../../../user-ref/cube/limitid). ### Measures No changes. ### Context values No changes. ### Other changes #### `IValidator` changes The following methods have been added to the `IValidator` interface. If you previously implemented a custom `IValidator` class, you will need to update it to include these methods. If you have not implemented a custom `IValidator` class, you do not need to make any changes. ```java theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} /** Operations to be performed before validation is started. */ void preValidation(Collection objectsToValidate); /** * @return true if validation succeeds for the tuple, false otherwise */ boolean validateTuple(Object[] tuple, int lineNumber); /** * @return objects that have passed validation */ List getValidObjects(); /** * @return objects that have failed validation */ List getInvalidObjects(); /** * Clears the state of the validator, so it is ready to validate a new set of objects. * * @param throwException if true, an exception will be thrown if there are validation errors */ void reset(boolean throwException); /** * @return true if there are validation errors, false otherwise */ boolean hasErrors(); ``` The intent behind these changes is to have the validators keep better track of their state. This allows for better separation between validation logic and handling of valid/invalid objects. `getValidObjects`, `getInvalidObjects` and `hasErrors` allow calling code to access the state of the validator, and `reset` is used to clear the state of the validator between validation operations. Additionally, to pair with the existing `postValidation` method, we have added a `preValidation` method to the `IValidator` interface. This method is called before the `validate`/`validateAll` methods and can be used to perform any pre-validation checks or operations. The default implementations of `IValidator` included with Atoti Limits have been updated to include an implementation of `preValidation` that populates a map of row indexes by ID to help with reporting line numbers for validation errors. A `validateTuple` method has also been added to the `IValidator` interface. This method is called for each tuple in a file being validated. This allows for more fine-grained control over the validation process, validating tuples prior to converting them to objects. #### Changes to ILimitsProcessInstanceWorkflowService You will need to modify the `update` method to the new signature which includes the additional `publishTuples` and `refreshKpis` parameters. # 4.0 Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/4.0 * [Updates since 4.0 pre-releases](./4.0/updates-since-4.0-prereleases) * [Release notes 4.0](./4.0/release-notes-4.0) * [Changelog](./4.0/changelog-4.0) * [Migration guide 4.0](./4.0/migrate-4.0) # Changelog Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/4.0/changelog-4.0 For a brief overview of the changes, see our [Release notes](./release-notes-4.0). For information on upgrading from previous versions, see the [Atoti Limits Migration Guide](./migrate-4.0). ### Fixed
Issue KeyDetails
LIM-2268DefaultLimitsAppCrudService now synchronizes all create, update and delete operations on the same monitor as the existing save\* methods, so concurrent limit modifications (from triggers or the UI) can no longer interleave and corrupt the JPA/datastore writes.
### Added
Issue KeyDetails
LIM-1523We have added new services to start Activiti workflows in bulk.
### Changed
Issue KeyDetails
LIM-1523The default implementation of ILimitsProcessInstanceWorkflowCacheService is now a no-operation implementation as this class is unused.
LIM-1837Updated warning message from “Warn when within x% of a limit” to “Warn when utilisation reaches x% of a limit” for improved clarity.
### Deprecated
Issue KeyDetails
LIM-1523ILimitsProcessInstanceWorkflowCacheService is unused and has been deprecated for removal. It is still present to avoid breaking the API.
LIM-1523IEvaluationTaskManager has been deprecated for removal because most of its methods are unused.
### Fixed
Issue KeyDetails
LIM-1850Fixed an issue where JWT tokens were not being refreshed causing requests between servers to fail after token expiration (default is 12 hours).
LIM-1910Fixed the logic and wording for warning thresholds. The warning threshold is now directly correlated to the limit utilization percentage.
LIM-1954You can now create limits on calculated measures where the underlying is a hierarchy.
### Added
Issue KeyDetails
LIM-1488Moved the IAuthenticatedLimitsUserService to limits-common and created a new implementation in limits-activeviam to assist with tasks requiring unrestricted access to Atoti Limits data.
### Changed
Issue KeyDetails
LIM-1622Changed the default DataLoadController to use an implementation that delegates the security context to the spawned threads.
### Deprecated
Issue KeyDetails
LIM-1611The ILimitsActivitiAuthenticationManager and the getWithAuth(...) methods in IWebClientService are no longer used and have been deprecated and marked for removal in the next minor release.
### Fixed
Issue KeyDetails
LIM-1550Fixed an issue where users with the ROLE\_CREATE\_ANY\_LIMIT permission role were blocked when attempting to create a limit via the UI or REST.
LIM-1611Fixed an issue where JWT authentication was not being used when accessing Activiti or when querying the content server.
### Known issues
Issue KeyDetails
BAS-1330Deleting the last limit value deletes the limit structure. As a workaround, don’t delete all limits on a limit structure unless you are sure that the structure won’t be used again. Alternatively, if you do need to reuse the structure, you can create a limit on it using the endpoint /modules/limits-module/limits/rest/v2/limitDefinition/limits/save. The key of the limit structure will still be visible in the admin-ui.
LIM-846Complex Scopes: Currently, a limit with an aggregated scope and a limit with a non-aggregated scope cannot be created on the same limit structure. As a workaround, create the limits on two separate structures.
LIM-840Complex Scopes: Currently, limits can’t be defined with an aggregated scope location and another scope location. As a workaround, create two separate limits on two separate structures.
LIM-813Managers can incorrectly upload Limit Structures through the REST endpoint.
LIM-594Having email notifications enabled for breaches causes decreased limit evaluation performance. See Configuring the breach email on how to disable breach emails.
LIM-357The Six Eyes workflow is currently not implemented.
LIM-346Limits on calculated measures only work through File Upload, not through the UI.
LIM-320Calculated measures need to be included in Pivot Table Query in order to view a Limit’s KPI in the Pivot Table. See Measures for more on how to create a query for Limits on calculated measures.
### Added
Issue KeyDetails
LIM-1481Added RestTemplate and RestClient beans in the connection modules when sending requests to Atoti Limits and reduced the number of requests sent between the application server and Atoti Limits.
### Changed
Issue KeyDetails
LIM-1552Only required folders are now fetched from the connected server when resolving calculated measures.
LIM-1560Use one global CalculatedMeasuresResolver to speed up queries on limits on calculated measures.
LIM-1563Performance improvements for creating, updating, and evaluating limits.
### Known issues
Issue KeyDetails
BAS-1330Deleting the last limit value deletes the limit structure. As a workaround, don’t delete all limits on a limit structure unless you are sure that the structure won’t be used again. Alternatively, if you do need to reuse the structure, you can create a limit on it using the endpoint /modules/limits-module/limits/rest/v2/limitDefinition/limits/save. The key of the limit structure will still be visible in the admin-ui.
LIM-846Complex Scopes: Currently, a limit with an aggregated scope and a limit with a non-aggregated scope cannot be created on the same limit structure. As a workaround, create the limits on two separate structures.
LIM-840Complex Scopes: Currently, limits can’t be defined with an aggregated scope location and another scope location. As a workaround, create two separate limits on two separate structures.
LIM-813Managers can incorrectly upload Limit Structures through the REST endpoint.
LIM-594Having email notifications enabled for breaches causes decreased limit evaluation performance. See Configuring the breach email on how to disable breach emails.
LIM-357The Six Eyes workflow is currently not implemented.
LIM-346Limits on calculated measures only work through File Upload, not through the UI.
LIM-320Calculated measures need to be included in Pivot Table Query in order to view a Limit’s KPI in the Pivot Table. See Measures for more on how to create a query for Limits on calculated measures.
### Added
Issue KeyDetails
LIM-1378Added an ILimitsCacheService to store structures/limits that exist on the business server to speed up evaluations.
LIM-1531Added a property limits.cube.scope-hierarchies-enabled that can be used to disable scope hierarchies to improve loading performance for large cardinalities of limit scopes.
### Changed
Issue KeyDetails
LIM-1469Use the IConfigurationService instead of REST requests to execute MDX statements when creating Atoti Limits calculated measures to improve performance.
LIM-1525Improved performance of limit evaluations by skipping unnecessary retrieval of limit workflow information.
### Deprecated
Issue KeyDetails
LIM-1378The LimitsRetriever class and the limits/rest/v2/limitDefinition/limitsDefinitionStoreQuery endpoint are no longer used and are deprecated in favor of the ILimitsCacheService. They will be removed in version 4.1.0.
Issue KeyDetails
LIM-1407limits-activeviam no longer has a dependency on limits-integration-common. Classes previously imported from limits-integration-common are now imported from limits-common.
### Fixed
Issue KeyDetails
LIM-1335Fixed an issue where data permissions in Atoti Limits were not applied to the KPIs and calculated members created by the module in the business cube.
LIM-1483Fixed an issue where KPIs were not refreshed after restarting Atoti Limits in persistent mode.
LIM-1492Fixed an issue where Atoti Limits calculated measures were being created on connected server KPIs that did not belong to Atoti Limits.
LIM-1498Fixed an issue where the connected application would not start if Atoti Limits Auto-configuration was disabled via limits.autoconfiguration.enabled=false.
LIM-1510Fixed an issue where the structure scope search can overflow the popover.
LIM-1512Fixed an issue where KPIs were not being created unless restricted users were defined.
LIM-1518Fixed an issue where warning thresholds were not being correctly evaluated.
LIM-1521Fixed an issue that prevented limits from being created on nested calculated measures.
LIM-1522Fixed an issue where generated IDs for limits created via the UI could collide with IDs for limits created via file upload if the uploaded limits respected the ordering of the generated IDs.
LIM-1530Fixed an issue where the evaluation error popover could overflow to the end of the screen.
### Known issues
Issue KeyDetails
LIM-1450Deleting an official limit makes the associated temporary limits invisible in the table. As a workaround, delete the temporary limit first.
LIM-1426Incidents workflows are not created/updated when modified via the IncidentCrudService. This does not apply on evaluation.
LIM-1309Wildcards and exclusive scopes are not handled by the IScopeRetrievalService default implementation. This affects the members visible in the scope level name and scope level member hierarchies, but only applies if exclusive scopes are used.
BAS-1330Deleting the last limit value deletes the limit structure. As a workaround, don’t delete all limits on a limit structure unless you are sure that the structure won’t be used again. Alternatively, if you do need to reuse the structure, you can create a limit on it using the endpoint /modules/limits-module/limits/rest/v2/limitDefinition/limits/save. The key of the limit structure will still be visible in the admin-ui.
LIM-846Complex Scopes: Currently, a limit with an aggregated scope and a limit with a non-aggregated scope cannot be created on the same limit structure. As a workaround, create the limits on two separate structures.
LIM-840Complex Scopes: Currently, limits can’t be defined with an aggregated scope location and another scope location. As a workaround, create two separate limits on two separate structures.
LIM-813Managers can incorrectly upload Limit Structures through the REST endpoint.
LIM-594Having email notifications enabled for breaches causes decreased limit evaluation performance. See Configuring the breach email on how to disable breach emails.
LIM-357The Six Eyes workflow is currently not implemented.
LIM-346Limits on calculated measures only work through File Upload, not through the UI.
LIM-320Calculated measures need to be included in Pivot Table Query in order to view a Limit’s KPI in the Pivot Table. See Measures for more on how to create a query for Limits on calculated measures.
### Added
Issue KeyDetails
LIM-468The default format for KPI Goal values can now be configured using the limits.cube.format.kpi-goal property.
LIM-987You can now drill down by a limit scope’s level name and level values in a pivot table.
LIM-1045Updated Atoti Server to version 6.1.1. This includes the upgrade of artifacts required to connect to 6.1.1 versions of Atoti Server.
LIM-1155Added an IScopeRetrievalService and a default implementation, facilitating granular querying of the scopes stores by passing a level or a member.
LIM-1199Limits CSV files can now contain Simplified Scopes.
LIM-1200An “Available Amount” and “Utilization %” measure for each KPI has been added to the limits-auto-config, calculating the difference and quotient between a KPI’s goal and the KPI’s value, respectively.
LIM-1205Added a property to configure whether or not filters are applied on evaluation.
LIM-1234Added support for permission-based data access depending on the user’s role. See Data access permissions.
LIM-1268Moved core configuration classes from limits-activeviam to limits-starter.
LIM-1275Added debug logs when evaluating Atoti Limits KPIs detailing eligible limits, exposures, and evaluation location.
LIM-1299Added connector artifacts for versions of Atoti Server running on Java 11.
LIM-1302Added support for restricting access on scopes in the role permissions.
LIM-1318Updated the Workflow Common Library to version 2.4.1 and H2 to version 2.2.220 to fix CVEs.
LIM-1324Pagination has been added to the Limits viewer.
LIM-1328Added new matchMode values for scopes to support more flexible retrievals in the IScopeRetrievalService. For details, see Match mode.
LIM-1339Added permission roles to control user access to UI actions.
LIM-1340Permission roles are now enforced on REST requests, blocking the action from being processed by the server if the user does not have the required permissions.
LIM-1341Permission roles for the workflow actions of approving/rejecting limits and processing incidents are now supported.
LIM-1345Improved performance in the Limits viewer screen by using the ScopeCacheService to help retrieve scope objects.
LIM-1355Added /limits/rest/v2/limitDefinition/limits/status/get endpoint to get limits status & server setting to include status for limit structures.
LIM-1357Added new property to set the default-scope-match-mode for scope permissions.
LIM-1369Added new property to set the owner role(s) for KPIs and calculated members Limits creates in connected Atoti servers. This property is optional and can be auto-configured.
LIM-1373Updated Data Connectors to version 4.2.0-AS6.1.
LIM-1377Added a service in the connected servers to be triggered on limit events. See Sending events to your connected server.
LIM-1382Atoti Limits has been upgraded to Atoti Server 6.1.1. The 6.0.X and 6.0.X-sb3 modules have been upgraded to use Atoti Server 6.0.17 and 6.0.17-sb3 respectively.
LIM-1390Permissions for uploading/downloading limits are now supported.
LIM-1395Added Alive field to the Limits store to indicate if a limit is active or deleted/expired.
LIM-1356Separate loading of workflow statuses by setting -Dlimits.workflow\.workflow-status-fetched-with-limit=false.
LIM-1418The datepicker for the limit start date in the Limits viewer screen now defaults to the server’s as of date.
LIM-1449Added re-evaluate action for reviewed incidents to allow them to be re-evaluated.
LIM-1466Updated Common Library to version 2.1.0-AS6.1.
### Changed
Issue KeyDetails
LIM-1033Maven artifact groupIDs have been renamed from com.activeviam.limits to com.activeviam.solutions.limits to align with other ActiveViam Business Solutions.
LIM-1096KpiCrudService and KpiCrudRestService have been updated, separating the two classes into a Spring Service and a REST Controller wrapper.
LIM-1257Improved handling of workflow-related exceptions so better information is provided in UI responses.
LIM-1276The limits-auto-config API has been improved. For more information see Atoti Java.
LIM-1298Improved property handling in Atoti Limits auto-configuration.
LIM-1300Modified properties of LimitsWorkflowConfigurationProperties to add a new token. Root for these properties is now limits.workflow.
LIM-1304The “DTO” suffix has been removed from java objects that were not pure data transfer objects.
LIM-1310“Complex scopes” have been renamed to “Advanced scopes”.
LIM-1314Improvements have been made to the validation framework. See the custom validator page for more information.
LIM-1323Improved performance of filters in Limits tables.
LIM-1344The ILimitsRetrievalService methods have been updated and the implementation modified to avoid executing methods recursively and to reduce the number of transactions in methods. For more details, see Changes to IlimitsRetrievalService.
LIM-1359The limits-shared-properties module has been renamed to limits-common and the limits-lookup-postprocessors modules have been merged into the limits-integration and limits-common modules.
LIM-1410Merged RemoteLimit, RemoteLimitEntity and LimitGoal into the new SimpleLimit class.
Issue KeyDetails
LIM-285Between and Not Between KpiTypes have been disabled. For more information, see Removing Between and Not Between KPI types.
LIM-658The properties for the Atoti Limits content server have been removed as they are no longer used.
LIM-1231The manual configuration has been removed in favor of auto-configuration.
LIM-1274private\_ and internal imports have been removed from Atoti Limits.
LIM-1312Removed support for Atoti Server version 5.11 as it is no longer supported by ActiveViam.
### Fixed
Issue KeyDetails
LIM-1303Fixed the admin-ui database tab by adding @EnableWebMvc and removing custom message converters.
LIM-1308Utilizations represented as strings as well as special or undetermined numbers are now handled correctly.
LIM-1325Fixed the scope selector overflowing the popover for large lists of scope members.
LIM-1349Removed the incorrect usage of the thread pool when creating/dropping KPIs in the KpiCrudService.
LIM-1358Updated calculated member creation to set ROLE\_USER as the default owner and reader so all users can see the measures.
LIM-1366Fixed issue with evaluation errors not being cleared when retrying the evaluation.
LIM-1371Limits are now correctly evaluated via the Inventory screen or REST services when cube filters are disabled.
LIM-1375The “Available amount” and “Utilization perc.” measures are now available for limits created both on startup and at runtime.
LIM-1413Removing the row(s) on the last page of the Limits Viewer table will no longer result in a table with an empty page. This includes deleting limits and canceling limit creation.
LIM-1416The Re-Evaluate icon for incidents in the Status screen is now disabled for users with no permission to evaluate limits.
LIM-1429Fixed an issue where restarting Atoti Limits in persistent mode did not restore the object and workflow states.
LIM-1430Corrected Limits roles documentation for roles that were previously prefixed by GROUP\_, but are now prefixed by ROLE\_.
LIM-1439Fixed the Limits viewer column configurator allowing reordering columns.
### Known issues
Issue KeyDetails
LIM-1450Deleting an official limit makes the associated temporary limits invisible in the table. As a workaround, delete the temporary limit first.
LIM-1426Incidents workflows are not created/updated when modified via the IncidentCrudService. This does not apply on evaluation.
LIM-1309Wildcards and exclusive scopes are not handled by the IScopeRetrievalService default implementation. This affects the members visible in the scope level name and scope level member hierarchies, but only applies if exclusive scopes are used.
BAS-1330Deleting the last limit value deletes the limit structure. As a workaround, don’t delete all limits on a limit structure unless you are sure that the structure won’t be used again. Alternatively, if you do need to reuse the structure, you can create a limit on it using the endpoint /modules/limits-module/limits/rest/v2/limitDefinition/limits/save. The key of the limit structure will still be visible in the admin-ui.
LIM-846Complex Scopes: Currently, a limit with an aggregated scope and a limit with a non-aggregated scope cannot be created on the same limit structure. As a workaround, create the limits on two separate structures.
LIM-840Complex Scopes: Currently, limits can’t be defined with an aggregated scope location and another scope location. As a workaround, create two separate limits on two separate structures.
LIM-813Managers can incorrectly upload Limit Structures through the REST endpoint.
LIM-594Having email notifications enabled for breaches causes decreased limit evaluation performance. See Configuring the breach email on how to disable breach emails.
LIM-357The Six Eyes workflow is currently not implemented.
LIM-346Limits on calculated measures only work through File Upload, not through the UI.
LIM-320Calculated measures need to be included in Pivot Table Query in order to view a Limit’s KPI in the Pivot Table. See Measures for more on how to create a query for Limits on calculated measures.
### Open CVEs
IssueStatusDetailsImpactingProduct impactWorkaroundFix expected
CVE-2024-38821CriticalSpring WebFlux applications that have Spring Security authorization rules on static resources can be bypassed under certain circumstances. For this to impact an application, all of the following must be true:
- It must be a WebFlux application
- It must be using Spring’s static resources support
- It must have a non-permitAll authorization rule applied to the static resources support.
org.springframework.security:spring-security-webLow. Atoti Server does not ship sensitive static assets, only the stock UI and the necessary config files. All sensitive information is performed in the backend.Use an alternative provider for static resources, like Nginx, at the cost of a more complex security configuration in the Java application.Yes, once Atoti Server is updated to the next version
CVE-2024-28752CriticalAn SSRF vulnerability using the Aegis DataBinding in versions of Apache CXF before 4.0.4, 3.6.3, and 3.5.8 allows an attacker to perform SSRF-style attacks on webservices that take at least one parameter of any type. Users of other data bindings (including the default data binding) are not impacted.org.apache.cxf:cxf-coreLow. This CVE is present in the limits-atoti-server-60-sb3 artifact which is only intended for testing purposes.Upgrade to the latest version of Atoti Server.No, as this CVE only exists in an artifact intended for testing purposes.
CVE-2022-1471CriticalSnakeYaml’s Constructor class, which inherits from SafeConstructor, allows any type to be deserialized given the following line:
new Yaml(new Constructor(TestDataClass.class)).load(yamlContent);
Types do not have to match the types of properties in the target class. A ConstructorException is thrown, but only after a malicious payload is deserialized.
org.yaml:snakeyamlLow. This CVE is present in the limits-atoti-server-60 artifact which is only intended for testing purposes.Upgrade to the latest version of Atoti Server.No, as this CVE only exists in an artifact intended for testing purposes.
CVE-2016-1000027CriticalPivotal Spring Framework before 6.0.0 suffers from a potential remote code execution (RCE) issue if used for Java deserialization of untrusted data. Depending on how the library is implemented within a product, this issue may or not occur, and authentication may be required.org.springframework:spring-web, com.activeviam.activepivot:activepivot-server-springLow. Only applies to Atoti Server version 6.0.x artifacts. Remote invocation is used for services defined by com.qfs.server.cfg.impl.ActivePivotRemotingServicesConfig. They can be optionally imported and are historically required for ActivePivotLive, an old abandoned version of AtotiUI.Do not import com.qfs.server.cfg.impl.ActivePivotRemotingServicesConfig in projects.No, as the only fix is migrating to Spring 6 by upgrading your connected server to Atoti Server version 6.0.x-sb3 or higher.
# Migration guide 4.0 Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/4.0/migrate-4.0 This guide explains the changes required to migrate to the stated version of the Atoti Limits. ## Migrate to 4.0.5 No migration necessary. ## Migrate to 4.0.4 ### Summary * **Recommended performance enhancement:** Disable scope hierarchies for large cardinalities of limit scopes. * **Warning Threshold:** Intrepretation of the [warning threshold](#warning-threshold) limit has been updated. #### Disabling scope hierarchies The [scope level name](../../../user-ref/cube/scope-level-name) and [scope level member](../../../user-ref/cube/scope-level-member) hierarchies can incur a performance cost when using Atoti Limits with limits with a high cardinality of scopes. We recommend disabling scope hierarchies if you do not require these hierarchies to improve the overall performance of Atoti Limits. This can be done by setting the property `limits.cube.scope-hierarchies-enabled=false` in the `application.yml` file of your Atoti Limits application. #### Warning threshold In version 4.0.1, the interpretation of the warning threshold was updated. The new behavior, along with the Atoti Limits and Atoti UI documentation, clarifies that the threshold is a direct percentage of the limit’s utilization. If you updated a limit’s warning threshold or defined new warning thresholds using Atoti Limits in version 4.0.1-4.0.3, you may need to update your warning thresholds to ensure they are still aligned with your expectations. ##### Example The following illustrates the updated behavior. Consider a limit with these settings: * **Rule**: GREATER\_THAN * **Warning**: True (80%) * **Absolute Value**: False * **Limit Value**: 1000 The UI wording and warning range have changed as summarized in the following table:
Previous behavior
(4.0.1-4.0.3 )
New (and original) behavior
(pre 4.0.1 and 4.0.4+)
UI Wording“Warn when within % of limit value”“Warn when utilization reaches % of a limit”
Limit will warn in the range\[200, 1000]\[800, 1000]
## Migrate to 4.0.3 ### Summary This is a maintenance release that includes bug fixes and performance improvements. ### Deprecations #### `ILimitsActivitiAuthenticationManager` The `ILimitsActivitiAuthenticationManager` interface is no longer used, has been deprecated and marked for removal. This interface was previously used to authenticate requests to the Activiti engine in threads spawned by the DLC. It is no longer used and the authentication is now managed by the `DelegatingSpringSecurityContextDataLoadController`. It will be removed in the next minor release. #### `IWebClientService` The `getWithAuth(...)` methods in `IWebClientService` have been deprecated and marked for removal. These are no longer invoked and the default implementations of these methods in `WebClientService` now throw an `UnsupportedOperationException`. The `get(...)` methods are now used instead. If you have custom code that calls the `getWithAuth(...)` methods you will need to update it to use the `get(...)` methods instead. #### `ConnectedAtotiServer` and `ConnectedAtotiServersManager` deprecations The following fields have been deprecated and marked for removal in `ConnectedAtotiServer` and `ConnectedAtotiServersManager`. These are no longer required because the `ILimitsRestClientBuilderProvider` is responsible for authenticating requests, so we don’t need to pass these variables through the application. `ConnectedAtotiServer` fields: * `authentication` * `limitsAuthentication` * `servicePrincipal` * `useJwtMachineToMachineAuth` `ConnectedAtotiServersManager` fields: * `contentServerAuth` * `limitsAuth` * `servicePrincipal` * `useJwtMachineToMachineAuth` ### Configuration properties #### Properties deprecated ##### [limits-integration-common module](../../../user-ref/properties/config-properties/limits-integration-common)
Property NameComment
limits.autoconfiguration.limits-authenticationThis property has been deprecated and will be removed in the next minor release. It is currently used to configure Basic Authentication which will be replaced with JWT Authentication.
limits.autoconfiguration.authenticationThis property has been deprecated and will be removed in the next minor release. It is currently used to configure Basic Authentication which will be replaced with JWT Authentication.
limits.autoconfiguration.content-server.authenticationThis property has been deprecated and will be removed in the next minor release. It is currently used to configure Basic Authentication which will be replaced with JWT Authentication.
## Migrate to 4.0.2 ### Summary * [`WebClientService` changes](#webclientservice-changes) * [Calculated measure location](#calculated-measure-location) ### `WebClientService` changes If you previously extended `WebClientService`, update it to implement the new `IWebClientService` interface. The methods are unchanged, but Atoti Limits now references `IWebClientService` instead of `WebClientService`. ```java theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} /** * IWebClientService * *

This service is used to send authenticated requests from the Atoti Limits Server to * application servers. * * @author ActiveViam */ public interface IWebClientService { /** * Sends a POST request with the {@link RestClient} API. * * @param serverName - The target server for this {@link RestClient}'s Http requests * @param path - The path of the endpoint receiving the request * @param jsonBody - The POST request's payload body * @param errorMessage - A custom error message if an exception occurs * @return The POST response as a String */ String post(String serverName, String path, String jsonBody, String errorMessage); /** * Sends a POST request with the {@link RestClient} API. * * @param serverName - The target server for this {@link RestClient}'s Http requests * @param path - The path of the endpoint receiving the request * @param jsonBody - The POST request's payload body * @param errorMessage - A custom error message if an exception occurs * @param extractResponseBody - If true, construct a {@link JsonErrorException}, else, throw a * {@link LimitsWebClientServiceException} * @return The POST response as a String */ String post( String serverName, String path, String jsonBody, String errorMessage, boolean extractResponseBody); /** * @param url - The {@code url} of the endpoint receiving the request * @param server - The target server for this {@link RestClient}'s Http requests * @param errorMessage - A custom error message if an exception occurs * @return The GET response as a String */ String get(String url, String server, String errorMessage); /** * @param url - The {@code url} of the endpoint receiving the request * @param server - The target server for this {@link RestClient}'s Http requests * @param errorMessage - The custom error message if an exception occurs * @param extractResponseBody - If true, construct a {@link JsonErrorException}, else, throw a * {@link LimitsWebClientServiceException} * @return The GET response as a String */ String get(String url, String server, String errorMessage, boolean extractResponseBody); /** * @param url - The {@code url} of the endpoint receiving the request * @param authorization - The encoded {@code authorization} string * @param errorMessage - The custom error message if an exception occurs * @return The GET response as a string */ String getWithAuth(String url, String authorization, String errorMessage); /** * Makes a GET request with the authentication already encoded. This method is called when sending * requests to the RemoteContentServer, which doesn't have a `serverName` but already has an * encodedAuth string. * * @param url - The {@code url} of the endpoint receiving the request * @param authorization - The encoded {@code authorization} string * @param errorMessage - A custom error message if an exception occurs * @param extractResponseBody - If true, construct a {@link JsonErrorException}, else, throw a * {@link LimitsWebClientServiceException} * @return The GET response as a String */ String getWithAuth( String url, String authorization, String errorMessage, boolean extractResponseBody); /** * Sends a PUT request with the {@link RestClient} API. * * @param serverName - The target server for this {@link RestClient}'s Http requests * @param path - The path of the endpoint receiving the request * @param body - The PUT request's payload body * @param responseType - The expected response type * @return The PUT response as a String */ ResponseEntity put(String serverName, String path, Object body, Class responseType); } ``` ### Calculated measure location If you have limits on calculated measures, we expect that these calculated measures are saved in either the `/pivot/entitlements/cm` folder of the content server (recommended) **OR** in the `ui/calculated_measures` folder (not recommended). If you have limits on calculated measures that exist in both folders, then those in `ui/calculated_measures` should be moved to `/pivot/entitlements/cm`, otherwise these limits won’t be created. The `ui/calculated_measures` folder is the location for calculated measures that were saved via ActiveUI 4, so we do not expect most users will need to migrate. ### Configuration files #### Files Modified ##### Properties added ###### [limits-activeviam module](../../../user-ref/properties/config-properties/limits-activeviam)
PropertyDefault valueDescription
limits.autoconfiguration.use-jwt-machine-to-machine-authfalseTrue if JWT Authentication should be used when sending requests from Atoti Limits to connected Atoti Servers. If false, Basic Authentication will be used by default unless you implement your own ILimitsRestClientBuilderProvider bean.
limits.autoconfiguration.service-principalThe name of the user authenticated to perform machine-to-machine requests from Atoti Limits to connected Atoti Servers, if using JWT Authentication.
## Migrate to 4.0.1 Upgrading from version *4.0.0*, see the [Atoti Limits 4.0.1 Release Notes](../../release-notes#401). ### Summary * **Disable Scope Hierarchies**: We have added a property `limits.cube.scope-hierarchies-enabled` that can be used to disable scope hierarchies to improve loading performance for large cardinalities of limit scopes. * **Roles**: `ROLE_USER` no longer required in Atoti Limits. ### Configuration files #### Files Modified ##### Properties added ###### [limits-activeviam module](../../../user-ref/properties/config-properties/limits-activeviam)
PropertyDefault valueDescription
limits.autoconfiguration.use-jwt-machine-to-machine-authfalseTrue if JWT Authentication should be used when sending requests from the Atoti Server to Atoti Limits. If false, Basic Authentication will be used by default unless you implement your own ILimitsRestClientProvider or ILimitsRestTemplateProvider bean.
limits.autoconfiguration.service-principalThe name of the user authenticated to perform machine-to-machine requests from the Atoti Server to Atoti Limits, if using JWT Authentication.
### Other changes #### `ROLE_USER` no longer required in Atoti Limits `ROLE_USER` is no longer a required role for all users in Atoti Limits. Previously, this role was required because it was hardcoded as the `owner`/`reader` of KPIs created by Atoti Limits. Now, the role set as the `owner`/`reader` of KPIs created by Atoti Limits is auto-configured, or can be overridden using the `limits.autoconfiguration.content-server.limits-created-measures-owners` property. Users will need to have this auto-configured (or overridden) role, or a [data access role](../../../dev/roles/data-access-permissions), to view KPIs created by Atoti Limits, including the calculated members related to the KPIS. ## Migrate to 4.0.0 Upgrading from version *3.3.0*, see the [Atoti Limits 4.0.0 Release Notes](../../release-notes#400). Atoti Limits is using Atoti Server 6.1.1 and Atoti UI 5.2.x. For new features and fixes included in these releases, please see the [Atoti UI documentation](https://docs.activeviam.com/products/atoti/ui/5.2/) and [Atoti UI Migration Notes](https://docs.activeviam.com/products/atoti/ui/5.2/docs/changelog), and the [release notes for Atoti Server](https://docs.activeviam.com/products/atoti/server/6.1.1/docs/release/changelog/index.). Please note that Atoti Server version 5.11 is now out-of-support. Therefore, we will no longer support connections to servers of this version as of this release of Atoti Limits. ### Summary * **Atoti Server upgrade**: Atoti Limits has been upgraded to Atoti Server 6.1.1. For the required changes, see [Atoti Server upgrade](#atoti-server-upgrade). * **Atoti UI upgrade**: Atoti UI has been upgraded to version 5.2.0. For the required changes, see the [Atoti UI migration guide](https://docs.activeviam.com/products/atoti/ui/latest/docs/migration/5.1-to-5.2/). * **Maven Artifact group ID changes**: The `groupID`s for maven artifacts have been updated from `com.activeviam.limits` to `com.activeviam.solutions.limits` to align with other ActiveViam Business Solutions. Please update your `groupID`s when importing Atoti Limits artifacts. This change does not affect package names. * **Improvements to the auto-configuration modules**: These improvements require you to update dependencies and properties. * **Simplified scopes migration script**: We have added an optional script for migrating CSV files to use the simplified scope notation. See [CSV migrations to 4.0.0](#csv-migrations-to-400). ### Breaking changes * **Starter changes**: Multiple classes have been removed from the starter module. See [Starter changes](#starter-changes) for more details. * **Removal of DTO suffix**: The “DTO” suffix has been removed from Java objects that were not pure data transfer objects. See the full list of changes [below](./migrate-4.0#removal-of-dto-suffix). * **Manual configuration removal**: Manual configuration has been removed in favor of auto-configuration. #### Atoti Server upgrade For details on migrating your code to Atoti Server 6.1.1, see [the Atoti Server migration notes](https://docs.activeviam.com/products/atoti/server/6.1.1/docs/release/migration_notes/). There is a [java-api-migration-tool](https://github.com/activeviam/java-api-migration-tool) available to help you migrate your code. We highly recommend that you use this tool. Here are the main changes you need to make to your Atoti Limits code: ##### Java 21 Update your Java version to Java 21 or later in order to run Atoti Limits. ##### Atoti Spring Boot Starter changes Atoti Server now ships with a suite of [Spring Boot Starters](https://docs.activeviam.com/products/atoti/server/6.1.1/docs/starters/starters_directory/). These dependencies auto-configure default imports required by Atoti Server, that you may override at runtime. If you do not use the out-of-the-box `limits-starter`, import these starter dependencies and remove any explicit import of classes that are now auto-configured. If you do use the out-of-the-box `limits-starter`, no further changes are required. The following core classes have been removed in `limits-activeviam` or `limits-starter` as they are now inherited from starters: * `ActivePivotServicesConfig.class` * `ActivePivotWebSocketServicesConfig.class` * `ActivePivotWithDatastoreConfig.class` * `ActivePivotXmlaServletConfig.class` * `ActiveViamRestServicesConfig.class` * `AdminUIResourceServerConfig.class` * `AtotiServerWebMvcConfigurer.class` * `ContentServerWebSocketServicesConfig.class` * `FullAccessBranchPermissionsManagerConfig.class` * `JwtConfig.class` * `LocalI18nConfig.class` * `NoSecurityDatabaseServiceConfig.class` * `TracingConfig.class` ##### Security configuration changes The upgrade to Atoti Server 6.1.1 includes changes to the security configuration. We expect you to implement your own security, but we provide a sample configuration in the `com.activeviam.limits.starter.cfg.security` package. This is not a production grade sample. For details on how to implement your own security, please see the [Atoti Server documentation](https://docs.activeviam.com/products/atoti/server/6.1.1/docs/starters/atoti_starter/#stock-security). #### Starter changes Most of the `limits-starter` module has been moved into `limits-activeviam`. The goal of these changes is ultimately to improve the developer experience when migrating, particularly in the context of client customizations. Please see the [Getting Started guide](../../../dev/getting-started) for more details on how to structure your project. To this end, we have made the following changes: * We have added a new `LimitsCoreAutoConfiguration` class in `limits-activeviam`. This is a base configuration class for the imports required by Atoti Limits and is auto-configured on startup. * Most of `LimitsAppConfig` has been moved to `LimitsCoreAutoConfiguration`. * `LimitsApplicationConfigurationPropertiesConfig` has been removed and the properties have been moved into the `@EnableConfigurationProperties` annotation in `LimitsCoreAutoConfiguration`. * We have added a new `LimitsRestServicesAutoConfiguration` class to import all the REST services required by Atoti Limits. * `LimitsProcessExceptionHandler` has been removed and the exception handlers it contained have been merged into `RestExceptionHandlerControllerAdvice`. We have converted many of the `*Config` classes explicitly imported in `LimitsAppConfig` to `*AutoConfiguration` classes and moved them to the `com.activeviam.limits.autoconfigure` package in `limits-activeviam`. These new classes will be automatically registered via [Spring Auto-configuration](https://docs.spring.io/spring-boot/reference/using/auto-configuration.), so there is no more need to explicitly import them. The beans that were exposed by these classes are now annotated with `@ConditionalOnMissingBean`, so you can define your own implementations of the interfaces to override the default beans. The following classes have been affected by this change:
Old \*Config classNew \*AutoConfiguration classDescription
DefaultManagedObjectIdentityGeneratorConfigManagedObjectIdentityGeneratorAutoConfigurationConfiguration for the ID generators.
EvaluationServiceConfigLimitsEvaluationServicesAutoConfigurationConfiguration for the services used when evaluating limits.
LimitsContentConfigContentServiceAutoConfigurationConfigurations for the content service.
LimitsDatastoreConfigLimitsDatastoreAutoConfigurationConfiguration for the datastores.
LimitsValidationConfigLimitsValidationAutoConfigurationConfiguration for the validation API.
LimitsWorkflowConfigLimitsWorkflowAutoConfigurationConfigurations for the workflow.
PivotConfigLimitsManagerAutoConfigurationConfiguration for the services used when evaluating limits.
The following classes have been moved from `LimitsAppConfig` to `LimitsCoreAutoConfiguration`: * `LimitsActivitiAuthenticationManager`, * `LimitsDataProperties` * `LimitsDimensionsConfig` * `LimitsCubeConfig` * `LimitsAsOfDateLoader` * `DataLoadControllerConfig` * `CSVSourceConfig` * `LimitsProcessEngineMailConfig` * `ConnectedAtotiServersManager` (previously `RemoteAtotiServersProperties`) * `LimitsManagerConfig` (previously `PivotConfig`) The following classes have been moved from `LimitsAppConfig` to the new `LimitsRestServicesAutoConfiguration` class: * `AutoConfigRestService` * `DataLoadControllerRestServiceConfig` * `IncidentRestController` * `IncidentsSseController` * `KPICrudRestService` * `LimitsAsOfDateRestService` * `LimitsDefinitionCrudRestService` * `LimitsEvaluationRestService` * `LimitsServerSettingsRestController` * `RemoteCubeRestService` * `RestExceptionHandlerControllerAdvice` * `ScopeRetrievalRestService` * `UploadCsv` The following classes have been moved from `LimitsAppConfig` to the new `LimitsDatastoreAutoConfiguration` class: * `AtotiServerWithDatastoreConfig` * `DatastoreConfiguratorSetup` * `LimitsDatastoreService` * `LimitsDatastoreVersionService` * `LimitsDefinitionDatastoreConfig` * `LimitsProcessInstanceDatastoreConfig` * `LimitsSchema` * `ScopeTupleGenerator` * `TuplePublisherConfig` The following classes have been moved from `LimitsAppConfig` to the new `LimitsCrudServicesAutoConfiguration` class: * `IncidentCrudService` * `KpiCrudService` * `LimitsCrudService` * `LimitsRetrievalService` The following classes have been moved from `LimitsAppConfig` to the new `LimitsEvaluationServicesAutoConfiguration` class: * `DefaultEvaluationService` * `DefaultEvaluationTaskManager` * `EvaluationErrorHandler` The following classes have been moved from `LimitsAppConfig` to the new `LimitsJpaAutoConfiguration` class: * `LimitsJpaConfig` * `LimitsProcessJpaConfig` The following classes have been moved from `LimitsAppConfig` to the new `LimitsPersistenceServicesAutoConfiguration` class: * `DefaultLimitsAppCrudService` * `DefaultLimitsAppDatastoreCrudService` The following classes have been renamed:
Old class nameNew class name
PivotManagerLimitsManagerDescriptionConfig
#### Improvements to the auto-configuration modules Although we do not intend for these modules to be extended, we have made improvements to the auto-configuration modules that are breaking. You won’t need to update code, but you’ll need to update dependencies and properties. For more information see [the connected server section](../../../dev/integration/java). ##### Changes requiring action
Breaking changeAction required
The limits-auto-config-ap\ artifacts have been renamed to limits-auto-config-\.Update your dependency import.
The limits-auto-config modules are now true auto-configuration modules, meaning you now only have to import the dependency, not the classes.Remove the previous import of LimitsAutoConfig.
The old autoconfiguration properties have been replaced with new properties.Update your properties accordingly.

Only four properties are marked as REQUIRED.

##### Changes not requiring action * `LimitsAutoConfig` has been renamed to `LimitsConnector`. * `RemoteAtotiServersProperties` was used in the past to store the connected servers in Atoti Limits and as a configuration source for the manual configuration. As we have removed the manual configuration, it has been renamed to `ConnectedAtotiServersManager`. * The `com.activeviam.limits.autconfig.*` packages have been renamed to `com.activeviam.limits.autoconfigure.*`. * The `com.activeviam.limits.integration.common.*` packages have been renamed to `com.activeviam.limits.autoconfigure.common.*`. * The `limits-auto-config-ap` artifacts have been renamed to `limits-auto-config-`. * The `lookup-post-processor-ap` artifacts have been renamed to `lookup-post-processor-`. #### Artifact changes We have reorganized the artifacts used by the connected server to connect with Atoti Limits. We do not expect users to have to modify their code to accommodate these changes, but we shall provide them nonetheless for clarity. This includes artifacts for connecting with instances of Atoti Server on version `6.0.x` using Java 11, in addition to the already supported `6.0.x-sb3` version using Java 17. The `limits-shared-properties` module has been renamed to `limits-common` and the `limits-lookup-postprocessors` modules have been merged into the `limits-integration` and `limits-common` modules. This helps: * reduce the number of modules in the project, * simplify the usage of Spring in the `LookUpPostProcessor`, * facilitate future improvements by having more reusable code across Atoti Server version-specific modules. The artifact structure is as follows: * **limits** * **limits-activeviam** - Source code for the services required by Atoti Limits. * **limits-atoti-server** - An Atoti Server sandbox used for **testing** Atoti Limits. **Not intended for production.** * **limits-atoti-server-60** - Atoti Server sandbox running on `6.0.X`. * **limits-atoti-server-60-sb3** - Atoti Server sandbox running on `6.0.X-sb3`. * **limits-atoti-server-61** - Atoti Server sandbox running on `6.1.X`. * **limits-integration** - Code to integrate Atoti Server with Atoti Limits. * **limits-auto-config-60** - Code to integrate Atoti Server with Atoti Limits `6.0.X`. * **limits-auto-config-60-sb3** - Code to integrate Atoti Server with Atoti Limits `6.0.X-sb3`. * **limits-auto-config-61** - Code to integrate Atoti Server with Atoti Limits `6.1.X`. * **limits-migrations** - Scripts to migrate Atoti Limits. * **limits-common** - Code common to both `limits-activeviam` and `limits-integration` modules. * **limits-starter** - Lightweight Spring Boot application used to get Atoti Limits up and running quickly. The artifact changes from the previous release are as follows:
Old NameNew NameComment
limits-shared-propertieslimits-commonThe old artifact has been renamed.
limits-common-lookuplimits-commonThe old artifact has been merged into the new artifact.
lookup-post-processor-ap60limits-auto-config-60-sb3The old artifact has been merged into the new artifact and requires Java 17.
N/Alimits-auto-config-60This new artifact is compatible with Java 11.
limits-auto-config-ap60limits-auto-config-60-sb3The old artifact has been renamed and requires Java 17.
limits-atoti-server-60limits-atoti-server-60-sb3The old artifact has been renamed and requires Java 17.
N/Alimits-atoti-server-60This new artifact is compatible with Java 11.
#### Removal of DTO suffix We have removed the “DTO” suffix from classes that were not pure data transfer objects. Please update any references to these classes in your custom code: * `LimitDTO.java` * `LimitStructureDTO.java` * `IncidentDTO.java` * `LimitsProcessInstanceDTO.java` * `HistoricalClassDifferenceDTO.java` * `HistoricalFieldDifferenceDTO.java` * `CalculatedMeasureDTO.java` * `CalculatedMeasuresDTO.java` * `ContentServerElementDTO.java` * `ContentServerEntryDTO.java` #### CSV migrations to 4.0.0 The migration script migrates the `limits.csv` files from Atoti Limits 3.3.0 to 4.0.0 by converting the scope value to the new simplified notation. Migrating the `limits.csv` files from Atoti Limits 3.3.0 to 4.0.0 is NOT a required migration. Scopes in the old format will still work in Atoti Limits 4.0.0. ##### How it works This script expects the following program arguments (in this order): 1. The target version of Atoti Limits (should be `4.0.0`). 2. The source limits input file path. 3. The target limits output file path. ##### Steps 1. Run `mvn clean install` on `limits-migrations`. 2. Run `java -jar path/to/limits-migrator-tool-exec.jar 4.0 path/to/source/limits.csv path/to/target/limits.csv path/to/properties/folder`. Your files are now converted to the new format and can be found in the target directory. The output directory must already exist, but the file will be created. #### Changes to `ILimitsRetrievalService` The `ILimitsRetrievalService` interface has been updated and the default implementation, `LimitsRetrievalService`, has been significantly changed to improve performance. If you have implemented a custom version of this service, you will need to make the following method changes:
Old signatureNew SignatureNote
ILimitsDatastoreVersionService getLimitsDatastoreVersionService();N/AThis method has been removed.
IDatabaseVersion getDatastoreVersion(LimitsQueryPayload limitsQueryPayload);IDatabaseVersion getDatastoreVersion(String branchName);This method has been modified to accept a string argument specifying the name of the branch on which to execute the query.
Integer getPendingApprovalsForLimitStructure(String limitStructureId);Map\ getPendingApprovalsForLimitStructure(Set\ limitStructureIds);This method has been updated to accept a set of limit structure IDs and return a map of those IDs to the number of pending approvals. This improves performance for UI requests on the Inventory screen.
#### Removing manual configuration The manual configuration has been removed from Atoti Limits. Please see the [removed properties table](#properties-deleted) for the properties you should remove. ### Validator API changes Several API changes have been made to the `IValidator` interface: * The `ILimitValidator`, `ILimitStructureValidator`, and `IIncidentValidator` interfaces have been moved to the `com.activeviam.limits.model.validation.function.intf` package. * The `getInvalidObjects()` method has been removed since it was not used. * The `reset(boolean throwException)` method has been updated to an empty default implementation and is overridden by the abstract class, `AValidator`. To override the `reset` method, see the [custom validator](../../../dev/dev-extensions/custom-validation/custom-validators) page for more information. ### Removing Between and Not Between KPI types The `Between` and `Not Between` Kpi types have been removed as valid KPI types since they were never supported by Atoti Limits. ### Configuration #### Configuration properties ##### Files Modified ###### [limits-integration-common module](../../../user-ref/properties/config-properties/limits-integration-common) All properties have been replaced. Please see the [new properties](../../../user-ref/properties/config-properties/limits-integration-common) for the updated list. ##### [limits-activeviam module](../../../user-ref/properties/config-properties/limits-activeviam) ###### Properties added ###### [limits-activeviam module](../../../user-ref/properties/config-properties/limits-activeviam)
PropertyDefault valueDescription
limits.cube.format.kpi-goal#,##0.#Format value for KPI Goal values.
limits.cube.kpi-filters-enabledtrueTrue if cube filters are enabled for Limits KPIs, false otherwise.
limits.data-access-control.servers..role-permissionsDefines the permissions available to each role.
limits.data-access-control.servers..default-scope-match-modeMATCH\_ALLSets the match mode to use for scope permissions when it is omitted.
limits.autoconfiguration.content-server.limits-created-measures-ownersThe roles that will be the owner/reader for the calculated members that were created based on the KPIs. The value should be auto-configured from the KPI owners in the content server.
limits.workflow\.workflow-status-fetched-with-limittrueWhen set to true, retrieving limit structures also updates the limit status with the current workflow status.
#### Property files No changes. ### Datastores #### Modified stores
ModificationStoreFieldTypeDescription
AddedLimitsAliveBooleanThis field indicates whether the limit is still alive (not deleted or expired). For more details, see Alive field in Limits store.
### Cube schema #### Added
CubeDimensionHierarchyLevelsDatastore fieldsDetails
LimitsLimitScope Level NameScope Level NameScopeKeysThe level name of a limit’s scope, for example Book\@Books\@Booking.
LimitsLimitScope Level MemberScope Level MemberScopeValuesThe level member of a scope, for example Book 1.
### Measures No changes. ### Other changes #### Independent retrieval of limit status `/limits/rest/v2/limitDefinition/limits/status/get` retrieves status of Limits based on their id. This completes the server setting `workflow-status-fetched-with-limit` to omit status when fetching limits structures with `/limits/rest/v2/limitDefinition/structure/get`. This helps loading the limits viewer screen in the Atoti UI when the amount of Limits in a structure is relatively large. If a long time is experienced when fetching the Limits in the UI (more than a few seconds) this aims at retrieving the Limits faster by decoupling the retrieval of each Limit’s status. #### `Alive` field in `Limits` store Due to the [independent retrieval of limit status](#independent-retrieval-of-limit-status), a field has been added to the [Limits store](../../../user-ref/datastore/limits-store) to keep track of whether a limit is alive (not expired or deleted). This was previously based on the status of the limit, which was stored in the Limits store. However, the status is now exclusively retrieved through the workflow, so information on whether a limit is alive is now independent of the status, so it can be retrieved at a later stage. This store field defaults to `true` and cannot be set via CSV source as we expect any limit loaded from file existing at its creation. To access a deleted or expired limit, it should be persisted in the audit trail. #### `ROLE_LIMITS` is no longer a required role The `ROLE_LIMITS` role is no longer required for all users of Atoti Limits. This role has been repurposed as the [full-access role](../../../dev/roles/limits-roles#role_limits-full-access) in the permission roles to maintain backward compatibility. Users with this role will continue having full access to all actions in the UI as they previously did. `ROLE_LIMITS` is still used to tag KPIs created by the module, but user access to the KPIs is controlled by the `ROLE_USER` role, which is still [required](../../../dev/roles/limits-roles#role_user). # Release notes 4.0 Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/4.0/release-notes-4.0 For the list of issues covered in this release, and known issues, see the [Changelog](./changelog-4.0). For information on upgrading from previous versions, see the [Atoti Limits Migration Guide](./migrate-4.0) Follow [this link](https://activeviam.jfrog.io/artifactory/activeviam-accelerators-artifacts/limits/4.0.5/) to download the zipped distribution files for: * **UI source code** * **UI build** * **Source files** to build the module * **Sample bookmarks** * **Maven repository** required to build the project and run the tests. The Atoti Server 6.1.1 Maven repository files are included in this repository. ### Dependencies
ComponentVersion
Atoti Server6.1.1
Atoti UI5.2.x
Common Dependencies BOM2.1.0 (com.activeviam.apps)
Common Library2.1.0-AS6.1
Common Parent POM2.1.0 (com.activeviam.apps)
Data Connectors4.2.0-AS6.1
JavaJDK21
UI Components5.2.3
Workflow Core2.4.1
### Summary This is a maintenance release that fixes a concurrency issue in limit persistence. **Improvements** * [Limit persistence concurrency fix](#limit-persistence-concurrency-fix) ### Improvements #### Limit persistence concurrency fix `DefaultLimitsAppCrudService` previously only synchronized its `save*` methods, so concurrent `create`/`update`/`delete` calls could run without the lock and interleave their JPA and datastore writes. Every mutating method is now synchronized on the same service monitor, so concurrent limit modifications (for example, from triggers and the UI running at the same time) can no longer interleave and corrupt persisted data.
Follow [this link](https://activeviam.jfrog.io/artifactory/activeviam-accelerators-artifacts/limits/4.0.4/) to download the zipped distribution files for: * **UI source code** * **UI build** * **Source files** to build the module * **Sample bookmarks** * **Maven repository** required to build the project and run the tests. The Atoti Server 6.1.1 Maven repository files can be downloaded from [here](https://artifacts.activeviam.com/share/ActivePivot_stable/6.1.1). ### Dependencies
ComponentVersion
Atoti Server6.1.1
Atoti UI5.2.x
Common Dependencies BOM2.1.0 (com.activeviam.apps)
Common Library2.1.0-AS6.1
Common Parent POM2.1.0 (com.activeviam.apps)
Data Connectors4.2.0-AS6.1
JavaJDK21
UI Components5.2.3
Workflow Core2.4.1
\| Common Dependencies BOM | 2.1.0 (com.activeviam.apps) |
ComponentVersion
Atoti Server6.1.1
Atoti UI5.2.x
Common Dependencies BOM2.1.0 (com.activeviam.apps)
Common Library2.1.0-AS6.1
Common Parent POM2.1.0 (com.activeviam.apps)
Data Connectors4.2.0-AS6.1
JavaJDK21
UI Components5.2.3
Workflow Core2.4.1
### Summary This is a maintenance release that includes performance enhancements, usability improvements, and minor functional updates. **Improvements** * [Evaluation improvements](#evaluation-improvements) * [Bulk Activiti Workflow Transactions](#bulk-activiti-workflow-transactions) * [Limits Data Reload Performance](#limits-data-reload-performance) * [Limits on calculated measures](#limits-on-calculated-measures) * [Smarter Scope Refreshing](#smarter-scope-refreshing) * [Batched Event Sending](#batched-event-sending) ### Improvements #### Evaluation improvements We’ve significantly optimised the evaluation process to improve responsiveness and reduce latency when working viewing KPIs in the cube: * Smarter Caching: Additional caching has been introduced, particularly in areas that handle high-cardinality evaluations involving numerous limits and locations. This reduces repeated computations and speeds up access. * Efficient Location Filtering: Locations are now automatically stripped of members that are irrelevant to the limits being evaluated. This minimises compatibility checks and streamlines processing. * Quicker Short-Circuiting: Evaluations now terminate earlier when incompatible location-limit combinations are detected, saving time and resources. * Improved MDX Query Batching: When evaluations are triggered via the UI, MDX statements are now batched into smaller, more manageable requests. This prevents application cubes from freezing due to large queries and ensures a smoother user experience. #### Bulk Activiti Workflow Transactions Creating workflows for limits and incidents is now significantly faster and more scalable. Instead of processing each workflow individually, the system now initiates them in bulk, reducing wait times and improving responsiveness, especially when dealing with large volumes. This enhancement is particularly beneficial when creating many limits or during post-evaluation processes, where many incident workflows may be triggered at once. Users can expect smoother performance and quicker turnaround when managing high volumes of data. These new services are invoked by default, but you can revert to the old behavior by setting `limits.workflow.enable-bulk-activiti-transactions=false`. #### Limits Data Reload Performance The process of reloading previously saved limits into the datastore has been optimised to reduce startup time. This improvement ensures that systems are ready for use more quickly after a restart, enhancing operational efficiency and reducing downtime for users who rely on timely access to limit data. #### Limits on calculated measures You can now define limits on calculated measures where the underlying is a hierarchy. #### Smarter Scope Refreshing Scopes are now refreshed only if they haven’t already been cached, reducing unnecessary processing and improving system efficiency. #### Batched Event Sending System events are now sent in batches of 10,000 to avoid overload issues on the receiving server, ensuring smoother and more reliable communication.
Follow [this link](https://activeviam.jfrog.io/artifactory/activeviam-accelerators-artifacts/limits/4.0.3/) to download the zipped distribution files for: * **UI source code** * **UI build** * **Source files** to build the module * **Sample bookmarks** * **Maven repository** required to build the project and run the tests. The Atoti Server 6.1.1 Maven repository files can be downloaded from [here](https://artifacts.activeviam.com/share/ActivePivot_stable/6.1.1). ### Dependencies
ComponentVersion
Atoti Server6.1.1
Atoti UI5.2.x
Common Dependencies BOM2.1.0 (com.activeviam.apps)
Common Library2.1.0-AS6.1
Common Parent POM2.1.0 (com.activeviam.apps)
Data Connectors4.2.0-AS6.1
JavaJDK21
UI Components5.2.3
Workflow Core2.4.1
### Summary **New features** * [Limit statuses](#limit-statuses) * [Role-based permissions](#role-based-permissions) * [Configurable limit sensitivity to runtime filters](#configurable-limit-sensitivity-to-runtime-filters) **Improvements** * [UI improvements](#ui-improvements) * [Dependency upgrades](#dependency-upgrades) ### New features #### Limit statuses You can now achieve faster loading times when displaying a limit structure with a large number of limits by enabling a property to fetch the statuses in a separate process. #### Role-based permissions Atoti Limits now supports restricting data access and access to UI actions for users depending on their role. See [Data access permissions](../../../dev/roles/data-access-permissions) and [Permission roles](../../../dev/roles/limits-roles#permission-roles) for more information. #### Configurable limit sensitivity to runtime filters In Atoti Limits, you can now configure whether your limits are sensitive to runtime filters. See [Cube Filters on Limit KPIs](../../../dev/evaluation-tasks/kpi-filters) for more information. ### Improvements #### UI improvements Atoti Limits features a number of improvements that makes interacting with your data easier: * **Paginated limits** : The Limits viewer now supports pagination. * **Enhanced table filtering** : The table filters are now virtualized to improve performance for large data sets. #### Scopes Atoti Limits introduces multiple additions and improvements to enhance defining and retrieving scopes: * **Simplified Scopes** : Scopes in the [limits input file](../../../user-ref/input-files/limits_approve) now support a simplified format. See [Simplified Scopes](../../../dev/scopes/scope-overview#simplified-scopes) for more information and examples. * **Scopes Retrieval Service** : A new Spring service has been added to retrieve [Scopes](../../../dev/scopes) from the datastore. * **Enhanced scope levels** : Users can now drill down by a limit scope’s [level name](../../../user-ref/cube/scope-level-name) and [level member](../../../user-ref/cube/scope-level-member) in a pivot table. #### Enriched business cube measures The [business cubes have been enriched](../../../user-ref/cube/measures/business-cube) with “Available Amount” and “Utilization perc.” calculated measures for each limits KPI. #### Simplified project structure We have simplified the project structure in an effort to ease migrations. Please see the [starter changes](./migrate-4.0#starter-changes). #### Dependency upgrades The following dependency upgrades have been made: * **Atoti Server upgrade** : Atoti Limits has been upgraded to Atoti Server 6.1.1. This version requires Java 21. * **Atoti UI upgrade** : Atoti UI has been upgraded to version 5.2.0. * **Common Parent POM and Common Dependencies BOM upgrade**: The Common Parent POM and the Common Dependencies BOM have both been upgraded to version 2.1.0 (com.activeviam.apps) . This versions updates Spring Boot to version 3.2.9. * **Activiti upgrade** : We have upgraded Activiti to version 8.6.0 to be compatible with Java 21. * **Java 11 connector artifacts** : We have added artifacts for connecting to supported versions of Atoti Server running on Java 11. Besides upgrading to the latest versions, Atoti Server version 5.11 is now out of support and is no longer supported within Atoti Limits.
# Updates since 4.0 pre-releases Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/4.0/updates-since-4.0-prereleases This page lists the [changes since 4.0.0-alpha](#changes-since-400-alpha) and [4.0.0-beta](#changes-since-400-beta), and explains any changes required to migrate from these early releases to the stated version of Atoti Limits: * [Migrate from 4.0.0-alpha](#migrate-to-400-beta) to beta * [Migrate from 4.0.0-beta](#migrate-to-400) to 4.0.0 ## Changes since 4.0.0-beta ### Added
Issue KeyDetails
LIM-987You can now drill down by a limit scope’s level name and level values in a pivot table.
LIM-1318Updated the Workflow Common Library to version 2.4.1 and H2 to version 2.2.220 to fix CVEs.
LIM-1340Permission roles are now enforced on REST requests, blocking the action from being processed by the server if the user does not have the required permissions.
LIM-1341Permission roles for the workflow actions of approving/rejecting limits and processing incidents are now supported.
LIM-1355Added /limits/rest/v2/limitDefinition/limits/status/get endpoint to get limits status & server setting to include status for limit structures.
LIM-1357Added new property to set the default-scope-match-mode for scope permissions.
LIM-1369Added new property to set the owner role(s) for KPIs and calculated members Limits creates in connected Atoti servers. This property is optional and can be auto-configured.
LIM-1373Updated Data Connectors to version 4.2.0-AS6.1.
LIM-1377Added a service in the connected servers to be triggered on limit events. See Sending events to your connected server.
LIM-1382Atoti Limits has been upgraded to Atoti Server 6.1.1. The 6.0.X and 6.0.X-sb3 modules have been upgraded to use Atoti Server 6.0.17 and 6.0.17-sb3 respectively.
LIM-1390Permissions for uploading/downloading limits are now supported.
LIM-1395Added Alive field to the Limits store to indicate if a limit is active or deleted/expired.
LIM-1356Separate loading of workflow statuses by setting -Dlimits.workflow\.workflow-status-fetched-with-limit=false.
LIM-1418The datepicker for the limit start date in the Limits viewer screen now defaults to the server’s as of date.
LIM-1449Added re-evaluate action for reviewed incidents to allow them to be re-evaluated.
LIM-1466Updated Common Library to version 2.1.0-AS6.1.
### Changed
Issue KeyDetails
LIM-1359The limits-shared-properties module has been renamed to limits-common and the limits-lookup-postprocessors modules have been merged into the limits-integration and limits-common modules.
LIM-1410Merged RemoteLimit, RemoteLimitEntity and LimitGoal into the new SimpleLimit class.
### Removed
Issue KeyDetails
LIM-000
### Fixed
Issue KeyDetails
LIM-1303Fixed the admin-ui database tab by adding @EnableWebMvc and removing custom message converters.
LIM-1371Limits are now correctly evaluated via the Inventory screen or REST services when cube filters are disabled.
LIM-1375The “Available amount” and “Utilization perc.” measures are now available for limits created both on startup and at runtime.
LIM-1416The Re-Evaluate icon for incidents in the Status screen is now disabled for users with no permission to evaluate limits.
LIM-1429Fixed an issue where restarting Atoti Limits in persistent mode did not restore the object and workflow states.
LIM-1430Corrected Limits roles documentation for roles that were previously prefixed by GROUP\_, but are now prefixed by ROLE\_.
LIM-1439Fix limits viewer column configurator allowing reordering columns.
### Fixed issues introduced in 4.0.0-beta
Issue KeyDetails
LIM-1392Fixed the utilization percentage measure created in the business cube.
LIM-1428Fixed an issue where role permissions were only partially enforced when creating limits.
LIM-1431Fixed an issue where a user with restricted data access could create a new structure with the same name as an existing structure.
## Migrate to 4.0.0 Upgrading from version 4.0.0-beta, see [Atoti Limits 4.0.0 Release Notes](../../release-notes#400). Atoti Limits uses Atoti Server 6.1.1 and Atoti UI 5.2.x. For new features and fixes included in these releases, please see the [Atoti UI documentation](https://docs.activeviam.com/products/atoti/ui/5.2/) and [Atoti UI Migration Notes](https://docs.activeviam.com/products/atoti/ui/5.2/docs/changelog), and the [release notes for Atoti Server](https://docs.activeviam.com/products/atoti/server/6.1.1/docs/release/changelog/index.). ### Breaking Changes No breaking changes. ### Summary * **Limit statuses** : faster loading times when displaying a limit structure with a large number of limits by enabling a property to fetch the statuses in a separate process. * **Enhanced scope levels** : Users can now drill down by a limit scope’s [level name](../../../user-ref/cube/scope-level-name) and [level member](../../../user-ref/cube/scope-level-member) in a pivot table. ### Input file formats No changes. ### Configuration #### Configuration Properties ##### [limits-activeviam module](../../../user-ref/properties/config-properties/limits-activeviam) ###### Properties added
Property NameCommentValue
limits.data-access-control.servers..default-scope-match-modeSets the match mode to use for scope permissions when it is omitted.MATCH\_ALL
limits.autoconfiguration.content-server.limits-created-measures-ownersThe roles that will be the owner/reader for the calculated members that were created based on the KPIs. The value should be auto-configured from the KPI owners in the content server.
limits.workflow\.workflow-status-fetched-with-limitWhen set to true, retrieving limit structures also updates the limit status with the current workflow status.true
#### Configuration files No changes. ### Datastores #### Modified stores
ModificationStoreFieldTypeDescription
AddedLimitsAliveBooleanThis field indicates whether the limit is still alive (not deleted or expired). For more details, see Alive field in Limits store.
### Cube schema #### Added
Issue KeyDetails
LIM-1200An “Available Amount” and “Utilization %” measure for each KPI has been added to the limits-auto-config, calculating the difference and quotient between a KPI’s goal and the KPI’s value, respectively.
LIM-1205Added a property to configure whether or not filters are applied on evaluation.
LIM-1275Added debug logs when evaluating Atoti Limits KPIs detailing eligible limits, exposures, and evaluation location.
LIM-1302Added support for restricting access on scopes in the role permissions.
LIM-1324Pagination has been added to the Limits viewer.
LIM-1328Added new matchMode values for scopes to support more flexible retrievals in the IScopeRetrievalService. For details, see Match mode.
LIM-1339Added permission roles to control user access to UI actions.
LIM-1345Improved performance in the Limits viewer screen by using the ScopeCacheService to help retrieve scope objects.
### Changed
Issue KeyDetails
LIM-1096KpiCrudService and KpiCrudRestService have been updated, separating the two classes into a Spring Service and a REST Controller wrapper.
LIM-1298Improved property handling in Atoti Limits auto-configuration.
LIM-1314Improvements have been made to the validation framework. See the custom validator page for more information.
LIM-1323Improved performance of filters in Limits tables.
LIM-1344The ILimitsRetrievalService methods have been updated and the implementation modified to avoid executing methods recursively and to reduce the number of transactions in methods. For more details, see Changes to IlimitsRetrievalService.
LIM-1372Updated common library to version 2.1.0-alpha-AS6.1.
### Removed
Issue KeyDetails
LIM-285Between and Not Between KpiTypes have been disabled. For more information, see Removing Between and Not Between KPI types.
LIM-1274private\_ and internal imports have been removed from Atoti Limits.
LIM-1312Removed support for Atoti Server version 5.11 as it is no longer supported by ActiveViam.
### Fixed
Issue KeyDetails
LIM-1325Fixed the scope selector overflowing the popover for large lists of scope members.
LIM-1349Removed the incorrect usage of the thread pool when creating/dropping KPIs in the KpiCrudService.
LIM-1358Updated calculated member creation to set ROLE\_USER as the default owner and reader so all users can see the measures.
LIM-1366Fixed issue with evaluation errors not being cleared when retrying the evaluation.
## Migrate to 4.0.0-beta Upgrading from version 4.0.0-alpha, see [Atoti Limits 4.0.0-beta Release Notes](../../release-notes#400-beta). Atoti Limits uses Atoti Server 6.1.0 and Atoti UI 5.2.x. For new features and fixes included in these releases, please see the [Atoti UI documentation](https://docs.activeviam.com/products/atoti/ui/5.2/) and [Atoti UI Migration Notes](https://docs.activeviam.com/products/atoti/ui/5.2/docs/changelog), and the [release notes for Atoti Server](https://docs.activeviam.com/products/atoti/server/6.1.0/docs/release/changelog/index.). ### Breaking changes #### Auto-Configuration changes * `LimitsCoreConfig` has been renamed to `LimitsCoreAutoConfiguration`, is now an `@Autoconfiguration` class and is no longer explicitly imported in `LimitsAppConfig`. ### Input file formats No changes. ### Configuration #### Configuration properties ##### Properties modified ###### [limits-integration-common module](../../../user-ref/properties/config-properties/limits-integration-common)
Property NameCommentNew ValueOld Value
limits.autoconfiguraton.limits-base-urlContains the base, for example, [http://localhost:3090](http://localhost:3090) instead of the full rest URL, such as [http://localhost:3090/limits/rest/v2](http://localhost:3090/limits/rest/v2)limits.autoconfiguraton.limits-base-urllimits.autoconfiguraton.limits-rest-url
#### Files Modified #### Property files ##### [limits-activeviam module](../../../user-ref/properties/config-properties/limits-activeviam) New properties:
Property NameCommentValue
limits.cube.kpi-filters-enabledTrue if cube filters are enabled for Limits KPIs, false otherwise.true
### Datastores No changes. ### Cube schema No changes. ### Measures No changes. ### Other changes #### `ROLE_LIMITS` is no longer a required role The `ROLE_LIMITS` role is no longer required for all users of Atoti Limits. This role has been repurposed as the [full-access role](../../../dev/roles/limits-roles#role_limits-full-access) in the permission roles to maintain backward compatibility. Users with this role will continue having full access to all actions in the UI as they previously did. `ROLE_LIMITS` is still used to tag KPIs created by the module, but user access to the KPIs is controlled by the `ROLE_USER` role, which is still [required](../../../dev/roles/limits-roles#role_user). # 4.1 Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/4.1 * [Release notes](./4.1/release-notes-4.1) * [Changelog](./4.1/changelog-4.1) * [Migration guide](./4.1/migrate-4.1) # Changelog Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/4.1/changelog-4.1 For a brief overview of the changes, see our [Release notes](./release-notes-4.1). For information on upgrading from previous versions, see the [Atoti Limits Migration Notes](./migrate-4.1). ### Added
Issue KeyDetails
LIM-1828Added new services to start Activiti workflows in bulk.
### Changed
Issue KeyDetails
LIM-1828The default implementation of ILimitsProcessInstanceWorkflowCacheService is now a no-operation implementation as this class is unused.
LIM-1837Updated the warning wording when creating a limit structure to “Warn when utilization reaches x% of a limit”.
### Deprecated
Issue KeyDetails
LIM-1828ILimitsProcessInstanceWorkflowCacheService is unused and has been deprecated for removal. It’s still present to avoid breaking the API.
LIM-1828IEvaluationTaskManager has been deprecated for removal because most of its methods are unused.
### Fixed
Issue KeyDetails
LIM-1827Fixed the logic and wording for warning thresholds. The warning threshold is now directly correlated to the limit utilization percentage.
LIM-1850Fixed an issue where JWT tokens weren’t being refreshed causing requests between servers to fail after token expiration (default is 12 hours).
### Added
Issue KeyDetails
LIM-1335Data permissions in Atoti Limits are now applied to the KPIs and calculated members created by the module in the business cube.
LIM-1378Added a cache service to store structures/limits that exist on the business server to speed up evaluations.
LIM-1403Atoti Limits now sends notifications to the UI when the initial data load completes, limit evaluations complete, and to users with the approval role when a FourEyes limit is created.
LIM-1444The newly developed Audit Service has been added and updated the version of workflow-core.
LIM-1488Moved the IAuthenticatedLimitsUserService to limits-common and created a new implementation in limits-activeviam to assist with tasks requiring unrestricted access to Atoti Limits data.
LIM-1489Updated dependencies for the Common Spring Services (audit-service and notification-service) to import the services from common-spring-services-bom.
LIM-1494Added an FAQ page in the Roles and Permissions documentation.
LIM-1511Updating Limit KPIs will now trigger a refresh of the application server’s data model in the UI.
LIM-1514Atoti Limits has been upgraded to Atoti Server 6.1.3. The 6.0.X and 6.0.X-sb3 modules have been upgraded to use Atoti Server 6.0.18 and 6.0.18-sb3 respectively.
LIM-1517sourceLimitId is now validated when temporary limits are created. This field should reference the limitId of the parent limit.
LIM-1531Added a property limits.cube.scope-hierarchies-enabled that can be used to disable scope hierarchies to improve loading performance for large cardinalities of limit scopes.
LIM-1538Added the Audit screen to the Atoti Limits UI.
LIM-1565A new service, JfrService, has been added to enable recording Java Flight Recordings (JFRs) on the fly.
LIM-1573Added properties for controlling which user roles will receive the server started and evaluation completed notifications.
LIM-1596Files can now be saved as attachments at each step of the default workflows.
LIM-1600Incident differences are now visible in the audit history.
LIM-1601Limit incidents can be reviewed directly from an incident’s linked dashboard.
LIM-1604Files saved as attachments in the workflow are now restricted to certain file types which are defined by the ‘limits.workflow\.allowed-file-upload-extensions’ property
LIM-1756Updated the version of common-spring-services-bom to 1.0.1 and workflow-core to 2.5.0.
### Changed
Issue KeyDetails
LIM-1241Errors that occur during the validation of limits and incidents are now reported in a more consistent format.
LIM-1434Temporary limits are now grouped under their source limit.
LIM-1456Atoti Limits now uses the IConfigurationService instead of REST requests to execute MDX statements when creating Atoti Limits calculated measures to improve performance.
LIM-1469Server-side limit structure errors are shown alongside the offending field in the UI.
LIM-1490The Inter Server event service that sends events from Atoti Limits to the connected server has been extracted into it’s own module.
LIM-1501Migrated workflow-related constants to dedicated class, WorkflowConstants.
LIM-1525Improved performance of limit evaluations by skipping unnecessary retrieval of limit workflow information.
LIM-1552Only required folders are now fetched from the connected server when resolving calculated measures.
LIM-1560Use one global CalculatedMeasuresResolver to speed up queries on limits on calculated measures.
LIM-1592The APIs for validation errors and error handlers have been updated to improve error handling. See the 4.1 migration notes for the list of changes to migrate your custom errors and/or error handlers.
LIM-1603Improved the default validation error messages provided by Atoti Limits to have a more consistent format and better readability.
LIM-1635The logic to filter objects based on user data permissions has been changed to use the Spring @PostFilter and @PostAuthorize annotations in ILimitsRetrievalService.
LIM-1659The ILimitsRestClientProvider, ILimitsRestTemplateProvider and ILimitsRestClientBuilderProvider have all been updated to return builders and now they have been renamed to ILimitsRestClientBuilder, ILimitsRestTemplateBuilder and ILimitsRestClientBuilder respectively.
### Removed
Issue KeyDetails
LIM-1070Removed evaluationDate field from Incident that was redundant to the evaluationTimestamp field.
LIM-1407limits-activeviam no longer has a dependency on limits-integration-common. Classes previously imported from limits-integration-common are now imported from limits-common.
LIM-1493Removed default value for property limits.autoconfiguration.content-service.limits-created-measures-owners. This property should be auto-configured, and if it is not then it should be explicitly set in the application configuration.
LIM-1591Removed the deprecated RemoteCubeRestService as calculated measures are now fetched directly from the application server.
LIM-1581The limits-activeviam source code has been removed from the released artifacts in an effort to ease client migrations. The javadoc sources are still available for download.
LIM-1629Removed deprecated code for Basic authentication in favor of using JWT authentication as the default for machine-to-machine communication.
LIM-1634Removed the LimitsPermissionOverrideUtil class and replaced its usage with queries that set LimitsQueryPayload::checkuserPermissions to false.
LIM-1636Removed the runWithAuthorization and decodeBase64EncodedAuthentication methods from IAuthenticatedLimitsUserService that are no longer used since the removal of the Basic authentication logic.
### Fixed
Issue KeyDetails
LIM-1468Fixed an issue where trying to create a limit structure with the same key fields as an existing limit structure would be treated as an update.
LIM-1483Fixed an issue where KPIs were not refreshed after restarting Atoti Limits in persistent mode.
LIM-1486Attempting to edit a temporary limit on the Limits Viewer screen no longer produces duplicate temporary limits.
LIM-1492Fixed an issue where Atoti Limits calculated measures were being created on connected server KPIs that did not belong to Atoti Limits.
LIM-1498Fixed an issue where the connected application would not start if Atoti Limits Auto-configuration was disabled via limits.autoconfiguration.enabled=false.
LIM-1509Fixed an issue where the differences in historical versions of incidents were not being returned in the status screen
LIM-1512Fixed an issue where KPIs were not being created unless restricted users were defined.
LIM-1522Fixed an issue where generated IDs for limits created via the UI could collide with IDs for limits created via file upload if the uploaded limits respected the ordering of the generated IDs.
LIM-1533Fixed tooltip message inside of the Limits Viewer screen, which suggested that the user is not authorized to delete limits.
LIM-1536Fixed an issue where having multiple valid temporary limits on the same official limit could cause errors when evaluating.
LIM-1542Fixed an issue where workflow actions were not set on retrieved limits if property limits.workflow\.workflow-rules.can-approver-be-same-as-creator was set to false.
LIM-1550Fixed an issue where users with the ROLE\_CREATE\_ANY\_LIMIT permission role were blocked when attempting to create a limit via the UI or REST.
LIM-1551Fixed an issue where filtering on a limit with scope (Total) or (For each) would display no data.
LIM-1578Non-limit features now remain accessible even if the Atoti Limits server is unavailable.
LIM-1605Fixed an issue where updating a limit structure with no differences from the existing limit structure would result in an exception.
LIM-1612Fixed an issue where some actions were not disabled when a limit was deleted or expired.
### Known issues
Issue KeyDetails
BAS-1330Deleting the last limit value deletes the limit structure. As a workaround, don’t delete all limits on a limit structure unless you are sure that the structure won’t be used again. Alternatively, if you do need to reuse the structure, you can create a limit on it using the endpoint /modules/limits-module/limits/rest/v2/limitDefinition/limits/save. The key of the limit structure will still be visible in the admin-ui.
LIM-846Complex Scopes: Currently, a limit with an aggregated scope and a limit with a non-aggregated scope cannot be created on the same limit structure. As a workaround, create the limits on two separate structures.
LIM-840Complex Scopes: Currently, limits can’t be defined with an aggregated scope location and another scope location. As a workaround, create two separate limits on two separate structures.
LIM-813Managers can incorrectly upload Limit Structures through the REST endpoint.
LIM-594Having email notifications enabled for breaches causes decreased limit evaluation performance. See Configuring the breach email on how to disable breach emails.
LIM-357The Six Eyes workflow is currently not implemented.
LIM-346Limits on calculated measures only work through File Upload, not through the UI.
LIM-320Calculated measures need to be included in Pivot Table Query in order to view a Limit’s KPI in the Pivot Table. See Measures for more on how to create a query for Limits on calculated measures.
# Migration guide Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/4.1/migrate-4.1 This guide explains the changes required to migrate to the stated version of the Atoti Limits. ## Migrate to 4.1.1 Upgrading from version *4.1.0*, see the [Atoti Limits 4.1.1 Release Notes](./release-notes-4.1). Atoti Limits is using Atoti Server 6.1.3 and Atoti UI \~5.2.6. For new features and fixes included in these releases, please see the [Atoti UI documentation](https://docs.activeviam.com/products/atoti/ui/5.2/) and [Atoti UI Migration Notes](https://docs.activeviam.com/products/atoti/ui/5.2/docs/changelog), and the [release notes for Atoti Server](https://docs.activeviam.com/products/atoti/server/6.1.3/docs/release/changelog/index.). ### Summary * **Limit warnings:** Intrepretation of the [warning threshold](#warning-threshold) limit has been updated. #### Warning threshold In version 4.1.0, the interpretation of the warning threshold was updated. The new behavior, along with the Atoti Limits and Atoti UI documentation, clarifies that the threshold is a direct percentage of the limit’s utilization. If you updated a limit’s warning threshold or defined new warning thresholds using Atoti Limits in version 4.1.0, you may need to update your warning thresholds to ensure they are still aligned with your expectations. ##### Example The following illustrates the updated behavior. Consider a limit with these settings: * **Rule**: GREATER\_THAN * **Warning**: True (80%) * **Absolute Value**: False * **Limit Value**: 1000 The UI wording and warning range have changed as summarized in the following table:
Previous behavior
(4.0.1-4.0.3 and 4.1.0)
New (and original) behavior
(pre 4.1.0 and 4.1.1+)
UI Wording“Warn when within % of limit value”“Warn when utilization reaches % of a limit”
Limit will warn in the range\[200, 1000]\[800, 1000]
## Migrate to 4.1.0 Upgrading from version *4.0.3*, see the [Atoti Limits 4.1.0 Release Notes](./release-notes-4.1). Atoti Limits is using Atoti Server 6.1.3 and Atoti UI \~5.2.6. For new features and fixes included in these releases, please see the [Atoti UI documentation](https://docs.activeviam.com/products/atoti/ui/5.2/) and [Atoti UI Migration Notes](https://docs.activeviam.com/products/atoti/ui/5.2/docs/changelog), and the [release notes for Atoti Server](https://docs.activeviam.com/products/atoti/server/6.1.3/docs/release/changelog/index.). ### Summary * **Authentication**: JWT is now the default authentication for machine-to-machine communication. Basic authentication has been removed. * **Removal**: `limits-activeviam` and `/limits/rest/v2/limitDefinition/limitsDefinitionStoreQuery` have been removed. * **Interface changes**: Several interfaces have been updated or removed (`IAuthenticatedLimitUserService`, `IEvaluationService`, `IValidationError`), custom implementations may need updates. * **“Save” operation changes**: Atoti Limits now strictly enforces create vs. update logic based on the presence and existence of IDs. * **Temporary limits**: `sourceLimitId` is now validated. Temporary limits are grouped under their official source limits in API responses. * **Security filtering**: `@PostFilter` and `@PostAuthorize` are now applied in `ILimitsRetrievalService` to enforce user-based result filtering. * **Auto-configuration**: Now uses `@ConditionalOnMissingBean` to simplify custom bean injection and avoid needing `@Primary`. ### Breaking changes * **Endpoint removal**: Removed the `/limits/rest/v2/limitDefinition/limitsDefinitionStoreQuery` endpoint used when evaluating in favor of using the `ILimitCacheService`. * **Module removal**: The `limits-activeviam` module has been removed from the released source files. * **Authentication changes**: JWT is now the default machine-to-machine (MtM) authentication. This will require property changes in your Atoti Server and Atoti Limits. * **`IAuthenticatedLimitUserService` changes**: With the removal of Basic authentication, some methods in `IAuthenticatedLimitUserService` are no longer required and have been removed. * **Evaluation service change**: There is a new method in `IEvaluationService`, which you will need to implement if you have a custom implementation of this interface. * **Validation error changes**: The `IValidationError` interface has been modified. If you have any custom validation errors you will need to update them accordingly. ### Module removal The `limits-activeviam` module has been removed from the released source files. This is to enforce best practices that will ultimately improve the developer experience. Providing a clean separation between source code and custom code makes migrations easier. The source code and javadoc of `limits-activeviam` is still available for download from the [ActiveViam internal Maven repository](https://activeviam.jfrog.io/activeviam/mvn-internal/). We have only excluded it from the [reference starter project](../../../dev/getting-started#installing-the-starter-project) that we distribute with our releases. We don’t recommend that you modify the source code of `limits-activeviam`. Instead, use Spring injection to add to or modify the default behavior of the core code. You can find examples of this in the [Extending the module](../../../dev/dev-extensions) section of our documentation. If you have modified the source code of `limits-activeviam`, you need to extract your changes into the `limits-starter` module and use Spring to inject the changes. If you can’t use Spring injection, please raise a Jira ticket in order for us to provide the appropriate hooks. In the meantime, you can override the `limits-activeviam` code in `limits-starter` by adding your code with the same class and package name as in `limits-activeviam`. #### JWT is now the default machine-to-machine (MtM) authentication Atoti Limits now uses JWT authentication for machine-to-machine communication. This is the default authentication method for Atoti Limits and your Atoti Server. Therefore, you need to set the `limits.autoconfiguration.service-principal` property on both the Atoti Limits and your Atoti Server to communicate between servers. This `service-principal` user should have sufficient rights to perform all limit related operations. You should remove the following unused properties in your Atoti Server: * `limits.autoconfiguration.authentication` * `limits.autoconfiguration.content-server.authentication` * `limits.autoconfiguration.limits-authentication` ##### `IAuthenticatedLimitUserService` changes The following methods were required to support Basic authentication which has been removed in favor of JWT authentication. They have been removed from `IAuthenticatedLimitUserService`: * `runWithAuthentication` * `decodeBase64EncodedAuthentication` If you have a custom implementation of `IAuthenticatedLimitUserService` that overrides the default interface implementation of these methods, you can safely remove them from your code. ##### Functional Interface changes The beans used for [MtM authentication](../../../dev/dev-extensions/custom-mtm-authentication) have been updated to return only builders and have been renamed. These changes provide more consistency and better flexibility. If you have customized the MtM authentication, you will need to update your code accordingly. The following interfaces have been updated:
Old Interface NameNew Interface NameApplicable ServerOld method signatureNew method signature
ILimitsRestTemplateProviderILimitsRestTemplateBuilderConnected servers on Atoti Server version 6.0.xRestTemplate getLimitsRestTemplate()RestTemplateBuilder getRestTemplateBuilder()
ILimitsRestClientProviderILimitsRestClientBuilderConnected servers on Atoti Server version 6.0.x-sb3 or 6.1.xRestClient getLimitsRestClient()RestClient.Builder getRestClientBuilder()
ILimitsRestClientBuilderProviderILimitsRestClientBuilderAtoti LimitsRestClient.Builder getLimitsRestClientBuilder()RestClient.Builder getRestClientBuilder()
#### Additional Method in `IEvaluationService` An overloaded version of the `evaluateLimits` method has been added to the `IEvaluationService` interface that allows you to control whether a notification is sent when the evaluation is complete: ```java theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} Collection evaluateLimits(Collection limitEvaluationTasks, boolean sendNotification); ``` If you have a custom implementation of `IEvaluationService`, you will need to add this method to your implementation. #### Validation error changes The structure of validation errors has been streamlined to improve readability and usability. These changes impact the error objects themselves, as well as the error handlers. If you have custom validation errors or error handlers in your project, you’ll need to migrate them accordingly. ##### `IValidationError` changes * new method added: `String getFieldName()` - returns the name of the field containing the error. * method `getLineNumber()` was renamed to `getIndex()`. * method `getColumnIndex()` was removed (replaced by `getFieldName()`). * method `getSource()` was removed. ##### `IValidationErrorHandler` changes * The `handleValidationFailure` and `handleValidationError` methods no longer take a `source` argument, since the source isn’t stored on the validation error. ### Input file formats No changes. ### Configuration #### Configuration properties ##### Properties added ###### [limits-activeviam module](../../../user-ref/properties/config-properties/limits-activeviam)
Property NameComment
limits.autoconfiguration.use-jwt-machine-to-machine-authJWT authentication is now the default machine-to-machine authentication. Basic authentication was removed.
limits.autoconfiguration.limits-authenticationThis property was used for basic machine-to-machine authentication to connect with Atoti Limits.
limits.autoconfiguration.authenticationThis property was used for basic machine-to-machine authentication to connect with the connected Atoti Server.
limits.autoconfiguration.content-server.authenticationThis property was used for basic machine-to-machine authentication to connect with the connected Atoti Server’s Content server.
#### Configuration files ##### Files Modified ###### [application.yml](../../../user-ref/properties/property-files/application-yml) New properties:
Property NameCommentValue
activeviam.apps.inter-server-event-service.issuer.target-servers\[0].nameThe name of the server to send events to (ConnectedAcc).ConnectedAcc
activeviam.apps.inter-server-event-service.issuer.target-servers\[0].urlThe URL of the server to send events to (ConnectedAcc).[http://localhost:7070](http://localhost:7070)
activeviam.apps.inter-server-event-service.issuer.target-servers\[1].nameThe name of the server to send events to (FRTB).FRTB
activeviam.apps.inter-server-event-service.issuer.target-servers\[1].urlThe URL of the server to send events to (FRTB).[http://localhost:8080/frtb-starter](http://localhost:8080/frtb-starter)
spring.application.nameSpring property for the application name. Used by the notification service to identify the source server for each notification.Atoti Limits
limits.autoconfiguration.service-principalThe name of the user authenticated to perform machine-to-machine requests from Atoti Limits to the connected Atoti Servers.admin
### Datastores No changes. ### Databases No changes. ### Cube schema No changes. ### Measures No changes. ### Context values No changes. ### Other changes #### `@PostFilter` and `@PostAuthorize` in `ILimitsRetrievalService` The methods of `ILimitsRetrievalService` have been updated to use the Spring `@PostFilter` and `@PostAuthorize` annotations to filter the results based on the user’s roles. This change is applied at the interface level for all methods, so all implementations of this interface will be affected. For custom internal calls that should not filter the results, you can use the methods that accept a `LimitsQueryPayload` argument and set `checkUserPermissions` to `false`. Please keep in mind that any user-facing invocations of these methods should always have `checkUserPermissions` set to `true` to ensure users only see the limits they are authorized to access. The `@PostFilter` annotation applies to methods that return java `Collection`s. The `@PostAuthorize` annotation applies to methods that return a single object. #### Behavior change for “save” methods/endpoints The default behavior of the “save” methods and endpoints in Atoti Limits has changed. Previously, “save” operations attempted to update the existing object if the incoming object had the same ID as an existing object. Otherwise it was treated as creation. If the incoming object did not have an ID or had an ID that did not match an existing object, a new object was created. Now, the “save” methods and endpoints follow these rules: * “save” a single object: * If the incoming object does not have an ID, it will be treated as a create operation that will fail if an object with that ID already exists. * If the incoming object has an ID, it will be treated as an update operation that will fail if no object with that ID exists. * “save” a collection of objects: * If any of the incoming objects are missing an ID, all objects are treated as create operations that will fail if any contain an ID that already exists. * If all incoming objects have an ID, all are treated as update operations that will fail if any of the IDs do not exist. The following methods and endpoints are affected by this change: * `DefaultLimitsAppCrudService.java`: * `saveLimitStructure` * `saveLimitStructures` * `saveLimit` * `saveLimits` * `saveIncident` * `saveIncidents` * `LimitsDefinitionCrudRestService.java`: * `/structure/save` * `/structures/save` * `/limit/save` * `/limits/save` These changes do not impact the “create” or “update” specific methods or endpoints. If you previously used the “save” methods or endpoints to create objects with pre-defined IDs, you will need to update your code to use the “create” methods or endpoints instead. #### `ROLE_USER` no longer required in Atoti Limits `ROLE_USER` is no longer a required role for all users in Atoti Limits. Previously, this role was required because it was hardcoded as the `owner`/`reader` of KPIs created by Atoti Limits. Now, the role set as the `owner`/`reader` of KPIs created by Atoti Limits is auto-configured, or can be overridden using the `limits.autoconfiguration.content-server.limits-created-measures-owners` property. Users will need to have this auto-configured (or overridden) role, or a [data access role](../../../dev/roles/data-access-permissions), to view KPIs created by Atoti Limits, including the calculated members related to the KPIS. If users have trouble accessing KPIs and calculated measures after upgrading to this version, you may need to manually delete them from the content server so Atoti Limits can recreate them with the correct owner/reader role(s). #### Temporary limits changes The following changes have been made involving temporary limits: ##### 1. `sourceLimitId` field is now validated for temporary limits The `sourceLimitId` field links a temporary limit to its source limit. This field is now validated to ensure that the source limit exists and is an official limit. Please ensure that the `sourceLimitId` field is correctly set when creating temporary limits. Prior to this change, creating temporary limits with another temporary limit as the source limit was blocked via the UI, but wasn’t validated by the server so it was possible to create such limits via the REST API. This was an unintended behavior which we don’t expect clients to do, and is now blocked. ##### 2. Temporary limits are now grouped under official limits Limits retrieved via REST now have temporary limits grouped under the official limit indicated in the temporary limit’s `sourceLimitId` field. If you are using the Atoti Limits REST API to retrieve limits, please note that you may need to update your code to account for this change. Temporary limits are stored in the `temporaryLimits` field of the corresponding official limit. #### Auto-configuration changes We have updated some of our `@Autoconfiguration` classes to not explicitly `@Import` Spring beans and to instead use the `@ConditionalOnMissingBean` annotation to check for the presence of the beans. This makes it easier for users to inject beans into Atoti Limits and prevents the need to mark a bean as `@Primary` when multiple beans are present. The following `@AutoConfiguration` classes have had explicit imports removed: * `LimitsCoreAutoconfiguration` * `LimitsEvaluationServicesAutoConfiguration` The following beans are now `@ConditionalOnMissingBean`: * `DefaultUtilizationMeasureCalculator` which implements `IUtilizationCalculator` * `LimitsCopperMeasureBuilder` which implements `ILimitsCopperMeasureBuilder` * `DefaultEvaluationService` which implements `IEvaluationService` If you have any custom implementations of these interfaces then you can remove the `@Primary` annotation. # Release notes Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/4.1/release-notes-4.1 For the list of issues covered in this release, and known issues, see the [Changelog](./changelog-4.1). For information on upgrading from previous versions, see the [Atoti Limits Migration Guide](./migrate-4.1) Follow [this link](https://activeviam.jfrog.io/artifactory/activeviam-accelerators-artifacts/limits/4.1.1/) to download the zipped distribution files for: * **UI source code** * **UI build** * **Source files** to build the module * **Sample bookmarks** * **Maven repository** required to build the project and run the tests. The Atoti Server 6.1.3 Maven repository files can be downloaded from [here](https://artifacts.activeviam.com/share/ActivePivot_stable/6.1.3). ### Dependencies
ComponentVersion
Atoti Server6.1.3
Atoti UI\~5.2.6
Common Dependencies BOM2.2.1 (com.activeviam.apps)
Common Library2.1.2-AS6.1
Common Parent POM2.2.1 (com.activeviam.apps)
Common Spring Services BOM1.0.1
Data Connectors4.2.0-AS6.1
JavaJDK21
UI Components5.2.8
Workflow Core2.5.0
ComponentVersion
Atoti Server6.1.3
Atoti UI\~5.2.6
Common Dependencies BOM2.2.1 (com.activeviam.apps)
Common Library2.1.2-AS6.1
Common Parent POM2.2.1 (com.activeviam.apps)
Common Spring Services BOM1.0.1
Data Connectors4.2.0-AS6.1
JavaJDK21
UI Components5.2.8
Workflow Core2.5.0
### Summary **New features** * [Limit notifications](#limit-notifications) * [Workflow file attachments](#workflow-file-attachments) * [Audit service](#audit-service) * [Notification service](#notification-service) * [Expired limits](#expired-limits) * [Historical difference in audit](#historical-difference-in-audit) * [Streamlined breach review](#streamlined-breach-review) **Improvements** * [Nested temporary limits](#nested-temporary-limits) * [Atoti Server upgrade](#-coreproductname--upgrade) * [Project Customizations](#project-customizations) * [Error handling](#error-handling) * [Performance](#performance) ### New features #### Limit notifications Atoti Limits now supports sending notifications to the UI based on server events. See [Sending Custom Notifications](../../../dev/dev-extensions/custom-limits-notifications) for more information. #### Audit service The audit service has been added to Limits, including new dedicated screens to display audit. For more information, see [Audit History screen](../../../user-ref/audit-screen). #### Notification service The notification service has been added to Limits, including a new notification centre in the UI to manage your notifications. For more information, see [Notifications in the UI](../../../user-ref/ui-notifications). #### Workflow file attachments You can now save files as attachments at each step of the default workflows. This way you can upload files such as emails, screenshots, or other relevant documents directly to the workflow as evidence. For details on adding this to your workflow see `Defining Task Spring Beans`. #### Expired limits Expired limits are now visible in the limits viewer. For more information, see [View, edit, copy and delete limits](../../../user-ref/using-limits/view-edit-limit). #### Historical difference in audit The audit log for each incident now includes a record of historical differences, letting you easily track what has changed between the current and previous evaluations and understand the impact on the incident. #### Streamlined breach review You can now review limit incidents from an incident’s linked dashboard. For more information, see [Review incidents](../../../user-ref/manage-incidents/review-incidents). ### Improvements #### Nested temporary limits Temporary limits are now displayed as sub-rows of their source limits in the Limits Viewer screen. #### Atoti Server upgrade Atoti Limits has been upgraded to Atoti Server 6.1.3. #### Project Customizations We have added a new [Customizing the Starter](../../../dev/getting-started#customizing-the-starter) section to the documentation. This section provides instructions on how we recommend configuring and customizing the starter project to suit your needs. #### Error handling The APIs for validation errors and error handlers have been updated to improve error handling in the UI. See the [4.1 migration notes](./migrate-4.1#validation-error-changes) for the list of changes to migrate your custom errors and/or error handlers. #### Performance Additional enhancements have been made to improve the performance of limit evaluation and creation.
# 4.2 Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/4.2 * [Release notes](./4.2/release-notes-4.2) * [Changelog](./4.2/changelog-4.2) * [Migration guide](./4.2/migrate-4.2) # Changelog Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/4.2/changelog-4.2 For a brief overview of the changes, see our [Release notes](./release-notes-4.2). For information on upgrading from previous versions, see the [Atoti Limits Migration Notes](./migrate-4.2). ### Added * LIM-1877: Users with the `ROLE_AUTO_APPROVE_LIMIT` permission can now upload Six-Eyes limits and have them auto-approved. * LIM-2113: Users with the `ROLE_AUTO_APPROVE_LIMIT` role can now bypass the approval workflow when uploading limits via a new "Bypass Approval" checkbox in the limit upload dialog. * LIM-2157: Limit scope accepts free text values using the search input. ### Deprecated * LIM-2164: The `POST /limits/rest/v2/limitEvaluation/unschedule` endpoint has been deprecated. Please use the `DELETE /limits/rest/v2/evaluation/scheduling` endpoint instead. ### Fixed * LIM-2158: Scope dropdown not showing members with no contributions. * LIM-2162: Stale entries in the identity generator cache were not being cleaned up. * LIM-2163: Persisted workflow information was not being correctly re-loaded when restarting Atoti Limits. * LIM-2164: The scheduled limit structure evaluation. * LIM-2165: Error thrown in limits inventory when the limits server is configured without legacy workflows. * LIM-2168: Limits datastore containing objects that failed validation on save in persistent mode. * LIM-2169: Scope keys for limits on slicing multi-level hierarchies are now correctly resolved against their limit structure. * LIM-2170: Restarting the limits server did not update the limits cache on the connected server. ### Added * LIM-2060: A new direct limit approval process has been added as a default workflow, which does not require any approvals for limits to be created, updated or deleted. This workflow uses the more performant `workflow-service` and should be preferred to the `StraightThrough` workflow. See [this section](../../../dev/limit-workflow/default-workflows/direct-approval-process) for more details. * LIM-2073: Added a new configuration property `limits.autoconfiguration.connect-on-application-ready-event` (default: true) which determines if the application server should automatically connect to Atoti Limits on startup upon receiving the Spring `ApplicationReadyEvent`. Set this property to `false` to disable automatic connection and enable manual connection control. * LIM-2073: Added a new POST endpoint `/limits/autoconfig/connect` in the application server that will allow users to manually trigger a connection to Atoti Limits when `limits.autoconfiguration.connect-on-application-ready-event` is set to `false`. * LIM-2074: Improved performance in `LookUpPostProcessor` and `LimitsKpiEvaluator` by caching work across locations and failing invalid evaluations faster. ### Changed * LIM-2032: `IAuthenticatedLimitsUserService` now uses a Spring authentication object for improved compatibility. * LIM-2078: Upgraded the Atoti Server dependencies for version-specific modules to versions `6.1.16`, `6.0.27-sb3` and `6.0.27`. * LIM-2106: The `limits.autoconfiguration.server-name` property is now required to be set if the connected server uses the default catalog name (‘Catalog’), otherwise the connection will fail. ### Deprecated * LIM-2073: Deprecated the `limits/autoconfig/connecting` endpoint for removal in favor of the `limits/autoconfig/connected` endpoint, both of which were previously doing the same thing. ### Fixed * LIM-1928: Fixed an issue where real-time updates in the status screen weren’t respecting the filters applied to the screen. * LIM-2041: Fixed an issue where workflow variable changes were being applied before approval in the Six-Eyes Approval Process. * LIM-2084: Fixed an issue where the calculated measures for limits with workflows using the new workflow service were not being created immediately after limits were approved. * LIM-2121: Fixed an issue where temporary limits were not being exported. * LIM-2124: Fixed incorrect parsing of localized numbers on the limits viewer. ### Added * LIM-357: Added a new six-eyes workflow for limits that require two levels of approval before they can be evaluated. * LIM-1809: We have added new services to start Activiti workflows in bulk. * LIM-1812: All workflow variables are now visible on the status screen table. * LIM-1818: Added a new set of properties, `LimitsInitialLoadConfigurationProperties`, to replace `LimitsDlcConfigurationProperties` for the new file loading service. * LIM-1819: Added a new service, `ILimitsFileLoadingService` with default implementation `DefaultLimitsFileLoadingService`, to replace the DLC in the initial load of Limits data. * LIM-1829: Added a new column to the table to display the ‘limit type’ of each incident. * LIM-1836: Added a new set of properties and a new API, `ILimitsStatusMananager`, that allow for statuses in custom workflows to be mapped to limit actions. * LIM-1839: Added a field `limitType` to the `Incident` class. This indicates which type of limit was used in the evaluation: `OFFICIAL` or `TEMPORARY` * LIM-1853: The audit differences drawer now supports array / JSON payloads from the server. * LIM-1854: Filter on limit ID is automatically applied to the table when navigating from the Status screen to the limit structure screen using links. * LIM-1856: Added a rest endpoint in the auto-configuration module to retrieve the limits with a location and a kpi name. * LIM-1862: Added a new endpoint `/activeviam/limits/rest/v2/startup`, which is used to ping the Atoti Limits server. * LIM-1864: Added a new endpoint `/limits/rest/v2/incidents/filter-with-variables` to retrieve the incidents along with their workflow variables, which is used to dynamically generate columns in the status screen. * LIM-1864: Added an optional request parameter `includeVariableDefinitions` to the endpoint `/limits/sse/v2/incidents/subscribe/filter` to send the initial incidents along with their workflow variables, which is used to dynamically generate columns in the status screen. * LIM-1921: Added a new endpoint `/activeviam/limits/rest/v2/workflow-service/workflow-history/{workflow-type}/{object-id}` for retrieving workflow histories in the new format. * LIM-1923: Added a new field `actionName` to the `WorkflowTaskActionExecutionDTO`. * LIM-1924: Updated Atoti Server to version 6.1.13. This includes the upgrade of artifacts required to connect to 6.1.13 versions of Atoti Server. * LIM-1924: Added a new endpoint `/activeviam/limits/rest/v2/dataexport/download` in the auto-configuration modules to handle evaluation responses. * LIM-1943: Added a new Incident workflow, `incident-review-process.bpmn`, that uses the new workflow service. * LIM-1962: Added new columns for limit structure files: `Limit Workflow Variables` and `Incident Workflow Variables` that are used to populate new fields in the limit structure table: `Limit Workflow Details` and `Incident Workflow Details`. * LIM-1962: Added new properties `limits.workflow.limit-business-functions` and `limits.workflow.incident-business-functions` to map the business functions used for limit and incident workflows respectively. * LIM-2019: Added a new column for setting limit workflow initialization variables * LIM-2027: Added new property `limits.workflow.structure-deletion-workflows` to configure the workflows where structure deletion is enabled ### Changed * LIM-1506: Removed server-specific properties from `application.yml`. Properties specific to the `ConnectedAcc` reference test servers released with Atoti Limits can be found in `application-connectedacc.yml` and can be activated with the `connectedacc` Spring profile. * LIM-1750: Realtime mode can now be toggled off during a long initial load. * LIM-1809: The default implementation of `ILimitsProcessInstanceWorkflowCacheService` is now a no-operation implementation as this class is unused. * LIM-1810: The status screen is filtered by default to only show the user’s outstanding tasks. * LIM-1838: Enhanced the filtering of the Server-sent events replacing the `asOfDates` and `incidentTypes` by a `FilterConditionDTOs`. * LIM-1849: Improved performance of executing workflow actions using the default workflows by skipping unnecessary retrieval of limit workflow information. * LIM-1849: Scope hierarchies are now disabled by default to improve performance. They can be enabled by setting `limits.cube.scope-hierarchies-enabled=true`. * LIM-1862: The optional property `limits.autoconfiguration.limits-ping-url` is now auto-configured to point at the newly introduced endpoint `/activeviam/limits/rest/v2/startup` * LIM-1912: The name of the process in `limit-process-straight-through.bpmn` has been renamed from `Straight-through instance process` to `StraightThrough` to match the name in the UI. * LIM-1912: The name of the process in `limit-process-four-eyes.bpmn` has been renamed from `Four-eyes instance process` to `FourEyes` to match the name in the UI. * LIM-1912: The name of the process in `limit-process-exception.bpmn` has been renamed from `Exception Workflow` to `Exception` to match the name in the UI. * LIM-1912: The property to define the file types allowed to be uploaded as attachments in the workflow has changed from `limits.workflow.allowed-file-upload-extensions` to `activeviam.apps.workflow-service.settings.allowed-file-upload-extensions`. * LIM-1912: The property to define the file storage path for uploaded attachments in the workflow has changed from `limits.workflow.file-storage-path` to `activeviam.apps.workflow-service.settings.file-storage-path`. * LIM-1923: The field `taskKey` in `WorkflowTaskActionDTO` has been renamed to `taskName`. * LIM-1924: The default value of the `limits.autoconfiguration.atoti-mdx-download-url` property has been changed from `/dataexport/download` to `/activeviam/limits/rest/v2/dataexport/download`. * LIM-2034: The `limitValue` field on the `Limit` and `Incident` objects has been changed from a `double array` to a `double`. The `double array` was previously unused. ### Deprecated * LIM-1809: `ILimitsProcessInstanceWorkflowCacheService` is unused and has been deprecated for removal. It is still present to avoid breaking the API. * LIM-1809: `IEvaluationTaskManager` has been deprecated for removal because most of its methods are unused. * LIM-1912: `LimitsWorkflowService` has been renamed to `LegacyLimitsWorkflowService` and deprecated for removal in a future release. ### Removed * LIM-1822: Removed the DLC and all related configuration properties and classes. It has been replaced by `ILimitsFileLoadingService`. ### Fixed * LIM-1777: The limits viewer sometimes incorrectly displays a notification that a limit was added on another table page * LIM-1799: Errors while creating a structure sometimes do not show up on the screen. * LIM-1811: Input fields are now properly disabled while submitting workflow actions. * LIM-1827: Fixed the logic and wording for warning thresholds. The warning threshold is now directly correlated to the limit utilization percentage. * LIM-1846: Fixed an issue where JWT tokens were not being refreshed causing requests between servers to fail after token expiration (default is 12 hours). * LIM-1848: Fixed an issue where duplicate incident events may be published by the SSE emitters. * LIM-1851: Fixed an issue where the Atoti Limits KPIs were not updated after a change of KPI description. * LIM-1862: Fixed an issue where the reconnection to the Atoti Limits server wouldn’t happen properly if the Atoti Limits server was behind a loadbalancer. * LIM-1865: Fixed an issue where a limit could not be created if it overlapped with an inactive limit. * LIM-1915: Fixed an issue where structures created without a `Limit Changes` workflow defaulted to using the `StraightThrough` workflow instead of throwing an exception. * LIM-1924: Fixed an issue where evaluation requests were failing due to the streaming responses. * LIM-1936: Fixed an issue where limit statuses were defaulting to `INITIALIZED` if they were not set on creation in `LimitsCrudService`. * LIM-1954: You can now create limits on calculated measures where the underlying is a hierarchy. * LIM-2002: Fixed an issue where creating and updating structures, limits and incidents simultaneously could fail intermittently. # Dependencies Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/4.2/dependencies-4.2 Dependency reference for Atoti Limits, listing compatible versions of Atoti Server, Spring Boot, Atoti UI, and UI Components for each release ### Dependencies This page lists the dependencies required for each version of Atoti Limits. For details on updates or changes to dependencies, refer to the [Changelog](./changelog-4.2). ## 4.2.3 ### Server | Component | Version | | :--------------------------------------------------------------- | :------ | | [Atoti Server](https://docs.activeviam.com/engine/java-sdk/6.1/) | 6.1.20 | | [Spring Boot](https://docs.spring.io/spring-boot/3.5/index.html) | 3.5.13 | | Java | JDK21 | | Notification service | 1.0.3 | | Workflow Core | 2.5.4 | | Workflow service | 1.0.2 | ### UI | Component | Version | | :------------------------------------------------------------------------------------------- | :------------- | | [Atoti UI](https://docs.activeviam.com/products/atoti/ui/5.2/) | >=5.2.6, \<5.3 | | [UI Components](https://docs.activeviam.com/products/tools/ui-components/5.2.8/online-help/) | 5.2.14 | ## 4.2.2 ### Server | Component | Version | | :--------------------------------------------------------------- | :------ | | [Atoti Server](https://docs.activeviam.com/engine/java-sdk/6.1/) | 6.1.19 | | [Spring Boot](https://docs.spring.io/spring-boot/3.5/index.html) | 3.5.13 | | Java | JDK21 | | Notification service | 1.0.2 | | Workflow Core | 2.5.3 | | Workflow service | 1.0.1 | ### UI | Component | Version | | :------------------------------------------------------------------------------------------- | :------------- | | [Atoti UI](https://docs.activeviam.com/products/atoti/ui/5.2/) | >=5.2.6, \<5.3 | | [UI Components](https://docs.activeviam.com/products/tools/ui-components/5.2.8/online-help/) | 5.2.14 | ## 4.2.1 ### Server | Component | Version | | :------------------------------------------------------------------------------------------------- | :---------- | | [Atoti Server](https://docs.activeviam.com/engine/java-sdk/6.1/) | 6.1.16 | | Common Dependencies BOM | 2.4.0 | | Common Library | 2.1.2-AS6.1 | | Common Parent POM | 2.4.0 | | Common Spring Services BOM | 1.0.3 | | Java | JDK21 | | Notification service | 1.0.2 | | [Workflow Core](https://docs.activeviam.com/products/modules/workflow-common-lib/2.5/online-help/) | 2.5.0 | | Workflow service | 1.0.0 | ### UI | Component | Version | | :------------------------------------------------------------------------------------------- | :------------- | | [Atoti UI](https://docs.activeviam.com/products/atoti/ui/5.2/) | >=5.2.6, \<5.3 | | [UI Components](https://docs.activeviam.com/products/tools/ui-components/5.2.8/online-help/) | 5.2.14 | ## 4.2.0 ### Server | Component | Version | | :------------------------------------------------------------------------------------------------- | :---------- | | [Atoti Server](https://docs.activeviam.com/engine/java-sdk/6.1/) | 6.1.13 | | Common Dependencies BOM | 2.4.0 | | Common Library | 2.1.2-AS6.1 | | Common Parent POM | 2.4.0 | | Common Spring Services BOM | 1.0.2 | | Java | JDK21 | | Notification service | 1.0.2 | | [Workflow Core](https://docs.activeviam.com/products/modules/workflow-common-lib/2.5/online-help/) | 2.5.0 | | Workflow service | 1.0.0 | ### UI | Component | Version | | :------------------------------------------------------------------------------------------- | :------------- | | [Atoti UI](https://docs.activeviam.com/products/atoti/ui/5.2/) | >=5.2.6, \<5.3 | | [UI Components](https://docs.activeviam.com/products/tools/ui-components/5.2.8/online-help/) | 5.2.14 | # Migration guide Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/4.2/migrate-4.2 Step-by-step migration guidance for upgrading Atoti Limits, covering property changes, dependency updates, data model changes, and configuration updates required for each version # 4.2.1 to 4.2.2 #### Scheduled evaluation properties The properties used to configure the scheduled INTRADAY limit evaluation have been replaced. The old properties are deprecated and will be removed in a future release, but still function as a fallback if the new properties are not set. You do not have to migrate these properties now, but we recommend doing so to reduce future upgrade efforts. | Old Property (deprecated) | New Property | | :--------------------------------------- | :--------------------------------------------- | | `limits.alert-task.sample-rate-cron` | `limits.evaluation.scheduler.cron-expression` | | `limits.task-scheduler.thread-pool-size` | `limits.evaluation.scheduler.thread-pool-size` | To migrate, replace the old properties in your `application.yml`: ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} # Before (deprecated) limits: alert-task: sample-rate-cron: 0 */5 * * * * task-scheduler: thread-pool-size: 4 # After limits: evaluation: scheduler: cron-expression: 0 */5 * * * * thread-pool-size: 4 ``` If both old and new properties are set, the new property (`limits.evaluation.scheduler.*`) takes precedence. #### Limit repository change The Atoti Limits codebase now lives within the Atoti Server codebase, which streamlines dependency management. This means that the Atoti Limits pom now inherits from ```xml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} com.activeviam.solutions workflows ``` where the version is aligned with the version of Atoti Server used by Atoti Limits, which for this release is `6.1.19`. **Please update your pom parent to this artifact.** The pom file no longer requires the `common-parent-pom`, `common-dependencies-bom` or `common-spring-services-bom`, so you can remove these. # 4.2.0 to 4.2.1 #### Connected server configuration ##### Server name property for connected servers with default catalog name Previously, if-and-only-if the `limits.autoconfiguration.server-name` property was not defined and the connected Atoti Server used the default catalog name (`Catalog`), Atoti Limits would use this default catalog name as the primary way to identify the connected server. This usually led to issues when connecting to Atoti Limits and creating limits. Now, if the connected Atoti Server uses the default catalog name (`Catalog`) then you must define the `limits.autoconfiguration.server-name` property, or else the connection will fail with an exception. To resolve this, set the `limits.autoconfiguration.server-name` property in your connected Atoti Server’s configuration file (e.g. `application.yml`): ```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}} limits: autoconfiguration: server-name: ``` This will be used when creating limit structures to verify that the server for your structure is a valid, connected server. For more information on the available properties, see the [limits integration common properties](../../../user-ref/properties/config-properties/limits-integration-common). # 4.1.1 to 4.2.0 This guide explains how to migrate Atoti Limits from versions 4.1.1 to 4.2.0. This migration guide focuses on breaking changes. Consult the Atoti Limits 4.2.0 [release notes](./release-notes-4.2) and [changelog](./changelog-4.2) for a complete view of changes. ## What is the recommended migration process? 1. Back up your project. 2. Automatically migrate your code and/or data using the [Atoti Limits migration tool](#how-do-i-use-the-atoti-limits-migration-tool). 3. Perform a diff between older Atoti Limits release builds and newer release builds. * Update your dependencies. * Update your code. 4. Confirm successful build and startup. ### How do I use the Atoti Limits migration tool? The migration tool doesn’t account for customizations nor does it account for all required changes. It is used as a helper to automate part of the migration process. The Atoti Limits migration tool is shipped with the Atoti Limits distribution files in the `limits-migrations` folder. It is a script written in Java that automates part of the migration process by updating your code and/or data to be compatible with the latest version of Atoti Limits. #### How does the Atoti Limits migration tool work? In general, the tool is installed and run as follows: 1. `cd limits-migrations` 2. Run `mvn clean install` 3. Run `java -jar path/to/limits-migrator-tool-exec.jar ` Replace `` with the version you are migrating to (e.g. `4.2.0`), and `` with the version specific arguments accepted by the migration tool for the target version. See the following section for more details. #### 4.2.0 migration script This migration script updates the following files from Atoti Limits 4.1.x to 4.2.x: * `limit_structures*.csv`: Adds new columns `Limit Workflow Variables` and `Incident Workflow Variables`. * `limits_approve*.csv`: Renames the `LimitValues` column to `Limit Value`. Adds a new column `Limit Changes Workflow Variables`. * `incident*.csv`: Adds a new column `Limit Type`. The original files are backed up in a separate folder, which you can delete after completing your migration. All new columns will be initialized as empty. This script expects the following program arguments (in this order): 1. The target version of Atoti Limits, which should be `4.2.0` 2. The glob pattern of the structure files to be migrated, for example `*.csv` or `**/*structures*.csv`. 3. The glob pattern of the limit files to be migrated, for example `*.csv` or `**/*limits_approve*.csv`. 4. The glob pattern of the incident files to be migrated, for example `*.csv`, `**/*incidents*.csv` or `**/2025-12-09/incidents/*.csv`. 5. The root folder of the files, for example `./data` or `/path/to/data`. ## What dependencies have changed? The following dependency changes are required for migrating Atoti Limits 4.1.1 to Atoti Limits 4.2.0. #### Updated
DependencyAtoti Limits 4.1.1Atoti Limits 4.2.0
workflow-service-2.0.0
## How do I migrate my project? The following information is applicable for migrating Atoti Limits 4.1.1 to Atoti Limits 4.2.0. ### Low-Code/No-Code If you are using Atoti Limits 4.1.1 in a low code/no-code setup and migrating to Atoti Limits 4.2.0, youâll need to know high-level changes. This section focuses on the high-level changes when migrating, such as configuration/property, data model, cube, and dashboard changes. * [Loading data](#loading-data) * [Moving from the DLC to the new file loading service](#moving-from-the-dlc-to-the-new-file-loading-service) * [Additional fields for the structure csv file/database table](#additional-fields-for-the-structure-csv-filedatabase-table) * [Additional field for the limit csv file](#additional-field-for-the-limit-csv-file) * [Additional field for the incidents csv file/database table](#additional-field-for-the-incidents-csv-filedatabase-table) * [Limit definition changes](#limit-definition-changes) * [Warning threshold behavior](#warning-threshold-behavior) #### Loading data ##### Moving from the DLC to the new file loading service In order to migrate your initial load configuration from the DLC to the new file loading service, you need to update the following properties in your `application.yml` file:
Old (DLC) Property NameNew Property NameComment
limits.dlc.root-dirlimits.initial-load.root-dirThe path to the directory containing the CSV files to load.
limits.dlc.path-matchers.limitslimits.initial-load.file-path-matchers.limitsThe pattern to identify the CSV files containing limits.
limits.dlc.path-matchers.limitstructureslimits.initial-load.file-path-matchers.limit-structuresThe pattern to identify the CSV files containing limit structures.
limits.dlc.path-matchers.incidentslimits.initial-load.file-path-matchers.incidentsThe pattern to identify the CSV files containing incidents.
limits.dlc.path-matchers.asofdatelimits.initial-load.file-path-matchers.as-of-dateThe pattern to identify the CSV files containing AsOfDates.
The following properties do not have an equivalent in the new configuration and can be safely removed:
Service/Configuration Class
com.activeviam.limits.cache.cube.cfg.source.IDataLoadControllerConfig
com.activeviam.limits.cache.cube.cfg.source.ICSVSourceConfig
If you have customized the DLC configuration in Atoti Limits by overriding the default implementations of these configuration classes, you will need to replace your custom DLC beans with a custom implementation of the `ILimitsFileLoadingService` interface. See [How to customize the file loading service](../../../dev/dev-extensions/custom-data-loading#how-to-customize-the-file-loading-service) for more details on how to override the default service. Once you have created your custom `ILimitsFileLoadingService` implementation that mirrors the behavior of your previous DLC configuration, you can safely remove all DLC-related configurations from your project. ##### Date roll via file no longer supported With the removal of the DLC, [rolling the date](../../../dev/date-roll) by sending the updated AsOfDate file to the DLC endpoint is no longer supported. Please use the [Limits asOfDate endpoint](../../../dev/date-roll#trigger-a-date-roll-via-rest) to roll the date instead. ##### Managing Workflows If you have made customizations to the default workflows then you will need to update them to conform to the new workflow service. # Release notes Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/4.2/release-notes-4.2 For the list of issues covered in this release, and known issues, see the [Changelog](./changelog-4.2). For information on upgrading from previous versions, see the [Atoti Limits Migration Notes](./migrate-4.2) Follow [this link](https://activeviam.jfrog.io/artifactory/activeviam-accelerators-artifacts/limits/4.2.2/) to download the zipped distribution files for: * **UI source code** * **UI build** * **Source files** to build the module * **Sample bookmarks** * **Maven repository** required to build the project and run the tests. ### Summary **New features** * [Uploaded Six-Eyes limits can be auto-approved](#uploaded-six-eyes-limits-can-be-auto-approved) **Improvements** * [Limit evaluation scheduling](#limit-evaluation-scheduling) * [Limit repository change](#limit-repository-change) ### New features #### Uploaded Six-Eyes limits can be auto-approved Limits using the Six-Eyes Approval Process workflow may now be automatically approved, foregoing both levels of approval that are typically required, when created via file upload by users that have the `ROLE_AUTO_APPROVE_LIMIT` permission role. ### Improvements #### Limit evaluation scheduling The scheduled evaluations of limit structures have been improved to be more robust and to provide more API and REST options. For more information, see the section on [Evaluating Limits](../../../dev/evaluation-tasks). #### Limit repository change The Atoti Limits codebase now lives within the Atoti Server codebase, which streamlines dependency management. Follow [this link](https://activeviam.jfrog.io/artifactory/activeviam-accelerators-artifacts/limits/4.2.1/) to download the zipped distribution files for: * **UI source code** * **UI build** * **Source files** to build the module * **Sample bookmarks** * **Maven repository** required to build the project and run the tests. The Atoti Server 6.1.16 Maven repository files can be downloaded from [here](https://artifacts.activeviam.com/share/ActivePivot_stable/6.1.16). * **Atoti Limits Python Extension** ### Summary **New features** * [Atoti Limits Python extension](#atoti-limits-python-extension) * [New Direct limit approval process](#new-direct-limit-approval-process) **Improvements** * [Limit evaluation performance improvements](#limit-evaluation-performance-improvements) ### New features #### Atoti Limits Python extension The new Atoti Limits Python extension allows users to connect an Atoti Python session to a running Atoti Limits server. See the [Atoti Python integration section](../../../dev/integration/python) for more details. #### New Direct limit approval process Atoti Limits now has a new Direct limit approval process which uses the more performant `workflow-service`. This workflow does not require any approvals for limits to be created, updated or deleted. This workflow should be preferred to the `StraightThrough` workflow. See [the Direct approval process section](../../../dev/limit-workflow/default-workflows/direct-approval-process) for more details. ### Improvements #### Limit evaluation performance improvements We have improved performance in limit evaluation by caching work across locations and implementing better fast-failure mechanisms for invalid locations. Follow [this link](https://activeviam.jfrog.io/artifactory/activeviam-accelerators-artifacts/limits/4.2.0/) to download the zipped distribution files for: * **UI source code** * **UI build** * **Source files** to build the module * **Sample bookmarks** * **Maven repository** required to build the project and run the tests. The Atoti Server 6.1.13 Maven repository files can be downloaded from [here](https://artifacts.activeviam.com/share/ActivePivot_stable/6.1.13). ### Summary **New features** * [Limit and incident workflows powered by new workflow service](#limit-and-incident-workflows-powered-by-new-workflow-service) * [Limit context provided alongside limit KPIs](#limit-context-provided-alongside-limit-kpis) * [Custom workflow status mapping](#custom-workflow-status-mapping) * [Define limits on calculated measures](#define-limits-on-calculated-measures) **Improvements** * [Enhanced task screen filtering](#enhanced-task-screen-filtering) * [Improved columns in status screen](#improved-columns-in-status-screen) * [Performance improvements](#performance-improvements) ### New features #### Limit and incident workflows powered by new workflow service A new workflow service has been introduced to streamline the configuration and execution of limit and incident workflows. Key benefits include: * **Simplified setup**: User tasks are now configured directly, while service tasks are defined via Spring beans. * **Runtime flexibility**: You can now provide additional context, such as attaching emails, when initiating workflows. * **Performance boost**: Bulk operations are significantly faster, supporting high-volume use cases. This release introduces two default workflows built on the new service: * **Six-Eyes workflow**: A standard approval process for limits requiring two levels of authorization before evaluation. * **Incident review workflow**: A simplified incident handling process designed for faster review and easier customization. Both workflows are provided out of the box and are fully supported by the new workflow service. The previous workflows remain available and continue to operate using the legacy workflow engine, ensuring backward compatibility. #### Limit context provided alongside limit KPIs You can now view the specific limit affecting a KPI’s status directly within the dashboard, allowing for quick identification of warning or breach triggers. With appropriate permissions, you can also request a temporary limit increase from this view. This streamlines the process, letting users proactively manage limits. For instance, before executing a trade, a user can perform a what-if check. If this check indicates a potential breach of the current limit, they can then request a temporary limit increase to prevent it. For more information, see [KPI Drawer](../../../user-ref/viewing-limits/in-the-cube#kpi-drawer). #### Custom workflow status mapping When using custom workflows, status values may differ from those in the [default limit workflows](../../../dev/limit-workflow). To ensure consistent behavior across Atoti Limits, you can now map these custom statuses to standard limit actions. This mapping allows the system to correctly interpret whether a limit is active, evaluable, visible in KPIs, or pending, regardless of the specific status labels used in your workflow. See the [custom workflow statuses section](../../../dev/dev-extensions/custom-workflow-service/custom-workflow-statuses) for more details. #### Define limits on calculated measures You can now define limits on calculated measures where the underlying is a hierarchy. ### Improvements #### Enhanced task screen filtering The Status screen lets you quickly view your outstanding tasks, enabling prompt action. Other incidents and passes can still be viewed using the switch located above the table. Additionally, screens can be pre-filtered by selected IDs allowing notifications to link directly to relevant tasks. #### Improved columns in status screen The Status screen now displays workflow variables as columns. This enhancement enables better analysis of incidents by making custom fields visible within the view. Additionally, the **Limit type**, which indicates whether an incident resulted from a temporary or permanent limit, is now shown by default. #### Performance improvements This release brings several enhancements that significantly improve system responsiveness and scalability: * **Faster KPI evaluations**: Evaluations are now quicker thanks to smarter caching and more efficient compatibility checks between limits and locations. Irrelevant data is automatically excluded to reduce processing time. * **Improved UI responsiveness**: When viewing KPIs, large evaluation requests are now broken into smaller batches to prevent freezing and ensure a smoother user experience. * **Bulk workflow execution**: New services have been introduced to start limit and incident workflows in bulk, reducing delays when processing large volumes of data. This is especially beneficial during post-evaluation when many incidents are created at once. * **Faster reloading on restart**: The system now reloads persisted limits more efficiently during server startup, reducing downtime and improving overall responsiveness. # 6.1 Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/6.1 * [Release notes](./6.1/release-notes-6.1) * [Changelog](./6.1/changelog-6.1) * [Migration guide](./6.1/migrate-6.1) # Changelog Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/6.1/changelog-6.1 From version 6.1.20 onwards, Atoti Limits version numbers are aligned with the Atoti Java SDK. Previously, Atoti Limits used its own versioning (the last release under the old scheme was 4.2.2). The jump in version numbers reflects this alignment. There are no missing releases between 4.2.2 and 6.1.20. For a brief overview of the changes, see our [Release notes](./release-notes-6.1). For information on upgrading from previous versions, see the [Atoti Limits Migration Notes](./migrate-6.1). ### Changed * PIVOT-14106 Improved performance of audit history filtering. ### Fixed * LIM-2182: The Atoti Python extension now supports connecting to a Limits server running on a different host or port. See the Python integration guide for how to configure the URL. * LIM-2188: Fixed the Atoti Python UI extension getting stuck on a loading screen forever when the Limits server was unreachable, blocking login and the cube/home page even though the Atoti session itself was healthy. The extension's LIMITS client is now always provided to the UI, using a fallback service descriptor when the server's versions can't be fetched, so a down or unreachable Limits server no longer prevents the rest of the application from loading. * LIM-2237: Fixed limit structure creation failing validation with `Server Name ... not in the list of current connections` when the connected Atoti server's catalog name differed from the configured `limits.autoconfiguration.server-name`. Remote cube discoveries were tracked by catalog name instead of the connection server name, so the lookup returned no server; they are now keyed by the connection server name. * LIM-2266: Fixed bulk workflow actions (for example selecting several Six-Eyes limits and approving them together) failing with a database deadlock on SQL Server. Completing several workflow tasks at once ran them as concurrent transactions that contended on Activiti's task and bookkeeping rows and deadlocked on `ACT_RU_TASK` (SQL Server error 1205). Task state-transitions (claim, assign, release, complete) now run sequentially, while the high-volume workflow start, deletion and read operations remain parallel to preserve performance. * LIM-2268: `DefaultLimitsAppCrudService` now synchronizes all create, update and delete operations on the same monitor as the existing `save*` methods, so concurrent limit modifications (from triggers or the UI) can no longer interleave and corrupt the JPA/datastore writes. * LIM-2285: Executing a workflow with an unknown task or action now returns a clear `400 Bad Request` instead of an opaque HTTP 500 `NoSuchElementException`. Limits whose scopes are inconsistent within a structure are now caught during validation, with an error naming the conflicting limits and scope keys. * LIM-2305: Fixed incident review actions of the new incident review workflow not enforcing permissions, which let a user without `ROLE_PROCESS_INCIDENT` or `ROLE_LIMITS` process incidents through the `/workflow-service/execute-task-action` endpoint. * LIM-2319: Fixed notifications breaking after running for several hours, where streaming the stored notifications for a new subscriber while another thread published could fail with `IllegalStateException: Accept exceeded fixed size`. The notification store is now backed by a concurrent map. * LIM-2320: Fixed the Limits Inventory "Pending Approval" count always showing `0` for limits awaiting six-eyes approval. The count only recognised the four-eyes `INITIALIZED`/`EDIT` statuses and ignored the six-eyes `PENDING_FIRST_APPROVAL`/`PENDING_SECOND_APPROVAL` (and update/deletion/changes) statuses; they are now all counted. * LIM-2331: Fixed a data-access-permissions leak where a limit structure containing several limits with different scopes exposed all of its limits to a restricted user as soon as one of them was in scope. Structure visibility is unchanged (a structure is shown when the user can see at least one of its limits), but its out-of-scope limits are now removed from the returned structure so a visible structure no longer reveals limits the user is not entitled to. * LIM-2332: Fixed attachment workflow variables being missing from the workflow history. When converting historic variable updates, the returned map was keyed by the raw variable name (with the internal `file://` prefix) instead of the prefix-stripped user-facing name, so callers looking up an attachment by its name could not find it; the map is now keyed consistently with the other variable converters. * LIM-2333: Fixed a data-access `scope` permission granted on a parent level of a multi-level hierarchy not granting visibility to limits scoped at a deeper level underneath it. `contains_any`/`contains_all` scope matching only inspected each scope location's selected (leaf) level name, so a permission on, for example, `Level 2=FICC` did not match a limit scoped at `Level 3` whose stored path contains `Level 2=FICC`; matching now considers every level in the nested path. ### Security * LIM-2313: Fixed a security issue where an uncontrolled server name passed when connecting to a limit server could be used to read arbitrary files from disk. Server names are now restricted to ANSI alphanumeric characters, spaces, `.`, `-`, and `_`. This release does not ship any changes. ### Added * LIM-2227: Added an implementation of the audit screen that uses the new workflow service. ### Fixed * LIM-2233: Fixed deletion of a limit failing on the connected Atoti server when one of its calculated members ("available amount" / "utilization %") had already been removed by a concurrent measure refresh. The drop is now idempotent, so an already-removed member no longer raises a "does not exist" error or leaves the deletion workflow in error. * LIM-2243: Fixed limit creation, update and deletion failing with a 409 `ConflictException` (`You cannot delete this member because other members depend on it`), which could make the whole application unusable, when a user-defined calculated measure depended on a Limits-created measure ("Available Amount" or "Utilization %"). Limits measures are now only created when missing and only dropped once their KPI no longer has any limit; a measure that another calculated member depends on is kept and the failure logged, instead of aborting the operation. * LIM-2252: Fixed `IndexOutOfBoundsException` in the incidents SSE listener when processing datastore transactions, which could cause real-time incident updates to stop being pushed to the UI. * LIM-2253 Limits: Improved the performance of limit operations for large applications with tens of thousands of limits, where operations could previously take 30s to 1min each. * LIM-2256: Fixed a race when several limits are deleted concurrently, where two `KpiCrudService.refreshKPIs()` runs both tried to `DROP` the same orphaned KPI on the connected server, causing the second drop to fail with a 404 (`NotFoundException`) and the deletion to surface as HTTP 500. The refresh is now serialized and a 404 on `DROP KPI` is treated as a successful (idempotent) deletion. * LIM-2259: Fixed new limit creation failing with `LimitsCrudException: No value present` when the new limit's date range overlapped multiple existing active limits sharing the same structure, scope, and limit type. * LIM-2264: Fixed the Limit Structure delete action remaining available in the UI when no live limits exist for that structure. * LIM-2267: Fixed KPI measures not being correctly created for new workflow limits because KPIs were refreshed before the limits were added to the connected server's cache. * LIM-2274: Evaluating a limit whose value is `0` no longer fails to persist the incident. The utilization ratio (`measureValue / limitValue`) produced a non-finite value (`Infinity`/`NaN`) that the relational store rejected; it now resolves to `0` for a zero-value limit. * PIVOT-14077: Fixed the ID of a deleted limit being re-issued to a subsequently created limit. ### Changed Group IDs of dependencies have changed and must be updated. See the [migration notes](./migrate-6.1#4-2-2-to-6-1-20) for more details. * LIM-2239: Scope strings now use backslash escaping for the reserved characters `| = < > & + [ ] \`, so level, hierarchy, dimension and member names containing any of these characters are preserved through a scope-string round-trip. Existing scope strings without backslashes parse unchanged. See the scope overview and advanced scopes pages for the escape rules. ### Fixed * LIM-2172: Member selection in limit scope sometimes does not allow to remove members. Switching between simple and advanced mode can lead to empty tiles being displayed. * LIM-2215 Permissions: Fixed limit permission checks being silently ignored for users authenticated via SSO. * LIM-2238: Fixed editing a limit's attachment in the Six-Eyes approval workflow failing with a 500 Internal Server Error when re-saving the limit. * LIM-2240: Fixed `ScopeCacheService.refresh()` throwing `IllegalStateException: Duplicate key ... (attempted merging values X and Y)` on every restart when the datastore contained two `LimitStructure`s declaring the same scope keys in a different order. The in-process scope-id dedup in `ScopeTupleGenerator` now keys by the canonical (sorted) scope form, matching what `ScopeCacheService.refresh()` uses, so equivalent scopes share a single id instead of being persisted as two store rows that later collide. * LIM-2241: Fixed the **Add Limit** button being incorrectly disabled when the structure's history contained a deleted limit with an advanced scope, which prevented the creation of new limits. * LIM-2242: Fixed KPIs not displaying on dashboards for limits with `TOTAL_EQUALS` / `TOTAL_EXCEPT` advanced scopes on multi-level hierarchies. * LIM-2244 Temporary limits: Fixed temporary limit creation failing from the KPI Drawer when selecting a different member on a multi-level hierarchy. * LIM-2251: Fixed Atoti Limits failing to start for applications with a very large number of workflows. Warming the workflow cache at startup previously fetched tasks one workflow id at a time and queried their variables with one bind parameter per workflow, which could exceed the database's per-query parameter limit (such as SQL Server's 2100-parameter cap) and fail with a "query too large" error. Tasks are now retrieved in a single bulk query and their variables are fetched in batches sized to stay under each database's parameter limit. * PIVOT-13934: Fixed an NPE on Limits startup when the content server held a calculated measure whose content was not readable by the Limits service account (for example a measure created by another user with restrictive owners/readers). Such measures are now skipped with a WARN log identifying the measure name and the reason (missing read permission, empty content, or directory entry). # Migration guide Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/6.1/migrate-6.1 From version 6.1.20 onwards, Atoti Limits version numbers are aligned with the Atoti Java SDK. Previously, Atoti Limits used its own versioning (the last release under the old scheme was 4.2.2). The jump in version numbers reflects this alignment. There are no missing releases between 4.2.2 and 6.1.20. # 4.2.2 to 6.1.20 Maven dependencies have changed: update the following group IDs in your `pom.xml`: * `com.activeviam.solutions` → `com.activeviam.modules` * `com.activeviam.solutions.limits` → `com.activeviam.modules.limits` * `com.activeviam.solutions.services` → `com.activeviam.modules.services` # 6.1.21 to 6.1.22 This release only shipped bug fixes and performance improvements. It does not require any migration. # 6.1.20 to 6.1.21 This release only shipped bug fixes and performance improvements. It does not require any migration. # Release notes Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/previous-versions/6.1/release-notes-6.1 From version 6.1.20 onwards, Atoti Limits version numbers are aligned with the Atoti Java SDK. Previously, Atoti Limits used its own versioning (the last release under the old scheme was 4.2.2). The jump in version numbers reflects this alignment. There are no missing releases between 4.2.2 and 6.1.20. For the list of issues covered in this release, and known issues, see the [Changelog](./changelog-6.1). For information on upgrading from previous versions, see the [Atoti Limits Migration Notes](./migrate-6.1) Follow [this link](https://activeviam.jfrog.io/artifactory/activeviam-accelerators-artifacts/limits/6.1.23/) to download the zipped distribution files for: * **UI source code** * **UI build** * **Source files** to build the module * **Sample bookmarks** * **Maven repository** required to build the project and run the tests. ### Summary **Improvements** * [Bug fixes and performance improvements](#bug-fixes-and-performance-improvements) ### Improvements #### Bug fixes and performance improvements This is a bug fix and performance release. Please see the [Changelog](./changelog-6.1) for more details. Follow [this link](https://activeviam.jfrog.io/artifactory/activeviam-accelerators-artifacts/limits/6.1.22/) to download the zipped distribution files for: * **UI source code** * **UI build** * **Source files** to build the module * **Sample bookmarks** * **Maven repository** required to build the project and run the tests. This release does not ship any changes. Follow [this link](https://activeviam.jfrog.io/artifactory/activeviam-accelerators-artifacts/limits/6.1.21/) to download the zipped distribution files for: * **UI source code** * **UI build** * **Source files** to build the module * **Sample bookmarks** * **Maven repository** required to build the project and run the tests. ### Summary **Improvements** * [Bug fixes and performance improvements](#bug-fixes-and-performance-improvements) ### Improvements #### Bug fixes and performance improvements This is a bug fix and performance release. Please see the [Changelog](./changelog-6.1) for more details. Follow [this link](https://activeviam.jfrog.io/artifactory/activeviam-accelerators-artifacts/limits/6.1.20/) to download the zipped distribution files for: * **UI source code** * **UI build** * **Source files** to build the module * **Sample bookmarks** * **Maven repository** required to build the project and run the tests. ### Summary **Improvements** * [Bug fixes and performance improvements](#bug-fixes-and-performance-improvements) ### Improvements #### Bug fixes and performance improvements This is a bug fix and performance release. Please see the [Changelog](./changelog-6.1) for more details. # Release notes Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/releases/release-notes For the list of changes and fixes covered in this release, see the [Changelog](./changelog). For information on upgrading from previous versions, see the [Migration guide](./migration-guide) ### Summary Follow [this link](https://activeviam.jfrog.io/artifactory/generic/limits/6.2.1/) to download the zipped distribution files for: * **UI source code** * **UI build** * **Source files** to build the module * **Sample bookmarks** * **Maven repository** required to build the project and run the tests. ### Summary **Improvements** * [Bug fixes and performance improvements](#bug-fixes-and-performance-improvements) ### Improvements #### Bug fixes and performance improvements * Incident and notification event streams are no longer buffered or compressed by reverse proxies. Real-time updates are now delivered as they happen, instead of only once the stream ends. * Limits scoped to a slicing hierarchy now evaluate every matching member, including multi-level `(Total)` subtotals, instead of only the default member. * Limits at the `(Total)` of a first level of multi-level slicing hierarchy now appear in the UI. * The Audit Screen no longer reports a spurious change (for example `100 → 100`) when a numeric value has not actually changed. * The Audit Screen now records breach reviews and other workflow actions, not only the initial creation entry. * Creating a limit structure with no limits no longer risks an application error. * Querying a limit's Goal or Status no longer fails with an error when the requested date falls outside the limit's date range. * Approving an update or deletion of a limit with an attachment no longer fails with an error. This error could previously leave Atoti Limits unable to restart. * Workflow buttons ("Approve", "Reject", "Review breach") are now disabled for users without the required permission, instead of showing an "Access Forbidden" error after being clicked. This is a bug fix and performance release. Please see the [Changelog](./changelog) for more details. Follow [this link](https://activeviam.jfrog.io/artifactory/generic/limits/6.2.0/) to download the zipped distribution files for: * **UI source code** * **UI build** * **Source files** to build the module * **Sample bookmarks** * **Maven repository** required to build the project and run the tests. ### Summary **New features** * [Atoti Limits Python plugin](#atoti-limits-python-plugin) **Improvements** * [Spring Boot 4 and Java 25](#spring-boot-4-and-java-25) ### New features #### Atoti Limits Python plugin Atoti Limits now ships a Python plugin that is a first-class citizen of the Atoti Python SDK. This plugin is intended to replace the Atoti Limits Python server extension, which connected a session to a running server from outside the SDK's plugin system. ### Improvements #### Spring Boot 4 and Java 25 Atoti Limits has been updated to use Spring Boot 4 and Java 25. # Audit History screen Source: https://docs.activeviam.com/atoti-intelligence/workflows/limits/6.2/user-ref/audit-screen How to use the Audit History screen to view a complete record of all limit and workflow activity in one place. The **Audit History** lets you view all your audit entries in a single screen. Check out our video overview of the Audit Service: