Skip to main content

DRE — User Manual

Last updated: 2026-06-13

This manual is for retail organisations, marketing planners, store operators, and compliance teams who work with the Digital Retail Engine (DRE). It describes the user interface, daily workflows, and common questions.

For technical integration details (POS API, OAuth2, webhooks), please read the Integrator Guide — in particular Promotion Scenarios & Action Types and the POS Integration Service reference.


Table of Contents​


Phase 1 — Setup​

1.1 Maintain product master data​

Last updated: 2026-05-28

DRE works headless. The platform compares item identifiers (articleNumber, EAN, articleGroup_ID) as plain strings. A condition like articleNumber = "BBQ-GRILL-001" evaluates correctly without master data — the POS sends the ID in the basket payload, and the platform evaluates the condition. An unknown article in the basket is not an error.

You need master data for:

  • Value help in the UI — when you create a promotion, you select items and item groups from a list instead of typing them by hand.
  • Item-to-group mapping — when a condition checks "item from group Wines", the platform needs the group assignment. In headless setups, the POS can send the group ID directly in the basket-item payload instead.
  • Reports and analytics — reports show item names instead of just the item number.
  • Local store instance — when you run DRE offline with a local instance, you need master data available at the store.

This section explains how to create individual items, upload them via CSV import, and check the import result.

Example: You want to import 500 BBQ items from your product range to start a grill season campaign. The fastest way is the CSV import.

Create a single item​

What you'll need: The "Master Data Manager" access right in the platform.

  1. Open Master Data → Items from the Launchpad.
  2. Click Create.
  3. Fill in the required fields:
    • Item number — a unique identifier (for example, "BBQ-GRILL-001"). Must be unique across the platform. Required — you cannot save the item form if this field is empty.
    • Name — a readable item name (for example, "Premium Charcoal Grill 60cm"). Required — you cannot save the item form if this field is empty.
  4. Optional fields:
    • EAN — European Article Number, exactly 13 digits (EAN-13) with GS1 check-digit validation. 8-digit EAN-8 codes or invalid check digits are rejected.
    • Category — free-text category label (for example, "BBQ-ITEMS") used to classify the item for reporting. Assignment to item groups is done in a separate Item Groups section on the item detail page.
    • Manufacturer — manufacturer name used for manufacturer-based promotion conditions.
  5. Click Save. If you leave a required field empty, the platform shows an error message.

Import items via CSV file​

Bulk import is the right choice when you want to create or update many items at once — for example, 500 BBQ items after a product range change.

What you'll need: The correct CSV template. You can download it directly from the import dialog.

  1. Open Master Data → Items.
  2. Click Import.
  3. In the dialog, click Download sample template to get the current template.
  4. Fill the template with your items. Follow the column headings — each column has help text in the template. The supported columns are articleNumber, name, ean, manufacturer, and category (the first CSV line is the header).
  5. Save the CSV file and upload it in the dialog.
  6. Click Upload.

The importer accepts CSV or JSON. You can optionally provide an Idempotency Key — the key is logged for tracking purposes. If you re-submit the same article, the import fails with a conflict error (article number already exists).

Important: Always download the latest CSV template from the platform. Older templates may contain fields that are no longer current — this causes import errors.

Import rules:

  • There is no fixed row limit per import. Because the rows are processed one after another in your browser, split very large lists into several smaller files for a smoother import.
  • If an item number already exists in the platform, the row is reported as a conflict in the error list (HTTP 409 "Article with articleNumber … already exists"). You cannot update existing items via the import dialog.
  • Every item needs an item number and a name. Rows without these fields are rejected.
  • Invalid EANs are rejected (error message in the results list).

Check the import result​

The CSV import processes the rows directly in your browser. During processing you see a short status message ("Importing N article(s)..."). As soon as the last row is processed, DRE shows a result dialog. This dialog summarises how many items were created or updated and which rows failed.

The dialog appears in one of three variants:

VariantWhenContent
SuccessAll rows were imported"Imported N of N article(s)."
WarningSome rows were imported, others failed"Imported N of M article(s)." plus a list of the failed rows with row number and reason
ErrorNo row was imported"Imported 0 of M article(s)." plus the error list

With more than 20 failed rows, the dialog shows the first 20 reasons and notes the number of remaining errors.

Close the result dialog with OK. The successfully imported items appear in the item list immediately — you do not need to reload the page.

If you close the app during the import, processing stops. Keep the browser window open until the result dialog appears. For very large imports, prefer to import in several smaller jobs.

Sync items from your ERP system​

If your organisation runs SAP S/4HANA, your IT team can set up automatic product synchronisation. Product master data is replicated directly from S/4HANA into DRE — without manual CSV imports.

For this setup, contact your IT team. The technical guide for DRFOUT integration is in the Integrator Guide.

Common questions about product master data​

Why is my EAN rejected? EAN must be exactly 13 digits (EAN-13) and pass GS1 check-digit validation. 8-digit EAN-8 codes or invalid check digits are rejected. You must provide a correctly formatted EAN before you can import it.

Can I delete an item? Yes. An item can be deleted at any time. Because the platform matches conditions on the item number and EAN as plain strings, deleting a master-data item does not remove or block the promotion conditions that reference its number — those conditions keep matching the basket payloads the POS sends.

Some rows of my import failed — what now? The result dialog lists each failed row with row number and reason. Correct the affected items in the CSV file. Then start a new import with only the corrected rows — you do not need to re-upload the items that were already imported successfully.


1.2 POS groups, priority groups, and exclusion groups​

Last updated: 2026-05-28

Before you create promotions, decide which POS terminals are allowed to see which promotions. DRE uses three group concepts: POS groups (stores / terminal sets), priority groups (ranking when conflicts occur), and exclusion groups (mutual blocking).

POS groups: group stores together​

A POS group combines POS terminals into a logical set. Promotions can be restricted to specific POS groups.

Example: During Oktoberfest, special prices should apply only in "Stores South" (Munich, Augsburg, Nuremberg) — not nationwide.

Create a new POS group:

  1. Open Master Data → POS Groups from the Launchpad.
  2. Click Create.
  3. Enter a Code (required, for example "STORES-SOUTH"), a Name (for example, "Stores South"), and an optional Description.
  4. Click Save.

A POS group is just this Code/Name/Description record — it does not hold a list of terminal IDs. The link between terminals and a group is made when you restrict a promotion to the group: on the promotion object page you add one row per group in the POS groups section (value help per row). Without a restriction, the promotion applies to all terminals.

Priority groups: ranking when multiple promotions apply​

When several promotions apply to the same basket at the same time, the priority value (a number: higher means higher priority) determines which promotion is evaluated first. Promotions with the same priority are treated as equal-ranked. Promotions without a priority group receive the default value 0.

Practical rule:

  • Set important standing promotions to priority 30 (highest priority, evaluated first).
  • Seasonal promotions to priority 20.
  • Flash sales and clearance to priority 10 (lowest priority, evaluated last).

There is no priority field on the create/edit form of a promotion. You set priority by assigning the promotion to a priority group — the group carries the integer priority value. You manage these assignments in the Priority Groups app: open a priority group's object page and add the promotions inline in the linked-promotions section.

Exclusion groups: block promotions from each other​

With exclusion groups (MutualExclusionGroups), you define that, of several promotions within a group, only the best one applies — regardless of the exclusivity level.

Example: Two beer promotions ("Weekend 20% off beer" and "Loyalty discount €3 off beer") should block each other, but a receipt-wide 2% promotion should still apply on top. Put the two beer promotions into the exclusion group "Beer Promos".

Assign an exclusion group:

  1. Open the promotion in edit mode.
  2. Open the Exclusions section.
  3. Click Add in the table and select the desired group via the value help in the Exclusion group field.
  4. Click Save.

Within an exclusion group, by default the promotion with the highest discount amount for the specific basket wins (resolutionStrategy: HIGHEST_DISCOUNT). Alternatively, you can set the LOWEST_DISCOUNT strategy per group, in which case the promotion with the smallest discount wins. The others are rejected with the note "Blocked by mutual exclusion group".

Note: Exclusion groups and the exclusivity level (see section 2.1 Promotion authoring) can be combined. Exclusion groups act within the group; exclusivity levels act beyond it.


1.3 Stakeholder management and budget funding​

Last updated: 2026-05-28

Budgets in DRE can be funded by one or more stakeholders — for example, your own marketing department, a brand partner, or an external supplier contributing co-op marketing funds (CMF). This section explains how to create stakeholders, link them to budgets, and track spending.

When do I need stakeholders?

  • You want to record who funds a promotion budget.
  • An external supplier is contributing co-op marketing funds and you want to clearly attribute spending to that supplier.
  • You want to generate monthly spending reports per funder.

Example: Coca-Cola provides €50,000 CMF for the summer drinks campaign. You create Coca-Cola as a stakeholder of type EXTERNAL_SUPPLIER and link it to the campaign budget.

Stakeholder types​

DRE distinguishes four stakeholder types:

TypeDescriptionExample
INTERNALInternal department of your own organisationMarketing department, purchasing
BRANDBrand partner (provides funds for brand-related promotions)Coca-Cola, Nike
SUPPLIERInternal supplierCentral warehouse, own wholesaler
EXTERNAL_SUPPLIERExternal supplier with a CMF agreementWine supplier with 5% co-op contribution

The EXTERNAL_SUPPLIER type is specifically for CMF (co-op marketing funds) workflows. It lets you clearly attribute budget portions to an external partner and track reimbursement claims.

Create a new stakeholder​

  1. Open the Stakeholders app from the Launchpad.
  2. Click Create.
  3. Fill in the fields:
    • Name — a unique label (for example, "CMF Coca-Cola GmbH").
    • Type — select the appropriate type from the list.
    • Contact Email (optional) — the stakeholder's primary contact address (for example, for co-op marketing coordination).
  4. Click Save.

A budget can be linked to one or more stakeholders. Each stakeholder receives a share of the total budget.

  1. Open the Budgets app and select an existing budget or create a new one.
  2. Scroll to the Stakeholders section.
  3. Click Add.
  4. Select the stakeholder from the list.
  5. Enter the Share (%) — the stakeholder's percentage share of the budget.
  6. Click Save.

View spending history​

The budget detail page has a Spending history tab. It shows when and through which promotion transactions the budget was consumed.

  1. Open a budget in the Budgets app.
  2. Click the Spending history tab.
  3. The table shows date, transaction, promotion, and the amount consumed.

Note: The spending history shows only confirmed transactions — checkouts confirmed through the POS process. Simulations and incomplete transactions do not appear.

Stakeholder cost reports​

For an aggregated view by stakeholder and time period, the Stakeholder Costs dashboard is available:

  1. Open Reports & Analytics → Stakeholder Costs from the Launchpad.
  2. Select the desired time period using a From/To date range.
  3. The dashboard shows:
    • Share per stakeholder — pie chart (percentage share of total consumption).
    • Trend over time — line chart by period.
    • Top promotions per stakeholder — the 10 promotions with the highest budget consumption.

Budget utilization and burn rate​

When a budget is active and transactions have been confirmed, the budget detail page shows current utilization (%). Burn rate and a forecast for the end date are available in the separate Budget Utilization report under Reports & Analytics.

Important — scheduled budgets. A budget with status SCHEDULED (not yet started) shows no burn rate and no projected end date. The reason: the budget has not yet begun consuming transactions — elapsed time is 0. Once the budget's validFrom date arrives and the first transactions are recorded, DRE calculates the metrics and updates the forecast.

These metrics help you identify early if a budget is being consumed faster than expected, so you can take corrective action if needed.

Common questions about stakeholders​

What is the difference between SUPPLIER and EXTERNAL_SUPPLIER? SUPPLIER is an internal supplier (for example, a subsidiary). EXTERNAL_SUPPLIER is an external partner with a CMF agreement — use this type when you want to track reimbursement claims against a third party.

Can I delete a stakeholder? Yes. Deleting a stakeholder is allowed. If the stakeholder still has budget links, DRE shows a warning that the deletion will also remove its related records, and then proceeds — the stakeholder's budget assignments and recharge contributions are removed together with it.

Why is the Spending history tab empty? Either there are no confirmed transactions for this budget yet, or the transactions are still being processed. Check the Pending transactions section on the budget page.


1.4 Notification Log and budget alerts​

The notification log is an audit trail that records every notification the system attempted to send. When a budget reaches a consumption threshold, DRE sends an alert through registered channels; each attempt — success or failure — is logged here.

When do you need it? When you want to verify that budget alerts were actually delivered, or when you need to diagnose failed deliveries.

Accessing the notification log​

  1. Open the launchpad.
  2. Go to the Administration group.
  3. Click the Notification Log tile (bell icon, subtitle "Budget threshold notifications and delivery status").

A list report of notifications opens; click a row to view details.

What the notification log shows​

ColumnMeaning
Budget NameName of the budget that reached the threshold.
Threshold (%)The configured trigger percentage (e.g., 80%).
Consumed (%)The consumption percentage at the moment the notification was sent.
ChannelEmail, webhook, or other delivery channel.
RecipientEmail address or webhook endpoint.
StatusSENT (success), FAILED (delivery error), RATE_LIMITED (too frequent), DISABLED (disabled).
Sent AtNotification timestamp (UTC).
ErrorFor FAILED or RATE_LIMITED: error message or reason.

Status meanings​

  • SENT — At least one channel delivered the notification.
  • FAILED — A delivery error occurred (e.g., invalid email address).
  • RATE_LIMITED — The notification was suppressed because one was already sent for this budget + threshold + channel within the last hour.
  • DISABLED — Notifications are globally off or off for this tenant.

Important notes​

  • The log is read-only — you cannot edit or delete entries.
  • Webhook-related entries: In addition to budget alerts, failed webhook retries and approval request notifications may also appear here.
  • Filtering: You can filter by Status, Channel, and Budget Name.

Phase 2 — Planning​

2.1 Promotion authoring​

DRE supports various promotion types that you create through the Fiori user interface. This section explains the most important patterns — BOGO, bundle, and how exclusivity works in practice.

Authoring BOGO promotions (Buy-N-Get-M-Free)​

A "buy N, get M free" promotion lets a basket contain N+M qualifying items but charges for only N of them — the M cheapest (or most expensive, or random) items receive a 100% discount (up to their line value).

The discount is capped at the value of the free units. If the M selected items cost less than the full amount of their line, only that smaller amount is discounted — the total discount can never exceed the full line total.

Example: "Buy 5 premium cigars at €28 each, get 2 free."

  • Basket contents: 5 cigars × €28 = €140.
  • Condition met (≥ 5 cigars).
  • The 2 cheapest cigars are selected (both at €28).
  • Discount = 2 × €28 = €56 (not €140).
  • Final amount: 140 − 56 = €84.

Another example: "Buy 3 beer 6-packs, get 1 free."

FieldValueWhy
Action typeARTICLE_GROUPDiscount targets a group of items
Discount typePERCENTAGEFree = 100% discount
Discount value100.00Full discount on the selected items
Selection typeCHEAPESTM cheapest items in the group
Application Quantity ModeLIMITEDCap the discount to a fixed count
Application quantity1Number of free items (the "M")
ConditionARTICLE_GROUP = "BEER-6-PACK", minQuantity = 4At least 4 beer 6-packs in the basket

Required field: When you set CHEAPEST/MOST_EXPENSIVE/RANDOM as selection type and LIMITED as quantity mode, Application quantity must be filled in. The platform rejects the save otherwise, to prevent incorrect full-charge calculations.

Behaviour:

  • 3 beer 6-packs in the basket → condition not met (minQuantity=4); no discount.
  • 4 beer 6-packs → the cheapest beer 6-pack receives 100% discount; the other three are at full price.

Check in the simulator:

  1. Open Tools > Simulator in the Fiori Launchpad.
  2. Add 4 rows with the beer 6-pack item (use different prices to see the "cheapest" logic).
  3. Click Simulate. The results panel shows one row at 100% discount and the other three at full price.

Authoring bundle promotions​

A bundle promotion requires several components at fixed minimum quantities and grants a flat discount when all components are present in the basket.

Example: "2 beer 6-packs + 1 grill kit = €10 discount."

FieldValue
Action typeBUNDLE
Discount typeABSOLUTE
Discount value10.00
Max. bundles1 (optional; empty = unlimited)

Add one row per required component in the Bundle components sub-table:

Item numberMin. quantityMax. quantity
BEER-6-PACK2empty
GRILL-KIT1empty

Required field: When you select BUNDLE as action type, at least one bundle component must be present. The platform rejects the save without components.


Authoring tiered-bundle promotions (volume pricing)​

A tiered-bundle promotion (volume pricing) gives a target a quantity discount. The target is either a single article or a whole article group. The more units of the target are in the basket, the lower the per-unit price. The resolved tier price applies to all units, each discounted on its own price.

This is not marginal pricing. When the basket reaches a tier, the tier price is applied to every unit — not only to the units above the quantity threshold.

The target is an article OR an article group — never both. You pick exactly one: either a Target Article Number (one dedicated article code) or a Target Article Group. Set both or neither, and DRE rejects activation.

  • Single article: The tier counts the units of one dedicated article code together.
  • Article group: The tier counts different articles of the same group together (see Target an article group).

The word "bundle" here means the tiered quantity — not a fixed combination of different articles. For a fixed combination of different articles, use the BUNDLE action type instead (see above).

The quantity is summed across the entire basket. If the article appears on multiple lines (for example, two separately recorded items), DRE adds these quantities before it selects the tier.

Example: "Case of mineral water — tiered price from 6 bottles."

Anna creates a promotion that lowers the per-bottle price depending on the purchase quantity: from 6 bottles €1.00 per bottle, from 12 bottles €0.80 per bottle.

How to configure the tier

  1. Open the promotion in edit mode (via the Promotions app in the Launchpad).
  2. In the Discount Actions section, create a discount action and set:
FieldValueWhy
Action typeQUANTITY_TIERVolume pricing for an article
Target Article NumberWASSER-05LThe one dedicated article code that is tiered
Discount value(empty)The prices are in the tiers, not on the action
  1. In the Quantity tier sub-table, maintain one row per tier. Each tier consists of a minimum quantity and a discount type with a discount value:
Min. quantityDiscount typeDiscount valueMeaning
6Unit price1.00From 6 bottles, each bottle costs €1.00
12Unit price0.80From 12 bottles, each bottle costs €0.80

Note on the interface: The Quantity tier sub-table appears as soon as you pick QUANTITY_TIER as the action type.

The three tier types

Each tier uses a discount type. There are three:

Discount typeLabelMeaningExample
UNIT_PRICEUnit priceSets the per-unit price directly — the value is the new per-unit price.Tier value 26.00 → each unit costs €26.00 (for example, the case price per bottle).
PERCENTAGEPercentagePercent off each unit.Tier value 15 → 15% off every unit.
ABSOLUTEAbsoluteAmount off per unit — deducted per unit, not per line.Tier value 3.00 on 4 units → €12.00 off (4 × 3.00), not €3.00.

Important — Absolute is "amount off per unit", not "amount off the whole line". A tier with ABSOLUTE and value 3.00 deducts €3.00 per unit. On 4 units that is €12.00 off, not €3.00. If you want to deduct a fixed amount from the whole line, QUANTITY_TIER is the wrong action type — use a regular discount action for that.

Below the lowest tier — full price, no discount

If the summed quantity is below the minimum quantity of the lowest tier, the customer pays the full price with no discount.

This differs from scaled receipt discounts (SCALED_RECEIPT): there, a base discount applies below the first tier. With the volume tier there is no base discount.

So that every quantity gets a price: Add a tier with minimum quantity 1. Without this tier, small quantities pay the full regular price.

Example (the most common misconfiguration): You maintain only two tiers — 3 → €30.00 and 4 → €26.00 (each Unit price).

  • 1 or 2 units → full regular price (no tier reached, no discount).
  • 3 units → each unit €30.00.
  • 4 or more units → each unit €26.00.

If 1 and 2 units should also get a price, add a tier with minimum quantity 1.

Ceiling — the highest tier applies without an upper limit

When the quantity reaches or exceeds the highest minimum quantity, the highest tier applies to all units. More units never reduce the discount again. In the example above, at 4, 10, or 50 units each bottle costs €26.00.

Worked example

Basket: 12 bottles WASSER-05L, regular price €1.20 per bottle.

  • Summed quantity = 12.
  • Highest tier reached = 12 → €0.80 (Unit price).
  • Final price: 12 × €0.80 = €9.60 (instead of 12 × €1.20 = €14.40).
  • Saving: €4.80.

At 8 bottles the tier 6 → €1.00 applies: 8 × €1.00 = €8.00 (instead of €9.60). At 4 bottles no tier is reached — the customer pays 4 × €1.20 = €4.80 with no discount.

Save rules

  • You specify exactly one target: either a Target Article Number or a Target Article Group. Set both or neither, and DRE rejects activation.
  • At least one tier must be present.
  • The minimum quantities must be integers, at least 1, and strictly ascending and unique across all tiers. DRE rejects two tiers with the same minimum quantity.
  • The discount value of each tier must be greater than 0; for Percentage, at most 100.
  • If the tier targets an article group, every tier must use the discount type Percentage. Unit price and Absolute are allowed only for a single article.

Check in the simulator

  1. Open Tools > Simulator in the Fiori Launchpad.
  2. Add a row with the dedicated article and set the quantity to 12.
  3. Click Simulate. The results panel shows the tier price on all 12 units.
  4. Lower the quantity to 4 (below the lowest tier) and simulate again — the line stays at the regular price, with no discount.
Target an article group​

Instead of a single article, you tier a whole article group. The difference: with a group, different articles of the same group count together toward the quantity. This lets a customer reach the tier even when they mix different articles of the group.

Each unit is discounted on its own price. The tier only sets the percentage; it does not set a shared price across different articles. For that reason, group tiers work exclusively with the discount type Percentage — a fixed unit price or a fixed amount would make no sense across different articles.

Example: "Cigar promotion — tiered discount across the whole range."

Anna wants to promote cigar sales, regardless of the individual variety. She creates a promotion that gives a quantity discount on the article group CIGARS: from 3 units 10% off each unit, from 5 units 15% off each unit.

How to configure the group tier

  1. Open the promotion in edit mode (via the Promotions app in the Launchpad).
  2. In the Discount Actions section, create a discount action and set:
FieldValueWhy
Action typeQUANTITY_TIERVolume pricing
Target Article GroupCIGARSThe group whose articles count together — leave the Target Article Number empty for this
Include sub-groups(off)Default: only articles assigned directly to the group CIGARS count
Discount value(empty)The percentages are in the tiers, not on the action
  1. In the Quantity tier sub-table, maintain one row per tier. With a group, the discount type is always Percentage:
Min. quantityDiscount typeDiscount valueMeaning
3Percentage10From 3 cigars (varieties mixed) 10% off each unit
5Percentage15From 5 cigars (varieties mixed) 15% off each unit

Include sub-groups. By default the option is off: only articles assigned directly to the group count toward the tier. Switch the option on, and the articles of all sub-groups of the target group count as well. Example: if CIGARS has the sub-groups CIGARS-MILD and CIGARS-STRONG, their articles count toward the quantity only when the option is on.

Note on the interface: The Target Article Group and Include sub-groups fields appear as soon as you pick QUANTITY_TIER as the action type.

Worked example (mixed varieties)

Basket: 2 × CIGAR-CHERRY at €4.00 and 3 × CIGAR-LIME at €5.00. Both articles are assigned to the group CIGARS.

  • Summed quantity in the group = 2 + 3 = 5 units.
  • Highest tier reached = 5 → 15%.
  • Cherry cigars: 2 × €4.00 − 15% = 2 × €3.40 = €6.80.
  • Lime cigars: 3 × €5.00 − 15% = 3 × €4.25 = €12.75.
  • Final price: €19.55 (instead of €23.00), saving €3.45.

Each variety keeps its own price; only the percentage selected by the summed group quantity is shared.

Check in the simulator (group)

  1. Open Tools > Simulator in the Fiori Launchpad.
  2. Add two rows with different articles of the same group — for example, 2 × CIGAR-CHERRY and 3 × CIGAR-LIME.
  3. Click Simulate. The results panel shows the same percentage discount on both rows, because the group quantity reaches 5.
  4. Reduce to a total of 2 units of the group and simulate again — no tier is reached, both rows stay at the regular price.

Next steps


Authoring free-item promotions (FREE_ITEM)​

A free-item promotion (action type FREE_ITEM) grants an article for free as soon as the promotion's conditions are met. You set a target article code and a free quantity. When the promotion matches, that quantity of the article is free for the customer.

DRE decides per basket how the free item is recorded — depending on whether the article is already in the basket:

  • Already in the basket: The relevant unit becomes free. It stays on the receipt and is flagged as a free item. The unit price of this unit is set to €0.00.
  • Not in the basket: DRE adds it as a free grant. The customer does not have to put the article in the basket themselves to receive it.

If only part of the free quantity is in the basket, DRE combines both: the present units become free and the shortfall is added as a grant.

Example: "From €50 spend: one cup of coffee free."

Anna creates a promotion with the condition "basket value ≥ €50" and attaches a free-item action that grants one cup of coffee (KAFFEE-TO-GO) for free.

How to configure the free-item action

  1. Open the promotion in edit mode (via the Promotions app in the Launchpad).
  2. In the Discount Actions section, create a discount action and set:
FieldValueWhy
Action typeFREE_ITEMGrant or add a free item
Free Item Article NumberKAFFEE-TO-GOThe article that is granted for free (required field)
Free Item Quantity1Number of free units (default: 1)
Restrict To One Per BasketYesAt most one free unit per basket (default)
Free Item Reference Price2.50Value of the grant when no basket price is available
Discount value(empty)A free item has no discount value

Note on the interface: The fields for the free-item action appear as soon as you pick FREE_ITEM as the action type.

Cap the free quantity — "Restrict To One Per Basket"

The field Restrict To One Per Basket (restrictToOnePerBasket) controls how often the free item is granted. It is enabled by default:

SettingMeaning
Yes (default)At most one free unit of this code across the whole basket — even when several promotions grant the same article.
NoThe free quantity follows the Free Item Quantity field and can grow with the triggers, bounded by Maximum Free Units.

The cap applies globally per article code: if two different promotions each trigger one free cup of coffee in the same basket and Restrict To One Per Basket is on for at least one of them, the customer receives one free cup in total, not two. When you save, the field shows the note "at most one free unit of this code across the whole basket".

Maximum Free Units — a hard cap

The optional field Maximum Free Units (maxFreeUnits) limits the total number of free units this action grants — regardless of price. Empty means unlimited (unless Restrict To One Per Basket already limits it to one unit).

The value of the grant — Free Item Reference Price and €0.00

Every free item is assigned a value, so that budget and reports capture the cost of the grant. DRE determines this value in this order:

  1. Basket price: If the article is in the basket, its recorded unit price is used.
  2. Free Item Reference Price: Otherwise, the Free Item Reference Price you maintain (freeItemReferencePrice).
  3. Master data price: A price from the article master data (not populated today — the article master data currently has no price column; DRE works master-data-optional).
  4. Unknown → €0.00: If no price can be determined, the grant is reported with €0.00. Reports can flag these cases.

Save rule — at least one bound is required. A free-item action must satisfy at least one of three bounds: (a) a positive Free Item Reference Price, (b) a Maximum Free Units cap, or (c) the toggle Restrict to one per basket is enabled (default: enabled). If all three bounds are disabled or empty, DRE rejects the action at save.

Save rules

  • The Free Item Article Number is required. Without it, DRE rejects the action.
  • Free Item Quantity and Maximum Free Units, if set, must be integers and at least 1.
  • There must be either a positive Free Item Reference Price or a Maximum Free Units cap (see the rule above).
  • The discount value of the action stays empty — a free item carries no discount value.

Worked example

Basket: a purchase over €54 including one cup of KAFFEE-TO-GO at €2.50. The promotion "From €50, one cup of coffee free" matches.

  • The cup is already in the basket → its unit becomes free.
  • The unit price of the cup is set to €0.00; the line stays on the receipt and is flagged as a free item.
  • Value of the grant: €2.50 (basket price).
  • Final amount: €54.00 − €2.50 = €51.50.

If the cup was not in the basket, DRE adds it as a free grant; the value (€2.50) then comes from the Free Item Reference Price.

Check in the simulator

  1. Open Tools > Simulator in the Fiori Launchpad.
  2. Add rows that meet the condition (for example, basket value ≥ €50), and include the free item once with and once without it in the basket.
  3. Click Simulate. If the article is in the basket, the results panel shows the line at €0.00 as a free item; if it is not in the basket, it appears as a free grant.

Next steps


Authoring post-purchase coupon promotions (POST_PURCHASE_COUPON)​

A post-purchase coupon promotion (action type POST_PURCHASE_COUPON) automatically gives the customer a coupon for their next visit after checkout. The coupon code is printed directly on the receipt and can be redeemed on the next purchase.

These promotions encourage repeat visits. They complement instant discounts: the customer does not get an immediate price benefit, but a credit for the future — ideal for loyalty programs or customer retention.

Example: "Every grill purchase over €100 comes with a €5-off coupon for the next visit."

Anna creates a promotion with the condition "basket value ≥ €100" and attaches a post-purchase coupon action that issues a €5-off coupon.

Prerequisites

  • The target coupon type must be single-use (INDIVIDUAL). Shared coupons (GENERIC) cannot be issued as post-purchase coupons. The system rejects the save if you choose a GENERIC type.
  • Optional but recommended: Enable auto-refill for the coupon type to ensure enough coupon codes are available. Without auto-refill, each issued coupon is generated by the asynchronous worker when fulfilled. Pre-generating a pool of codes (auto-refill) reduces worker load and avoids coupon pool exhaustion stalls. See Coupon codes and auto-refill for details.

How to configure the post-purchase coupon action

  1. Open the promotion in edit mode (Promotions app in the launchpad).
  2. Add a discount action in the Discount Actions section and set:
FieldValueWhy
Action typePOST_PURCHASE_COUPONPost-purchase coupon
Target coupon type(single-use coupon type name)The coupon type from which the code is issued (required field); must be type INDIVIDUAL
Discount value(empty)Post-purchase coupons carry no discount value on the action

Note on the interface: The fields for the post-purchase coupon action appear as soon as you pick POST_PURCHASE_COUPON as the action type.

How it works

  1. The customer meets the promotion's conditions (e.g., basket value ≥ €100).
  2. The receipt is processed and the post-purchase coupon action is triggered.
  3. The system assigns the customer an available coupon code from the configured type. If no codes remain in the pool, one is generated on the fly.
  4. The coupon code is printed on the receipt. The customer takes it home.
  5. On the next visit, the customer enters the code at the POS terminal. The terminal accepts it and applies the discount.

Coupons for anonymous customers

Post-purchase coupons are printed as codes on the receipt — they work even for anonymous customers not enrolled in a loyalty program. The code itself is the proof. The system does not need a customer ID to issue or redeem.

Coupon expiry and availability

The expiry date is determined by the coupon type, not the promotion. Open the Coupon Types app and check the Valid until field of the configured coupon type. After that date, no new codes can be issued.

Save rules

  • The Target coupon type is required. Without it, the DRE rejects the action.
  • The selected coupon type must be single-use (INDIVIDUAL). If the type is GENERIC (multi-use coupon), the DRE rejects the save with an error message.
  • The Discount value remains empty — the action carries no discount value.

Worked example

Basket: €120 (grill accessories). The promotion "€5-off coupon for every €100+" applies.

  • Condition met (≥ €100).
  • The system assigns a code from the configured coupon type, e.g. GRILL26-ABC123.
  • The code is printed on the receipt: "Discount coupon: GRILL26-ABC123 (€5.00), valid until [date from the type]".
  • The customer takes it home.
  • On the next visit, they enter the code. The terminal accepts it and grants a €5.00 discount.

Check in the simulator

The simulator does not show post-purchase coupons (they are created only in live transactions). But you can check the promotion's condition:

  1. Open Tools > Simulator in the launchpad.
  2. Add line items that meet the condition (e.g., basket value ≥ €100).
  3. Click Simulate. The result shows the post-purchase coupon action as applied (though the actual code appears only in the real receipt).

Check redemptions

Redeemed coupons appear later in the Coupon Analytics report (Launchpad → Reports & Analytics → Coupon Analytics). There you can:

  • Issued — how many coupons were issued in total.
  • Redeemed — how many were redeemed later.
  • Redemption rate — the percentage (redeemed divided by issued).
  • Avg days to redeem — average number of days between issuance and redemption.

See Coupon Analytics for the full report.

Next steps


Stacking and exclusivity in practice​

DRE controls whether multiple promotions can be applied to the same basket at the same time using the exclusivity level field (ExclusivityLevel). There are four levels:

LevelMeaning
NONEDefault. The promotion stacks with all others.
PROMOTIONOnly the best promotion at this level applies within the same priority rank.
GROUPOnly the best promotion within the same exclusion group applies.
GLOBALNo other promotion may be applied at the same time.

The four scenarios below show how this works in practice.


Scenario A — Stack-all (default, all set to NONE)

Basket: BBQ grill €99.00 + beer 6-pack €9.00 + premium cigars €35.00 = €143.00

Three active promotions, all with ExclusivityLevel: NONE:

  • "10% off grills" → −€9.90
  • "5% off receipt total" → −€7.15
  • "15% off tobacco" → −€5.25

Result: All three apply. Total saving €22.30, final amount €120.70.

No conflict — because all are set to NONE, the platform stacks them without mutual blocking.


Scenario B — GLOBAL blocks everything

Same basket (€143.00) plus a fourth promotion: "Black Friday 25%" with ExclusivityLevel: GLOBAL.

Result: Only "Black Friday 25%" applies (−€35.75, final amount €107.25). The other three promotions are rejected as blocked by the GLOBAL promotion "Black Friday".

When multiple GLOBAL promotions are active: The platform selects the one with the highest discount amount for the specific basket.


Scenario C — Exclusion group (MutualExclusionGroup)

Basket: 2× beer 6-pack at €9.00 each = €18.00

Two beer promotions in the exclusion group "Beer Promos":

  • "Beer Weekend 20%" → −€3.60
  • "Loyalty discount €3" → −€3.00

Plus a receipt-wide promotion (not a member of the group):

  • "2% off receipt" → −€0.29

Result: Within the exclusion group, "Beer Weekend 20%" wins (higher amount). "Loyalty discount €3" is blocked. The receipt-wide 2% promotion stacks on top. Total saving €3.89, final amount €14.11.


Scenario D — PROMOTION level

Basket: BBQ grill €99.00

Three promotions, all with ExclusivityLevel: PROMOTION, same priority rank:

  • "10% grill discount" → −€9.90
  • "€15 clearance promotion" → −€15.00
  • "5% new-customer discount" → −€4.95

Result: "€15 clearance promotion" wins (highest discount amount). The other two are rejected as blocked by the PROMOTION-exclusive promotion "Clearance". Final amount €84.00.

Practical tip: Use PROMOTION when several similar promotions exist and only the best one should apply for the customer — without having to maintain an explicit exclusion group.


Promotion Templates — blueprints for recurring promotions​

A promotion template is a frozen blueprint of a promotion that you can reuse repeatedly as the starting point for new promotions. Instead of rebuilding conditions and actions every time, you materialize a template once, and DRE creates a new, ready-to-edit promotion in draft status.

Example: You run the same "weekly leaflet promotion" every week with the same scenario (e.g., "Beer 6-packs ≥ 6 = 5% discount"). A template saves manual setup each time.

Accessing promotion templates​
  1. Open the launchpad.
  2. Go to the Promotions group.
  3. Click the Promotion Templates tile.

The list report shows all saved templates. Click a template to open it.

Materializing a template (converting to a promotion)​
  1. Open a template in the object page.
  2. Click the Materialize as Promotion button in the header.
  3. A dialog asks for:
    • Promotion Name — what the new promotion should be called.
    • Valid From — start date.
    • Valid To — end date.
  4. Click Create. DRE creates a new promotion in Draft status with the same scenario (conditions and actions copied).
  5. Adjust the name, dates, or other details as needed.
  6. Activate the promotion as usual.
Important notes​
  • Templates are editable. "Frozen" means they are a static snapshot; however, you can create, edit, and delete them at any time.
  • Materialization always creates a draft — not activated. You must approve the new promotion separately.
  • Roles: Only admins can create/edit templates. PromotionManagers and approvers have read-only access.
  • Known limitation: Scaled-receipt tiers, quantity tiers, and bundle components (scaledTiers, quantityTiers, bundleComponents) are not deep-copied today — you must add these manually after materialization.

2.2 Coupon codes and auto-refill​

Coupon types that issue single-use codes can run out of codes during an active campaign — as soon as the pool of unused codes reaches zero, the next shopper at the POS terminal sees a "No codes available" message. Auto-refill prevents this by automatically topping up the pool once the stock falls below a threshold you configure. You enable it once per coupon type; the platform handles the rest in the background.

This section is for promotion managers and marketing planners. You configure auto-refill on the Coupon Types detail page (Fiori Launchpad → Coupons → select a coupon type).

When is a refill triggered?​

Auto-refill monitors the count of ACTIVE (unused, not redeemed, not expired) codes for the coupon type. As soon as this count falls below the refill threshold you set, the platform generates a new batch of codes — the size of that batch is the Codes per refill value — and the new codes are immediately available to shoppers.

The check runs on a schedule in the background. The scheduler tick evaluates every enabled refill schedule once a minute; the actual refill interval per schedule comes from the linked code configuration (field refillIntervalMinutes). Without a linked code configuration, the platform uses a safe default of 60 minutes per schedule.

If you leave Code configuration empty, the platform checks each schedule every 60 minutes (safe default). For tighter intervals, link a code configuration with refillIntervalMinutes ≥ 1.

Configure​

  1. Open the Coupon Types app from the Fiori Launchpad.
  2. Select the coupon type you want to auto-refill. The detail page opens.
  3. Scroll to the Auto-Refill section.
  4. Click Enable auto-refill in the action bar at the top of the page.
  5. Fill in the dialog:
FieldMeaningTypical value
Refill thresholdWhen unused codes fall below this value, a refill is triggered.100
Codes per refillHow many new codes the platform generates per refill.500
Code configuration (optional)Saved configuration for format (prefix, length, character set) and refill interval (refillIntervalMinutes). Leave empty for the 60-minute per-schedule default.empty
EnabledToggle to enable/disable without losing settings.on
  1. Save. The Refill history sub-table at the bottom of the page starts recording every batch the platform generates.

Tip: Set the threshold high enough to cover the expected redemption rate between two refill intervals. For a campaign consuming ~50 codes per minute, a threshold of 100 at the 60-minute default interval is too tight — either link a code configuration with a shorter refillIntervalMinutes, or significantly raise the threshold and batch size (for example to 5000).

View status​

The Auto-Refill section on the detail page shows two read-only timestamps:

FieldMeaning
Last CheckedTimestamp of the last check. If this is older than the configured interval, the scheduler may have stopped — check the Aggregator Runs tile.
Last RefilledTimestamp of the last successful refill. If "Last Checked" is moving but "Last Refilled" is not, the threshold has not been crossed yet — that is normal.

The Refill history sub-table lists every batch the platform generated, with timestamp, code count, and the resulting batch ID.

Disable​

You have two options, both reversible:

  • Pause — open the Auto-Refill section, click Update auto-refill, and switch Enabled to off. Threshold and batch size are retained; switch the toggle back on to resume.
  • Disable — click Disable auto-refill in the action bar. Same effect as pausing, but in one click with a clear label.

The existing pool of unused codes remains valid in both cases — only the automatic top-up stops.


2.3 Activation on specific weekdays​

You can restrict a promotion to specific weekdays. This lets you set up, for example, a "Monday breakfast offer" or a "weekdays" promotion without creating several separate promotions.

Note: This weekday control replaces the former "Recurring Promotion Patterns" app. Its launchpad tile has been removed. You now maintain day-based activation directly on the promotion.

Where to find it. Open a promotion and switch to edit mode. The Days of Week section is on the promotion page, between Validity and Promotion Scenario.

How to select weekdays:

  1. Use a preset — Every Day, Weekdays (Mon–Fri), or Weekends (Sat–Sun).
  2. Or toggle individual days on and off with the day switches (Mon–Sun).
  3. A summary line confirms your selection, for example "Active on weekdays (Mon–Fri)".
  4. Click Save.

How it behaves. Leave the selection empty and the promotion is active on every day. Otherwise DRE evaluates the promotion only on the selected weekdays — the pre-filter excludes it on all other days.


2.4 Campaign management​

Last updated: 2026-06-11

Campaigns bundle multiple promotions under a common theme — for example, all promotions for the grill season or a Black Friday event. This gives you a single place to control dates, maintain an overview, and shift promotions together.

When do I need a campaign?

  • You have 10 or more promotions for the same event and want their periods kept in sync.
  • You want to see in the promotions calendar which promotions belong to one theme.
  • You plan to shift the campaign period later — and all linked promotions should move automatically.

Example: "Grill Season 2026" — 5 promotions, 4-week run. You create a campaign and link all 5 promotions to it. If the weather stays cold for two weeks and you need to extend the campaign by one week, you just change the campaign end date.

Create a new campaign​

What you'll need: Admin role (campaigns can only be created by administrators).

  1. Open the Campaigns app from the Launchpad.
  2. Click Create in the top right.
  3. Fill in the required fields:
    • Name — a unique, descriptive name (for example, "Grill Season 2026").
    • Valid from / Valid to — the timeframe of the entire campaign.
  4. Click Save.

The campaign starts as a draft. You can now link promotions to it.

  1. Open an existing campaign (or the one you just created).
  2. Scroll to the Linked promotions section.
  3. Click Add and select the promotions you want from the list.
  4. Click Apply and then Save.

Tip: You can also link a promotion to a campaign directly from the promotion detail page — in the Campaign field in the General Information section on the promotion's detail page.

Shift campaign dates​

When the schedule of a campaign changes — for example because the event starts one week earlier — you can adjust the campaign dates. The platform asks whether all linked promotions should also be shifted.

  1. Open the campaign.
  2. Click Edit.
  3. Change Valid from and/or Valid to.
  4. Click Activate (finish the draft).
  5. A confirmation banner appears: "N linked Promotion(s) will be updated to the new date range. Continue?"
  6. Click Activate & Update Promotions.

After confirmation, all linked promotions automatically receive the new dates. You see the updated entries in the promotions calendar immediately.

Important: If you click Cancel, all promotions remain unchanged. The campaign dates are not saved either.

Common questions about campaigns​

Can a promotion belong to multiple campaigns? No — a promotion belongs to exactly one campaign, or to none.

What happens to promotions I edited manually? The platform shifts all linked promotions, regardless of whether you edited them manually. If you want to exclude a specific promotion from the campaign date shift, unlink it from the campaign before activating.

Can I see the campaign in the calendar? Yes — open the Promotions calendar and switch the colour coding to "By campaign". Promotions in the same campaign are grouped under their campaign header. See also section Promotions calendar.

Locking a campaign​

When all promotions in a campaign have been communicated externally — for example on printed flyers, in promotional emails, or in an external data feed — you can lock the campaign. The lock freezes all authoring changes so the system state cannot drift from what was communicated to customers. Runtime evaluation at the POS is unaffected: a locked promotion continues to apply its discount normally.

Why lock? You prevent accidental edits to promotions that have already been printed or published.

Who can lock? Administrators and Promotion Managers can lock a campaign.

How to lock a campaign​
  1. Open the campaign in the Campaigns app from the Launchpad.
  2. Click the Lock button (🔒) in the toolbar.
  3. The campaign is now locked. All editable fields are greyed out and the 🔒 status badge appears in the header.
How to unlock a campaign​
  1. Open the locked campaign (the 🔒 badge is visible in the header).
  2. Click the Unlock button in the toolbar.
  3. Confirm the action in the confirmation dialog.
  4. The campaign is unlocked. All fields can be edited again.

Who can unlock? Only the campaign creator (the user who created the campaign) or an Administrator can unlock a campaign. Being registered as the campaign owner does not grant unlock rights. Promotion Managers who are not the campaign creator cannot unlock it.

What is frozen — what stays allowed?​
ActionStatus
Edit campaign fields (name, dates, description)Locked
Add or remove promotionsLocked
Shift campaign datesLocked
Edit promotion fieldsLocked
Run promotion actions (Activate, Approve, etc.)Locked
Read and navigate the campaignAllowed
Clone to newAllowed
ICS calendar exportAllowed
Edit budgetsAllowed
Unlock the campaign (creator or admin)Allowed

Note: Budget authoring remains allowed even for locked campaigns. You can continue to record invoices and approve costs.

The 🔒 marker in the Promotions list​

In the Promotions list (Fiori Launchpad → Promotions), a 🔒 icon in the Locked column indicates that this promotion belongs to a locked campaign. The promotion itself cannot be edited while its campaign is locked. To make changes to such a promotion, unlock the campaign first.

Error messages​

If you attempt to edit a promotion or a campaign that is locked, the DRE shows an error message indicating that the campaign is locked and must be unlocked first. This restriction applies to all write operations via the Admin Service and via the API.


2.5 Promotions calendar​

Last updated: 2026-05-28

The Promotions calendar shows all promotions and campaigns on a timeline. It is the right tool for an overview: which promotions run when? Do two promotions overlap? Are there gaps in the promotions plan?

When do I use the calendar?

  • Weekly planning: I see at a glance what is active this week and next week.
  • Campaign planning: I see how campaigns are distributed on the timeline.
  • Conflict check: I immediately notice when two promotions with the same items would be active at the same time.

Open the calendar view​

  1. Click Promotions Calendar in the Launchpad.
  2. The calendar opens in month view. Switch to the desired view using the Week / Month buttons.
  3. Use the Back / Forward arrows to navigate through time.

See campaigns as a group​

Promotions belonging to the same campaign are grouped under the campaign in the calendar. The campaign row shows the total period; the individual promotions appear below it.

Switch colour coding​

Use the toggle in the toolbar:

  • By status (default): Active promotions in green, drafts in grey, expired light grey, rejected in red.
  • By campaign: Promotions are grouped by campaign (plus a group Without campaign). Each campaign group has a header row; the colours of individual promotions correspond to their status (active = green, draft = grey, etc.), not the campaign.
  • By stakeholder: Useful for quickly seeing who funds which promotions.

Filter the calendar​

The filter button at the top of the toolbar lets you filter the calendar by article groups, POS groups, and stakeholders. Click the search icon (⧉) next to a filter field to open a search dialog:

Filter by article group:

  1. Click the search icon next to the Article group field.
  2. The dialog opens. Enter an article group to search the list.
  3. Select one or more article groups by clicking them.
  4. Click OK. The calendar shows only promotions that contain these article groups.

The same applies to POS group and Stakeholder — filter by the groups or departments that interest you. The selected filters are retained when you reload the page or save the view and open it later.

Combine multiple filters: When you have set several filters (for example, article group AND POS group), the calendar shows only promotions that meet both conditions.

Saved calendar views​

If you use certain filters frequently (for example, "drinks promotions only" or "promotions from my department only"), you can save that view:

  1. Set the desired filters in the filter button.
  2. Click Save view and give the view a name.
  3. The saved view appears in the My views dropdown from then on.

Open a calendar event​

Click a bar in the calendar to jump directly to the detail page of the promotion or campaign.

Note on drag and drop​

Moving promotions directly by drag and drop is planned but not yet available. To change dates, open the promotion via the calendar and edit Valid from / Valid to on the detail page. To shift an entire campaign together with all its linked promotions, see section Campaign management.


Phase 3 — Approval and pilot​

3.1 Approval process​

The approval process controls promotion activation through a reviewer decision. Authors create promotions as DRAFT, submit them for approval, and reviewers (with the role PromotionApprover) approve or reject them. The audit trail in PromotionApprovals is append-only — every decision is retained.

Lifecycle states​

   DRAFT → Submit for approval → Pending Approval (PENDING_APPROVAL)
│
├─ Approve → ACTIVE (validFrom ≤ today)
├─ Approve → APPROVED (validFrom > today; scheduler activates on validFrom)
└─ Reject → REJECTED

REJECTED is a terminal state for the calculation engine — the pre-filter never passes it through. Authors can revise a rejected promotion using the action Resubmit for approval (REJECTED → DRAFT), so the author can edit and resubmit the promotion without recreating the record. The immutable PromotionApprovals audit trail retains both the original rejection and the subsequent resubmission.

Author flow​

  1. Create a promotion as DRAFT.
  2. Click Submit for approval on the list or detail page.
  3. Optionally add a free-text comment for the reviewer.
  4. The status changes to Pending Approval (internal PENDING_APPROVAL). The author can no longer edit target fields until the reviewer responds.

Reviewer flow​

  1. Receive the email notification. The deep link opens the object page of the promotion in question. To review several pending promotions at once, use the saved list view "Pending My Approval" in the Promotions list.
  2. The status column is colour-coded (orange for pending, green for approved, red for rejected).
  3. Click Approve or Reject. Approval immediately switches to ACTIVE if validFrom is already in the past; otherwise it lands in APPROVED and the existing scheduler activates it on validFrom.

Tenant configuration: enforce approval​

The DRFOUT tenant config flag requireApprovalBeforeActive (default false) controls the old DRAFT → ACTIVE direct path. Set it to true to force every promotion through the approval workflow before it can become ACTIVE.

Email notifications​

  • In development mode, no email is sent (logged only).
  • For production, your IT team configures the recipient list.
  • Repeated submissions within 5 minutes (same promotion, same recipient) are consolidated.

Role without admin rights​

The PromotionApprover role requires no admin or PromotionManager permissions. A standalone approval role is sufficient to use the entire approval workflow.

Approvals tile​

Users with the PromotionApprover role find the Approvals tile on the Launchpad home screen (icon: task icon). Clicking it opens the promotion list, automatically pre-filtered to promotions with status PENDING_APPROVAL.

The approver sees only the pending promotions — this is the list's default state. You can clear this filter at any time if you want to browse all promotions.

Pending-only visibility​

The approval inbox shows only promotions with status Pending Approval. Approved or rejected promotions leave the inbox automatically — they are no longer visible to the approver.

Active and draft promotions — default list view​

The promotions list (Launchpad → Promotions) displays active promotions by default. In-progress drafts (including abandoned, unnamed drafts) are hidden from this view. To see drafts, activate the Editing Status filter and select Draft. This toggles drafts in and out of the list.

Step-by-step flow (approver)​

  1. Open Launchpad → click Approvals tile.
  2. Select a promotion from the list.
  3. Review the promotion, then click Approve or Reject.
  4. The promotion leaves the inbox; the approval log is automatically updated.

Common questions about the approval process​

Can an author approve their own promotion? No. Self-approval is blocked server-side: the user who created a promotion cannot approve or reject it, regardless of their roles.

What happens when the reviewer is away? The promotion stays in Pending Approval (internal PENDING_APPROVAL) until someone with the PromotionApprover role decides. Ask your IT team to configure a substitute role for leave periods.


3.2 Pilot mode​

Pilot mode lets you launch a promotion to a limited set of POS groups, measure the uplift against a control group, and either automatically promote it or return it for revision.

Example: You want to test a new tobacco formula with "15% off tobacco in selected stores" — in 10% of stores, while 90% serve as the control group.

Lifecycle states​

   DRAFT → Start pilot → PILOT (within the pilot window)
│
├─ Promote to Active → ACTIVE (manual)
├─ End pilot → DRAFT (manual review)
├─ Auto-promote ≥ threshold → ACTIVE (automatic)
└─ Auto-promote < threshold → DRAFT (automatic)

Set up a pilot​

The pilot is configured in its own app — there is no pilot section or pilot link facet on the promotion's object page.

  1. Create the promotion as DRAFT and save it.
  2. Open Promotions → Pilot Configuration in the launchpad. Create a new pilot configuration and link it to your promotion with the Promotion field. The configuration has its own sections:
    • Pilot Window — the Pilot Start / Pilot End dates during which the pre-filter restricts targeting to the pilot POS groups.
    • Pilot POS Groups — stores participating in the pilot arm (own facet).
    • Control POS Groups — stores staying on the baseline, no pilot promotion (own facet).
    • Auto Promote — when switched on, the auto-promote job changes PILOT to ACTIVE if the measured uplift ≥ threshold; otherwise to DRAFT.
    • Auto Promote Threshold (%) — required minimum uplift.
  3. Save the configuration. Validation rejects:
    • Pilot group ∩ control group overlap (no store may be in both arms).
    • End equal to or before start.
    • Threshold ≤ 0 or > 100 (valid range: greater than 0 up to 100 %).
  4. Open the promotion and click Start pilot to switch it from DRAFT to PILOT. Start pilot is an action on the promotion and requires a saved pilot configuration.

Note on statistical significance​

Aim for at least 20 stores per pilot arm — smaller arms cannot reliably distinguish a 5% uplift from random variation. This is advisory guidance and is not enforced during setup: you can start the pilot regardless. The sample-size warning does not appear during setup; it is raised in the pilot comparison report (section 3.3) when an arm has fewer than 20 stores.

Auto-promote job​

A 5-minute background process checks all pilot configurations whose window has ended:

  • autoPromote = off → switches to DRAFT for manual review.
  • autoPromote = on and uplift ≥ threshold → switches to ACTIVE.
  • autoPromote = on and uplift < threshold → switches to DRAFT.

Note — automatic promotion to ACTIVE is not yet live. The uplift telemetry that the job compares against the threshold is not yet wired up, so the job currently returns every ended pilot to DRAFT for manual review — it does not promote to ACTIVE on its own. Use the manual Promote to Active action to activate a successful pilot.


3.3 Pilot evaluation​

After a pilot completes, you can compare the pilot arm and the control arm directly.

Open the pilot comparison page​

  1. Open Reports & Analytics → Pilot comparison in the Launchpad.
  2. Select the pilot configuration from the list.
  3. The detail page shows four charts:
    • Revenue: pilot vs. control — net revenue over the pilot window.
    • Basket size: pilot vs. control — weighted average basket value.
    • Transactions: pilot vs. control — total and promotion transaction counts.
    • Statistical Confidence (p-value) — p-value badge + winner status.

Available metrics​

MetricMeaning
Pilot / control storesNumber of POS groups in each arm
Sample size warningVisible when an arm has fewer than 20 stores
Pilot / control transactionsConfirmed transactions over the pilot window
Revenue uplift(pilot revenue − control revenue) / control revenue
WinnerPilot / Control / Inconclusive (backend codes PILOT / CONTROL / INCONCLUSIVE)

Best practices​

  • At least 20 stores per arm for meaningful chi-squared tests.
  • At least 14 days window length so daily aggregations balance weekday and holiday effects.
  • Similar traffic profiles between arms (similar revenue, similar product mix).
  • Auto-promote threshold should reflect the minimum business uplift, not the statistical threshold.

Phase 4 — Execution​

4.1 Simulator​

The simulation app (accessible from the Fiori Launchpad under Tools > Simulator) lets you create test baskets and run them through the promotion engine without side effects.

The direct URL for the simulator tile is: http://localhost:4004/launchpad.html#Simulation-display

Important — page reload. If you reload the browser page in the Fiori Launchpad, the shell returns to the Launchpad home page. Use the Tools > Simulator tile or the breadcrumb navigation to return to the simulator — do not rely on the browser reload button.

Line reference input​

Each basket row in the simulator contains a Line reference column with a text input. The placeholder text reads "Auto".

  • Leave empty for normal testing. The server automatically assigns "1", "2", "3", and so on.
  • Fill in when you are testing split-always scenarios — for example, when you add the same item on two rows and want to check which row receives the discount. Enter a unique string per row (for example, "10", "20").

The simulation response panel shows the lineReference on each result entry so you can visually confirm the mapping.


Missed promotions​

When you run a simulation, the response panel includes a Missed promotions block that lists every promotion that was considered but not triggered. The block is hidden when every active promotion was applied — its presence means something matched the basket but was rejected.

Each entry is grouped by the pipeline phase that rejected it:

Phase labelWhat it meansExample
Pre-filterFiltered out before any condition check — because the promotion is outside its validity window, not active for this POS group, blocked by weekday or happy-hour rules, or simply inactive."Summer Sale" expired three days ago.
Coupon requiredThe promotion is coupon-triggered but the basket has no matching coupon."VIP Loyalty Boost" requires code VIP-2026.
Conditions failedPassed pre-filter but the condition tree did not evaluate to true. The popover shows which condition node failed and what value was expected versus observed."10% off drinks" requires receipt total ≥ €50; basket total is €32.
Blocked by priorityConditions matched but a higher-priority promotion claimed the same items first."Stacked discount" lost to the higher-priority "Top Priority Bundle".
Budget limitedConditions and priority passed but the promotion's budget is exhausted or would exceed the per-customer limit. The popover shows used / required / remaining and the limiting reason."Black Friday Bundle" budget is at 500 / 500 — exhausted.
Invalid couponsA coupon code in the basket failed validation (expired, already redeemed, not yet active, wrong customer, etc.). The popover shows the code and the validation error.Coupon SAVE10 is EXPIRED.

Click the info icon on a row to open the drill-down popover for that rejection. If a promotion was rejected without any recordable detail, the popover shows "No further details".

Simulator only. This panel is rendered exclusively in the simulator user interface. Live POS terminals do not show missed promotion data.


Import Request from the Calculation Log​

You can import a test basket from a real point-of-sale request to debug a promotion against live transaction data. This is helpful when a customer reports behavior in-store and you want to reproduce it without manually re-entering cashier data.

The Simulator app provides an Import Request button at the top of the basket panel. Click it to select a JSON file.

Step-by-step:

  1. Click the Import Request button.
  2. Select a JSON file that you exported from the Calculation Log display.
  3. (Optional) Enable the Set timestamp to now checkbox to run the simulation with the current date and time instead of the original timestamp from the file.
  4. Click Import to load the basket.

File format. The file must be a JSON request exported from the Calculation Log display. The system rejects response files.

Basket will be overwritten. Import replaces all current basket items. Save your test scenarios locally before importing new requests if you are working through multiple scenarios.

Data protection note. The Calculation Log imports customer ID and customer group with their real values — these fields are not masked and can be used directly to test customer-based conditions (for example, a discount for VIP customers only). Fields such as the loyalty card number, payment card details, and personal contact data (name, email, phone, IBAN) may appear as ***REDACTED*** if they were present in the stored request. Loyalty tier and loyalty points are not masked — these fields are also available directly from the file.


4.2 Baskets with returns​

Last updated: 2026-06-03

The promotion engine now accepts mixed baskets. A mixed basket contains both sale lines (positive quantities) and return lines (negative quantities) in a single transaction.

How returns work​

When your POS sends a return line to DRE (recognisable by a negative quantity), the promotion engine performs the following steps:

  1. Return lines are not evaluated. The promotion engine checks its conditions and calculates discounts only on sale lines (positive quantities). Return lines are echoed back in the response without being evaluated or discounted.

  2. Return lines do not feed into budgets, coupons, or loyalty. Returns do not cause budget consumption, do not reduce coupon availability, and do not earn loyalty points. Only sale lines affect these entities.

  3. The return stays in the status quo. The line is returned unchanged with the original amount / quantity. No discounts and no surcharges are applied.

Responsibility between the POS and DRE​

The correctness of the return price lies with your POS — the promotion engine returns the supplied price unchanged.

That means:

  • Your POS checks whether an item is returnable, whether the return window is still open, and which price should be refunded (original price, average price, current market price).
  • The promotion engine accepts the price you send and passes it through unchanged.

This split ensures that returns do not violate your business logic — the DRE platform does not need to interfere with return policies.

Safety limits​

The promotion engine checks return baskets for plausibility:

  • Quantities of exactly 0 are invalid and are rejected.
  • Baskets whose return quantities greatly exceed the sales (more than twice the sale volume) are rejected.
  • Baskets whose total falls below a minimum value are rejected.

These limits prevent abuse (for example, returning items that were never sold) and protect the integrity of your financial reports.

Testing in the simulator​

The simulator accepts negative quantities directly. Enter a positive quantity per basket line for a sale, or a negative quantity for a return. This lets you test mixed baskets (sale plus return) in a single simulation, without calling the POS API.

A quantity of zero is rejected — the simulator shows a warning dialog stating the quantity must be non-zero (positive for sales, negative for returns).

The result view reports returns separately: a Return subtotal line shows the total value of the return lines. Discounts apply only to the sale lines; return lines stay unchanged.


4.3 POS features​

Last updated: 2026-05-28

DRE includes five POS features at the point of sale — features at the checkout that improve the customer experience at the point of sale and increase the conversion rate of your promotions. All five are active in the production version and work automatically in the background.

Threshold gap​

What it does: The platform calculates how close a basket is to a promotion that has not yet triggered. When a shopper needs, for example, 2 more bottles of wine to reach a "buy 3, get 1 free" promotion, DRE detects this gap.

When it runs: On every checkout simulation — automatically, with no configuration.

What the shopper sees: The POS display or a receipt display can show the gap hints (for example, "Just €3.00 more to reach the next discount!"). Display depends on the POS integration.

Typical benefit: Upsell — shoppers buy one or two more items to reach the discount.


Near-miss recommendations​

What it does: When a shopper narrowly missed a promotion (for example, the basket was at 85% of the requirement), the platform can issue a recommendation: "Almost! Add 1 more item from the Wines category for 20% off."

When it runs: After every checkout, when near-miss analysis is enabled for your tenant (disabled by default for privacy reasons).

What the shopper sees: A recommendation on the POS display or on the receipt — configurable depending on the POS system.

How to enable: An administrator enables near-miss in the Tenant analytics app. Two separate flags govern it (both off by default): Enable Near-Miss Analytics turns on telemetry capture, and Enable Production Near-Miss turns on the live recommendations at the POS. Without enabling them, no near-miss data is collected. See section 5.3 Tenant analytics.

Privacy: Near-miss recommendations contain no customer number and no personal data. Only the basket contents are evaluated.


Savings summary​

What it does: At the end of a checkout, DRE summarises all discounts earned into a single figure: "You saved €4.50 today."

When it runs: Whenever at least one promotion was applied.

What the shopper sees: The total saving appears on the receipt and can be shown on the POS display (depending on the POS integration).

Savings breakdown with voucher details: When a "voucher promotion" (for example, "Spend €50, get a €10 voucher") is active, the voucher discount now appears in the breakdown of the discounts granted — as a standalone line with an amount. Example: the receipt shows a standalone voucher line with an amount (for example "−€10.00") next to other discount lines — the exact line label depends on your POS integration. This makes the total transparent: all listed discounts plus the final amount add up.

Typical benefit: Higher customer satisfaction — customers see exactly which promotions they received and how much they save.


Progressive nudges​

What it does: DRE classifies each recommendation by its nudge type — what kind of promotion the shopper is close to, not the phase of the checkout:

  • Spend threshold — a hint that the basket is close to a spend-based promotion (for example, "Spend €50 to unlock the discount").
  • Multi-buy — a hint that the customer is close to a multi-buy promotion (for example, "Add 1 more to get the third free").
  • Tiered discount — a hint that the customer is close to the next tier of a tiered-discount promotion (for example, "2 more units for the next price tier").

When it runs: On every checkout, when progressive nudges are enabled (enabled by default).

What the shopper sees: The POS system can display the hints in stages on the screen — the hint changes as the basket grows.

Enable / disable: In the Tenant analytics app, via the Enable Production Nudges flag. Can be disabled if the hints are not wanted in your operation.


A/B testing​

What it does: DRE can activate a promotion for selected stores only (test group) and compare the results with stores without the promotion (control group). This lets you measure reliably whether a new promotion actually drives more revenue.

When it runs: Whenever a promotion is marked as an "experiment" and control and test stores are assigned.

What the operator sees: In the Pilot Comparison report you see conversion rate, revenue, and statistical significance value (p-value) for both groups, with the winning test arm labelled Pilot, Control, or Inconclusive. In the Post-Mortem Dashboard (its A/B Confidence Panel) you see the same metrics for the completed campaign, with the winner labelled Experiment, Control, or Inconclusive.

Typical benefit: Evidence-based decisions instead of gut feeling — you know before a full rollout whether the promotion works.


All five features in the ROI dashboard​

The Promotion Impact ROI Dashboard (Launchpad → Reports & Analytics → Promotion Impact ROI) brings together the metrics from all five features in one view. You see how often each feature triggered and how often a purchase decision followed.


Phase 5 — Analysis​

5.1 Promotion Impact ROI Dashboard​

The Promotion Impact ROI Fiori dashboard shows production telemetry for the 5 POS features at the checkout:

FeatureChartWhat it shows
Threshold gapBar (emissions vs. conversions)How often response.thresholdGaps[] was emitted and how often a discount followed
Near-missLine (emissions + avg shortfall)Emission count + average shortfall amount
Savings summaryBar (funnel)Impressions of response.totals.savingsSummary and follow-on conversions
Progressive nudgesLine by phaseEngagement curve per recommendation phase (Spend threshold / Multi-buy / Tiered discount)
A/B testExperiment tablePer experiment: promotion, control Ø basket, experiment Ø basket, uplift %, sample size per arm, significance traffic light

Understanding the metrics: emissions, conversions, and threshold-gap conversion​

All charts on this dashboard work with two base figures: emissions and conversions. This section explains both and uses the threshold-gap conversion to show how to read the numbers.

Emission. An emission is a completed checkout in which DRE surfaced the relevant feature. For threshold-gap conversion this means: the basket was close to a promotion that had not yet triggered. "Close" means the customer had reached at least 80% of the condition — for example €80 of a €100 minimum spend. The 80% is the default proximity threshold. In this case DRE sent a hint to the POS. Each checkout counts at most one emission, even if the customer narrowly missed several promotions.

Conversion. A conversion is an emission where the same checkout also produced a discount — the receipt's total discount was greater than 0. Important: the conversion measures a relationship within the same transaction. It does not measure whether a customer returns later and deliberately closes the gap. The discount may even come from a different promotion. The conversion is therefore a soft KPI: it shows that a near-miss customer benefited in the end. It does not prove cause and effect.

Conversion rate. The conversion rate is the share of emissions that became a conversion: conversions divided by emissions. A rate of 50% means half of the near-miss checkouts still received a discount on the same receipt.

The "Threshold-Gap Conversions" chart. For each day the chart places two bars side by side: the emissions (how often DRE detected a threshold gap) and the conversions (how many of those checkouts still produced a discount on the same receipt).

Example: On 2026-06-06 the chart shows 8 emissions and 4 conversions. On that day DRE detected 8 customers who narrowly missed a promotion; 4 of them still received a discount in the same transaction. The conversion rate is 4 divided by 8, i.e. 50%.

In addition, the dashboard shows the average gap (avgGapClosed): how much the near-miss customers were short on average. A small average gap combined with a low conversion rate is an especially clear signal — a small adjustment is often enough to make more customers trigger the promotion.

What is the metric for? It helps you find promotions whose trigger threshold is set too high. Many emissions with a low conversion rate mean: many customers come close but do not trigger the promotion. Then check two levers — lower the promotion's condition (for example the minimum receipt value), or surface a clearer hint at the POS (see section 4.3 POS features).

Three kinds of gaps. DRE distinguishes why a promotion was narrowly missed:

Gap typeMeaningExample POS hint
Amount gap (RECEIPT_AMOUNT)Revenue is missing up to a minimum receipt value."€5 more to unlock the discount."
Quantity gap (ITEM_QUANTITY)Units are missing up to a minimum quantity."1 more item for the offer."
Tier gap (SCALED_RECEIPT)Revenue is missing up to the next discount tier."€20 more for 15% instead of 10%."

Note on the other charts. Emissions and conversions apply to all five charts, with one exception: the Near-Miss Conversions chart currently shows emissions only. No separate conversion count is calculated there, because a near-miss carries no discount value of its own per transaction; the conversion column therefore stays at 0. The proximity threshold for near-miss is also a separate value (default 30%), which you set in Tenant Analytics (see section 5.3 Tenant analytics).

Per-promotion drill-down: which promotions drive this number?​

Each ROI panel answers not only "how many emissions and conversions were there today?" but also "which promotions are behind that number?" Click a day point on the Threshold gap or Savings summary chart to open a popover listing the top promotions for that day.

Threshold-gap drill-down. The popover is a list; each promotion appears as a list item (name, a context line "Threshold X · avg gap Y" and a "conversion % · n=…" line) with these data points:

ColumnMeaning
Promotion nameThe name of the promotion, for example "Summer wine discount".
Conversion %Share of this promotion's emissions that led to a discount on the same receipt.
Volume (n)Sample size — how many transactions fed this figure. A high rate on a low n is not reliable.
Spend thresholdThe configured minimum spend for this promotion (for example €50).
Average gapHow far customers were from the threshold on average (for example −€8.20).

Savings drill-down. The popover is a list; each promotion appears as a list item (name, a context line "Total savings X · avg Y" and a "conversion % · n=…" line) with these data points:

ColumnMeaning
Promotion nameName of the promotion.
Conversion %Share of transactions in which this promotion issued a saving amount.
Volume (n)Sample size.
Total savingsSum of all discounts granted by this promotion on the selected day.
Average savingDiscount per triggering transaction.

Example: Anna selects 10 June on the Threshold-gap chart. The popover shows: "Summer wine discount — 42% conversion, n=24, threshold €50, gap −€6.80." This means 24 customers came within €6.80 of the threshold, but only 42% bought an additional item. Lowering the threshold to €45 would likely produce more completions.

The Near-Miss panel already uses the same drill-down mechanism (click a day point → top promotions).

A/B test results: experiments at a glance​

The A/B panel shows a table of all running and completed experiments — not a single averaged uplift bar. You see at a glance which experiment is performing and which is not.

What the table shows. Each row is one experiment and contains:

ColumnMeaning
Promotion nameThe promotion running as an experiment.
Control Ø basketAverage receipt value in the control stores (without the promotion).
Experiment Ø basketAverage receipt value in the test stores (with the promotion).
Uplift %Percentage difference between the experiment and control average basket. A positive value means test-store customers spent more on average.
n control / n experimentSample size per arm. Always check n — an uplift of 30% at n=8 is noise; at n=800 it is a signal.
SignificanceTraffic-light symbol based on a statistical test (Welch two-sample t-test on basket totals, 95% confidence).

How to read the significance indicator: The indicator has two states (there is no middle "borderline" state):

  • Green — significant (95%) — The difference between experiment and control is not attributable to chance with 95% confidence. You can make a decision based on this result.
  • Amber — not significant — The difference has not reached 95% confidence; it could be noise, especially with small samples. Do not make a rollout decision on this basis — collect more data first.

Example: The experiment "GRILL26 Summer" shows control Ø basket €42.30, experiment Ø basket €49.80, uplift +17.7%, n control=312, n experiment=308, green ("significant (95%)"). This is a reliable result. "Cosmetics campaign week" shows +22% uplift, but n=11 per arm and an amber ("not significant") indicator — more data is needed before any decision.

Day-by-day breakdown. Click a row to open the daily view: control and experiment average basket as two lines over time, cumulative sample size, and significance per day. This lets you see whether the uplift was consistent or concentrated on individual days.

"Roll out winner". At the bottom of the day-by-day view, the "Roll out winner" button is shown for every experiment (it is not gated by significance — always check the significance indicator yourself before acting). Clicking it does not change the promotion's status: it opens the Promotions application, where you transfer the winning variant into regular operation.

Recommendation phase labels. In the Progressive nudges chart and in drill-down popovers, phases are now shown as plain business terms instead of internal codes:

LabelMeaning
Spend thresholdThe customer still needs a minimum spend amount to trigger the promotion.
Multi-buyThe customer still needs a certain number of units.
Tiered discountThe customer is just below the next discount tier.

Empty state on first open​

The first time a tenant opens Promotion Impact ROI, each chart shows "No data" — this is expected. The dashboard answers three questions:

  1. What feeds this chart? Each panel has a contextual empty-state message that names the underlying feature.
  2. When will the data update? A top banner says "Data is updated daily at 02:00 UTC. Last run: {timestamp}, {n} rows processed."
  3. Do my simulator runs count? Only if you confirm them. The banner explains: "Source: confirmed POS transactions — including transactions you confirm in the simulator; preview-only calls (without confirmation) are not counted."

Load demo data: For demonstrations or training, you can seed synthetic data into the database to see the charts populated immediately. To do so, run:

npm run seed:kfroi-demo

The script loads 6 days of demo telemetry (threshold gaps, near-miss, savings, recommendations, and A/B tests) and runs the aggregation jobs automatically. After a few seconds, all five charts show realistic charts with sample data. For more information, see section 7.3 Set up a demo environment.

Tenant feature flags​

Two of the five charts require your explicit activation:

ChartRequired flagDefaultWhere to toggle
Near-miss conversionsEnable Near-Miss AnalyticsOFF (GDPR-safe)Tenant analytics → detail page
Progressive nudgesEnable Production NudgesON for new tenantsTenant analytics → detail page

When a flag is OFF, the chart's empty state changes to "Near-Miss Analytics is disabled for this tenant. Click here to enable it on the Tenant Analytics page."

Enable near-miss analytics (opt-in)​

Near-miss analytics are off by default (GDPR safety). No near-miss rows are written until you switch on Enable near-miss analytics on the tenant's TenantAnalyticsConfig record. This is intentional.

The dashboard renders a guided activation panel on the near-miss conversion card when the flag is OFF:

  1. A short help text explains what near-miss analytics record.
  2. A primary button "Enable near-miss analytics for this tenant" that activates the flag without leaving the dashboard.
  3. A secondary link "Open tenant analytics settings" for operators who want to review related flags.

Troubleshooting checklist​

  1. Banner shows "… No updates recorded yet" → The cron has not triggered yet (default 02:00 UTC). Wait, or use the "Run now" button at the top of the dashboard.
  2. Banner has a ranAt value but processedRows is 0 → No confirmed POS transactions on that day (preview-only simulator calls without confirmation do not count). Check the calculation logs.
  3. A chart shows a disabled hint (for example "Near-Miss Analytics is disabled for this tenant") → Toggle the flag on the Tenant analytics detail page.
  4. Banner shows status PARTIAL → Check the aggregator job logs for tenant-specific errors.

Aggregator Runs — analytics background job​

The aggregator is a nightly background job that summarizes the previous day's telemetry and feeds data to the KPI dashboards (ROI, killer features). The Aggregator Runs tile shows when (and whether) this job actually ran and how much data it processed.

When do you need it? When an ROI dashboard looks empty and you need to distinguish: "The job is broken" vs. "The job ran fine, but there was no activity yesterday."

Accessing aggregator runs​
  1. Open the launchpad.
  2. Go to the Administration group.
  3. Click Aggregator Runs (refresh icon, subtitle "KFROI background job history").

A list report shows all job invocations; click a row for details.

What the report shows​
ColumnMeaning
Run IDUnique technical ID of the job invocation.
Ran AtCompletion timestamp of the job (UTC).
Aggregated DateThe UTC date that was summarized (typically: previous day D-1).
StatusSUCCESS, PARTIAL, NO_DATA, or FAILED.
Tenants ProcessedNumber of tenants that had data.
Processed RowsTotal count of telemetry rows written.
Duration (ms)How long the job took to run.
Error MessageFor FAILED or PARTIAL: error message.
Status meanings​
  • SUCCESS — At least one row processed, no errors.
  • PARTIAL — Completed, but at least one tenant had an error.
  • NO_DATA — No active tenants with data — nothing to aggregate (not a failure, expected).
  • FAILED — The job crashed; error shown in the Error column.
Important notes​
  • Read-only — the log is a diagnostic view; you cannot edit entries.
  • Nightly cron job — runs daily at a configured UTC hour (default 02:00 UTC). The refresh button does NOT re-run the job — it is display-only.
  • For operations staff (Boris persona) — this view is for ops and platform admins, not retail planners.
  • Empty ROI dashboards: If a dashboard looks empty, check for a recent NO_DATA entry — it usually means "we had no transactions yesterday", not a bug.

5.2 Post-Mortem Dashboard​

When a promotion ends, planners see a curated KPI page comparing its performance against a pre-period baseline. The PromotionPerformance detail page shows the Promotion Insights section (KPI tiles) plus five further visualisation sections and a conditional A/B confidence panel (shown only for experiments) — each as its own section (not nested):

  1. KPI tiles — redemptions, total discount granted, average basket delta, active days. (Confirmed transactions only — simulator runs are excluded.)
  2. Uplift comparison — line chart of average daily revenue during the promotion compared to a 30-day baseline window before the promotion. Two toggles:
    • Same weekday only — restricts the baseline to weekdays matching the promotion window.
    • Exclude days with other promotions (strict mode) — excludes baseline days on which another promotion was also active (default ON).
  3. Top 10 stores — horizontal bar chart, ranked by discount total. Shows confirmed transactions only. Click a bar to go to filtered calculation logs.
  4. Top 10 items — same format, ranked by item discounts (confirmed transactions only).
  5. Hour-of-day heatmap — 24×7 grid. Cell colour corresponds to the number of applications (confirmed transactions only). (Simulator runs are not counted.)
  6. A/B confidence panel — hidden by default. Visible only when the promotion was marked as an experiment (isExperiment=true). Shows control vs. experiment transaction counts, conversion rates, revenue, average basket, p-value, and a winner badge.

Best practices​

  • Open the dashboard at the earliest one day after the promotion ends — the nightly aggregation must run first.
  • Use the "Exclude days with other promotions" toggle (strict mode) when your promotion ran in parallel with other promotions, to avoid baseline distortion.
  • The A/B confidence panel is particularly valuable for pilot decisions — it shows a statistical p-value, not just raw revenue figures.

5.3 Tenant analytics​

Last updated: 2026-05-28

As a tenant manager or system administrator, you use this page to configure the analytics behaviour for your entire tenant account. It is a settings page, not a metrics dashboard: it controls which analytics features are captured, the near-miss proximity threshold, and the time zone for daily evaluations. The actual metrics and charts live on the 5.1 Promotion Impact ROI Dashboard and the 5.2 Post-Mortem Dashboard.

When do I need this page?

  • You want to enable or disable privacy-sensitive analytics features (for example, near-miss tracking).
  • You want to configure the near-miss threshold (at what percentage of basket proximity a "near-miss" hint appears).
  • You want to set the time zone in which daily and hourly evaluations are calculated.

Configure thresholds​

  1. Open Tenant analytics from the Launchpad.
  2. Click Edit.
  3. Adjust the desired thresholds:
    • Near-Miss Shortfall (%) — how close must a basket be to a promotion for a hint to appear? Default: 30%. Range: 5–100%.
    • Time zone — set the time zone in which daily and hourly evaluations are calculated (for example, "Europe/Berlin"). Default: UTC.
  4. Click Save.

Caution: Changing the time zone affects the display of all historical daily values. Existing aggregates are not recalculated — only new data is captured with the new time zone.

Privacy settings (GDPR)​

Some analytics features require your explicit activation because they collect additional data:

Field (toggle)DefaultDescription
Enable Near-Miss AnalyticsOffRecords detailed data about which promotions customers narrowly missed. Enable this only after your data protection officer has approved it.
Enable Production Near-MissOffShows near-miss hints on the POS display. Requires Near-Miss Analytics to be enabled.
Enable Production NudgesOnShows staged hints ("Just €X more to reach the discount") at the POS. Can be disabled if the hints are not wanted.

To enable or disable a feature:

  1. Open the Tenant analytics tile from the Launchpad.
  2. Click Edit.
  3. Navigate to the Production Features tab (Teleportation) or Telemetry (Track 2) tab (Near-Miss + Threshold).
  4. Toggle the desired switch.
  5. Click Save.

Changes take effect within ~1 minute (process cache) — no server restart required.

Common questions about tenant analytics​

Why does the dashboard show "No data"? Analytics are based on confirmed checkouts. Simulations are not counted. If you have just set up the platform or have only run test transactions, the charts will not populate until the next production checkout.

Can analytics data be deleted? Aggregated daily data is retained permanently (no automatic deletion). Raw data for near-miss events is automatically purged after 30 days.

5.4 Coupon analytics​

The Coupon Analytics report (Launchpad → Reports & Analytics → Coupon Analytics) shows per coupon type how many codes were issued, redeemed, expired, or cancelled. The redemption rate is calculated as redeemed codes divided by all issued codes.

Post-purchase metrics. For coupons that were issued at the POS terminal as a post-purchase coupon (issuance channel "POST_PURCHASE"), additional columns are available:

MetricMeaning
Post-Purchase IssuedNumber of codes issued via a post-purchase action.
Post-Purchase RedeemedNumber of those that were later redeemed.
Post-Purchase Rate (%)Redeemed divided by issued, in percent. If no code has been issued yet, the field remains empty.
Avg Days to RedeemAverage number of days between issuance and redemption. Useful for assessing the typical return timeframe.
Avg Redemption Basket TotalAverage basket value of checkouts where a post-purchase coupon was redeemed.

Post-purchase metrics on the coupon type overview. Click a coupon type in the table to open its overview (object page). You will find a Post-Purchase section showing the 5 key post-purchase metrics: issued, redeemed, redemption rate, average days to redemption, and average basket total. These metrics apply exclusively to codes issued via a post-purchase action. The overall columns in the table (Issued, Redeemed, Redemption Rate) continue to count all channels together.

Coupon comparison​

In the Coupon Analytics report, you can compare 2–4 post-purchase coupon types side by side to see which coupon mechanic brings customers back fastest, is redeemed most reliably, and generates the highest basket total.

How to use coupon comparison:

  1. Open the Coupon Analytics report (Launchpad → Reports & Analytics → Coupon Analytics).
  2. Select 2–4 post-purchase coupon types by checking the boxes to the left of the table. The Compare button is disabled when you select fewer than 2 types. When you select more than 4 types, a notice appears.
  3. Click Compare. The comparison view opens.

The comparison view has two zones: a bar chart at the top for a quick visual read, and the scorecard below it with the exact values.

The bar chart (upper zone):

At the top of the comparison view, a grouped bar chart shows the three primary metrics — Redemption Rate, Return Speed (Avg Days to Redeem), and Avg Basket Total. The bars are grouped by coupon type. Each group contains one bar per compared coupon type. This gives you the values at a glance.

How to read the bar length:

  • For Redemption Rate and Avg Basket Total: a longer bar means a higher and therefore better value.
  • For Return Speed: a shorter bar means a faster return. The chart does not invert the axis. The note "lower = better" appears next to this metric to make the direction explicit.

The chart shows only these three primary metrics. The context metrics (issued, redeemed) appear in the scorecard only, not in the chart. Avg Basket Total (€) is plotted on a separate right axis so that the Redemption Rate and Return Speed bars are not flattened by the larger € scale.

The comparison scorecard (lower zone):

The comparison table shows a side-by-side view with five metrics, one column per selected coupon type:

MetricMeaning
Redemption Rate (%)Percentage of issued codes that were redeemed.
Avg Days to RedeemAverage number of days between issuance and redemption — lower is better.
Avg Basket Total (€)Average basket value at redemption.
Post-Purchase IssuedNumber of codes issued via a post-purchase action.
Post-Purchase RedeemedNumber of redeemed codes.

Baseline and deltas: The first selected coupon type is marked as Baseline. All other columns show the difference to the baseline as both absolute values and percentages.

Best-in-class highlight: The best value per metric is visually highlighted, so you can quickly see which coupon type leads in each category.

Confidence signal (n=X): Each column header displays a traffic-light signal based on the number of codes issued:

  • Green — ≥ 100 codes: low statistical uncertainty, results are reliable.
  • Amber — 30–99 codes: moderate uncertainty, results should be interpreted with caution.
  • Red — < 30 codes: high statistical uncertainty, results are not yet conclusive.

Type-mismatch notice: If the comparison selection includes both individual coupons (INDIVIDUAL) and generic coupons (GENERIC), a notice appears indicating that direct rate comparisons may be misleading (different target audiences, issuance channels).

Verdict line: At the bottom of the comparison scorecard, a summary is displayed that describes which coupon type leads in the most primary metrics.

XLSX export: Click Export XLSX to download the full comparison table as a localized Excel file (XLSX). The file includes all metrics, baseline deltas, and confidence signals.

Return to list view: Click Back to return to the Coupon Analytics list table. Your filters and selections are preserved.


5.5 Free-Item Give-Away Report​

The free-item report shows how many times DRE actually issued free items (FREE_ITEM actions) and how many times an issuance was blocked because a global per-code cap was already met. This report answers the question: "How often did two promotions try to give the same free item, so only one won?"

Accessing the free-item report​

  1. Open the launchpad.
  2. Go to the Reports & Analytics group.
  3. Click Free-Item Give-Away (subtitle "Daily free-item give-aways + how often a grant was suppressed by another promotion").

The list report shows daily aggregate rows; click a row to view details.

What the report shows​

ColumnMeaning
DateThe business date of the aggregation.
POS GroupThe POS group (e.g., DOWNTOWN, MALL, OUTLET).
GrantedCount of free-item give-aways that actually occurred.
Suppressed by Another PromotionCount of attempts to give the same code that were blocked due to a cap.
Give-Away CostSum of the cost of actually granted free items (EUR).
Unvalued GrantsCount of grants for which DRE could not assign a price (data quality flag).

Status meanings and gotchas​

  • Suppressed = global per-code cap: Suppression occurs when at least one contributing promotion has restrictToOnePerBasket=true — then the global per-code cap applies (1 unit basket-wide), and the higher-priority promotion wins. This is the restrictToOnePerBasket-driven global per-code cap feature.
  • Unvalued Grants: DRE could not resolve a price for this unit (price source=UNKNOWN_ZERO). The grant was issued but cost is unknown → counts 0.00 EUR toward cost (data quality signal).
  • Data is NOT real-time: The report is aggregated nightly over the PREVIOUS UTC day. Today's latest transactions appear tomorrow.
  • POS Group 'UNASSIGNED': Telemetry without POS-group assignment is rolled up here.

Important notes​

  • Read-only — this is a pure analytics report.
  • Roles: Access for Admin, PromotionManager, BudgetManager.
  • Filtering: You can filter by Date and POS Group.

Phase 6 — Compliance​

6.1 Audit log and compliance​

Last updated: 2026-05-28

DRE maintains a complete record of all security-relevant actions. The Audit log is intended for compliance teams, auditors, and system administrators.

Example: For the quarterly compliance review, you want to export all approval and rejection events from the last quarter. The audit log delivers that in a few minutes.

What is recorded?

ActionRecorded
Activate / deactivate promotionYes — with timestamp and actor
Submit promotion for approvalYes
Grant / reject approvalYes — with comment
Webhook replay triggered / delivery skippedYes
Failed sign-in / security event (for example, a rejected access)Yes

Note: For promotions, budgets, and other business objects, the audit log now shows their meaningful name (for example, "Summer Promotion 2026" instead of just a technical ID), which makes tracking easier.

Open and filter the audit log​

  1. Open the Audit log app from the Launchpad.
  2. You can sort the list by timestamp to show the newest events at the top.
  3. Use the filter bar to narrow the view:
    • Action — for example, "Activate" only or "Approval" only.
    • Actor — all actions by a specific user.
    • Timestamp — from/to date.
    • Entity Type — for example, only events for Promotions or Budgets. There is no filter for a single individual promotion.

View an entry in detail​

Click an entry in the list to see the full details:

  • Timestamp — exact date and time.
  • Actor — who performed the action.
  • Action — what exactly was done.
  • Affected Object — the type (for example, Promotions, Budgets), name, and technical ID of the affected object.
  • Comment — for approvals: the reviewer's comment.

SIEM export for external systems​

If your organisation uses a Security Information and Event Management (SIEM) system, the audit log can be exported automatically as a JSON Lines file. The export runs daily as a background job.

What is exported: All entries from the audit log table (promotion activations, deactivations, approvals, rejections, campaign locks, webhook replays, and security events).

Where are the export files? The configuration of the SIEM export (destination path, authentication) is handled by your IT team.

Note: The SIEM export outputs only audit log entries — no transaction data and no personal customer data (no customer IDs in the audit log).

Common questions about the audit log​

How long are entries retained? Audit log entries are not automatically deleted. Contact your system administrator if a statutory deletion obligation must be fulfilled.

Can I edit or delete entries after the fact? No — the audit log is read-only. No user (including administrators) can edit or delete entries. This is a deliberate design decision for compliance requirements.

An entry is missing — why? Only the actions listed in the table above are recorded. Read accesses (for example, opening the promotion list) are not captured. If an activation or approval event is missing, contact support.


Phase 7 — Advanced topics​

7.1 Local store instance​

Last updated: 2026-05-28

The local store instance is a lightweight copy of DRE that runs directly on the store server. It evaluates receipts without needing a connection to the central cloud platform. Once the connection is available again, it synchronises data automatically.

When do I need a local instance?

  • Your store has an unreliable or slow internet connection.
  • You want to minimise response times at the POS terminal (no cloud latency).
  • Your operation must remain fully functional during internet outages.

What does the store operator see?​

The store operator works with the Local admin app (accessible at http://<store-server>:4004/local-admin). When you open the app without an active session, the platform prompts you to sign in and takes you to the login page. After that, you can log in.

In the Status section of the BTP-connection object page (Local admin app) you see:

DisplayMeaning
Connection statusGreen = connected to BTP, Yellow = untested (no connection test yet), Red = disconnected/error. The probe/half-open state and offline mode are shown separately via the Circuit breaker state and BTP status fields.
Last syncTimestamp of the last successful data synchronisation
Last sync statusResult of the most recent synchronisation
Pending transactionsCount of checkouts not yet transferred to BTP
Promotions loadedNumber of promotions currently available locally

Heartbeat monitoring​

The local instance continuously monitors whether the connection to the central cloud platform is available ("heartbeat"). You do not need to do anything manually — monitoring runs automatically in the background.

  • Connected (Green): All checkouts run through the cloud — maximum freshness of promotions data.
  • Offline (Red): The cloud is not reachable. Checkouts are calculated locally and stored as pending transactions.
  • Probe (Yellow): The platform is testing whether the connection is stable. Checkouts still run locally until stability is confirmed.

Note for the operator: If the connection stays in offline mode for an extended period, please check the router and internet connection. Local promotions data can become stale if the last sync was more than 24 hours ago.

Synchronisation between store and cloud​

Synchronisation runs in two directions:

  1. Promotions data from cloud to store: New and changed promotions are downloaded automatically every 5 minutes (configurable). This ensures the store always knows the current promotions.

  2. Transactions from store to cloud: Each confirmed checkout is transferred to the cloud. If the connection was interrupted, all accumulated transactions are automatically sent once the connection is restored.

Trigger manual synchronisation:

  1. Open the Local admin app.
  2. Click Sync now.
  3. The platform immediately shows the result — success or an error message with the cause.

Test the connection​

If you are unsure whether the connection to the cloud is working:

  1. Open Local admin → BTP Connection.
  2. Click Test Connection.
  3. The platform shows either "Connection successful" or an exact error message (for example, wrong credentials, missing permission).

Common questions about the local instance​

How long can the store work offline? Indefinitely — as long as the promotions data has not expired. The Last sync and Promotions loaded fields in the admin app show how fresh the locally stored data is and how many promotions are available.

What happens to discounts granted during offline operation? All checkouts are stored as pending transactions and transferred to the cloud after connection is restored. If a promotion budget was exceeded in the process, the overage is flagged as a warning in the budget report — the transactions themselves are not reversed.

How do I set up a local instance? The complete setup guide (Docker installation, credentials, network configuration) is in the separate document Local Store Installation (for IT administrators).


7.2 Tenant configuration​

As a system administrator, you can customise the behaviour of the DRE tenant through Tenant configuration. These settings affect the entire tenant account and require administrator permissions.

Enable the approval workflow​

By default, promotions can move directly from draft to active. To enforce the approval process, enable the flag Approval required before activation:

  1. Open Tenant configuration from the Launchpad.
  2. Click Edit.
  3. Switch Approval required before activation to On.
  4. Click Save.

From this point on, all promotions must go through the approval workflow (see section 3.1 Approval process).

Analytics settings​

The analytics configuration (near-miss threshold, time zone, GDPR flags) is managed through the Tenant analytics app — see section 5.3 Tenant analytics.

Reset password (local instance)​

For the local store instance, a CLI tool is available for password resets. Contact your IT team if needed — the full guide is in the document Local Store Installation.

Important: Change the default password of the local instance immediately after the initial installation. The default password is documented in the installation guide.


7.3 Set up a demo environment​

As an administrator, you can prepare demo environments for training, customer demonstrations, or test purposes with realistic sample data. DRE provides automated scripts for this that build and manage a complete demo landscape.

Load demo data (seed:demo)​

The script npm run seed:demo fills the database with a curated demo campaign based on German retail scenarios:

What is seeded:

  • 5 promotions — a complete promotion lifecycle: discount on an article group (for example, "10% off electronics"), receipt discount, bundle offer (grill set), coupon promotion, and loyalty-card bonus.
  • 2 campaigns — "Summer Campaign 2026" (active) and "Autumn Promotions 2026" (draft).
  • 2 budgets — with funding shares (for example, 60% supplier, 40% marketing department).
  • 2 stakeholders — one external supplier and one internal marketing department.
  • Coupon codes — 3 pre-generated codes for testing coupon redemption.
  • Conditions and actions — fully configured for each promotion.

Use case: You want to demonstrate the platform to a new prospect and need a realistic scenario landscape within seconds.

Usage:

npm run seed:demo

The script is idempotent — you can run it multiple times without creating duplicates. It checks before each insert whether the data already exists.

After running it, navigate via the Launchpad to the Promotions app to see the seeded promotions. Test them with the Simulator (section 4.1 Simulator).

Clean up test residue (db:clean)​

During your test runs and development, entries with test prefixes (for example, TEST_, BUG-P-, BUG-PT-) accumulate. The script npm run db:clean removes these entries safely.

Behaviour:

  • Dry run (default): npm run db:clean shows which entries were found, without deleting them. This is the safe default.
  • With deletion: npm run db:clean -- --apply actually deletes the found entries.

The script scans the following entities for test prefixes: promotions, campaigns, budgets, stakeholders, coupon types, and more.

Example:

# Dry run — what would be deleted?
npm run db:clean

# Actually delete
npm run db:clean -- --apply

Note: The dry run exits with exit code 1 when residue was found. This lets CI pipelines detect when the database is not clean.

Load demo data for the analysis dashboard (seed:kfroi-demo)​

The Promotion Impact ROI dashboard (section 5.1 Promotion Impact ROI Dashboard) needs transaction data to render its 5 charts. In a fresh environment, the dashboard shows "No data".

The script npm run seed:kfroi-demo seeds 6 days of synthetic telemetry data so you can see the charts immediately and be demo-ready.

What is seeded:

  • Threshold gaps: scenarios in which customers narrowly missed a discount.
  • Near-miss data: missed promotion opportunities per day.
  • Savings summary: total customer savings over 6 days.
  • Progressive nudges: hints in different checkout phases.
  • A/B test data: variant uplift and conversion rates.

Usage:

npm run seed:kfroi-demo

The script runs the aggregation jobs for the last 6 days automatically. Afterwards, open the Reports & Analytics → Promotion Impact ROI tile in the Launchpad to see the charts populated with data.

Note: The data is synthetic and created for demo purposes. It is not based on real checkouts. After running real promotions, the real telemetry data replaces the demo data.

Production safeguard: test names rejected​

On the production profile, a safeguard is activated automatically: you cannot create or rename a promotion, campaign, budget, or other entity with a name that begins with TEST_, BUG-P, or BUG-PT.

Reason: The database can accidentally overflow with test residue, especially when demo environments are tested in production.

Behaviour:

  • Attempt to create a promotion with the name TEST_Summer Campaign: HTTP 400 with the message "Names starting with TEST_, BUG-P, or BUG-PT are reserved for testing and are not allowed in production."
  • Dev/test/local profiles: The safeguard is disabled. You can use test names freely.

Workaround: Name your test promotions with a date or asset number, for example 2026-06-02-Demo-Campaign or PROMO-999-Training.

Next steps​

  • Run npm run seed:demo to load a demo environment.
  • Open the simulator and test one of the seeded promotions against a sample basket.
  • If you want to demonstrate the ROI dashboard: run npm run seed:kfroi-demo and then open the Analytics app in the Launchpad.
  • Before the next test or demo: run npm run db:clean (dry run) to detect residue, and clean up with --apply if needed.

7.4 External notifications — webhook subscriptions and failed deliveries​

Last updated: 2026-06-10

Webhooks are external notifications that DRE sends to partner systems — for example, when a promotion is activated or a receipt reaches a budget. Sometimes these deliveries fail: the receiving system does not respond, the network drops, or a temporary overload causes a timeout.

Prerequisite — Redis and webhook worker​

Webhooks require two technical components:

  1. Redis cache — to manage the delivery queue and retry state.
  2. Webhook delivery worker — a continuously running process that processes pending deliveries (status PENDING) and sends them to the receiver URLs.

Without these components, you can create and save a webhook subscription, and DRE creates delivery entries in the outbox. However: the entries remain in status PENDING — no active delivery occurs. DRE logs a warning at startup ("Webhook delivery worker not started (REDIS_URL unset)…"), and the health endpoint (/health) reports the status webhookDelivery: inactive.

Ask your system administrator:

  • Is Redis available and configured?
  • Is the webhook delivery worker running?

If you are unsure, check the DRE startup logs or ask your operator.

Create a webhook subscription​

You configure webhooks through the Webhook Subscriptions app in the admin interface. Each subscription defines which external URL DRE sends notifications to, and on which events.

Steps to create a webhook subscription:

  1. Open the Launchpad and navigate to the Administration group.
  2. Click the Webhook Subscriptions tile.
  3. Select Create in the toolbar.
  4. Fill in the create form:
    • Callback URL (required): The HTTPS address of the receiving system to which DRE sends the notifications. Example: https://api.example.com/webhooks/promotions.
    • Event Filter (required): Defines which events trigger a webhook. Three forms are possible: * (all events), an exact event name (for example, PROMOTION_ACTIVATED), or a prefix pattern <prefix>.* (for example, ImportJobs.*). Important: The promotion, budget, transaction, and coupon events contain no dot in the name (see the event catalogue below). A pattern such as Promotions.* or coupon.* therefore matches nothing — to receive these events, use * or the exact name.
    • Secret (required): A shared secret for signing the webhook requests. At least 16 characters. DRE uses this secret to compute HMAC-SHA256 signatures that the receiver uses for validation.
  5. Optional — adjust the retry parameters:
    • Active: Switch the subscription on/off (default: On).
    • Max. attempts: Maximum number of automatic retry attempts on failed delivery (default: 5).
    • Backoff strategy: Delay model for retries (EXPONENTIAL — the default — or FIXED).
    • Retry interval: Wait time between retry attempts (in milliseconds; only effective with the FIXED backoff strategy).
  6. Click Create in the dialog footer to save the subscription.

Available events (event catalogue):

You can subscribe to these events. Note the spelling: the lifecycle events contain no dot and are therefore reachable only via * or their exact name, not via a .* pattern.

EventWhen it is triggeredReachable via
PROMOTION_ACTIVATEDA promotion is activated* or exact
PROMOTION_DEACTIVATEDA promotion is deactivated* or exact
PROMOTION_EXPIREDA promotion is automatically deactivated because its validity period has elapsed* or exact
PROMOTION_SUBMITTEDA promotion is submitted for approval* or exact
PROMOTION_APPROVEDA promotion is approved* or exact
PROMOTION_REJECTEDA promotion is rejected* or exact
PROMOTION_ARCHIVEDA promotion is archived* or exact
CAMPAIGN_ACTIVATEDA campaign is activated* or exact
CAMPAIGN_COMPLETEDA campaign is completed* or exact
TRANSACTION_CONFIRMEDA POS transaction is confirmed* or exact
LOYALTY_POINTS_AWARDEDA confirmed transaction awarded loyalty points (only when points > 0; fires in addition to TRANSACTION_CONFIRMED)* or exact
TRANSACTION_RETURNEDA confirmed transaction contained return lines (only for returns; fires in addition to TRANSACTION_CONFIRMED)* or exact
PROMOTION_UPDATEDAn edit changed a material field of a promotion (discount value, validity period, exclusivity) — purely cosmetic changes such as name or description do not trigger it* or exact
BUDGET_THRESHOLD_REACHEDA budget reaches its threshold* or exact
BUDGET_EXHAUSTEDA budget is fully consumed (in addition to BUDGET_THRESHOLD_REACHED)* or exact
COUPON_ISSUED, COUPON_REDEEMED, COUPON_CANCELLEDCoupon lifecycle (issued / redeemed / reservation cancelled)* or exact
COUPON_EXPIREDA coupon code reaches the EXPIRED status* or exact
COUPON_BATCH_COMPLETEDA coupon auto-refill batch finishes generating codes* or exact
COUPON_POOL_LOWThe available coupon code count falls below the configured threshold* or exact
ImportJobs.SUCCEEDED, ImportJobs.FAILEDMaster data import completed*, ImportJobs.*, or exact
ArticleImportJobs.SUCCEEDED, ArticleImportJobs.FAILEDArticle import job completed successfully or failed*, ArticleImportJobs.*, or exact

Example: To be notified about all promotion status changes, either create several subscriptions with the exact names (PROMOTION_ACTIVATED, PROMOTION_DEACTIVATED, …) or a single subscription with * (all events).

For developers: The exact JSON data models, signature verification, and delivery guarantees per event are documented in the API reference under “Webhook Events”.

Important — secret security:

The secret is shown only during creation. After saving, it is no longer shown in the list or on the detail page — it is stored only as a secure hash. If you lose the secret, choose Edit, enter a new value in the Secret field, and save; the field appears empty in edit mode and overwrites the old secret on save. There is no "show secret" wizard — the old value is never shown again. Important: As soon as you change the secret, DRE signs all subsequent webhooks with the new value. Update the secret in the receiving system at the same time, otherwise the signature check fails there and the deliveries end up as DEAD_LETTER.

Next steps after creation:

After saving, the webhook subscription is active. DRE now sends notifications to the callback URL for all events that match the event filter. You can open the External Notifications app to check whether deliveries succeed (status: DELIVERED, PENDING, or DEAD_LETTER).

To verify that your receiving system processes the notifications, use the Test Delivery button on the webhook subscription. It sends a synthetic test event to the callback URL so you can confirm reachability and processing. This is a separate feature from the replay function (which re-queues a previously failed outbox delivery).


Lifecycle webhooks (activation/deactivation): When you activate or deactivate a promotion and an active webhook subscription matches, DRE reliably creates an outbox entry (status: PENDING). You find this entry in the webhook delivery list for monitoring.

DRE retries automatically, but after 5 automatic attempts a delivery is marked as DEAD_LETTER (permanently failed). The replay feature lets you manually re-queue a failed or pending delivery, without database access.

When do I need the replay feature?

  • A webhook is stuck (status: PENDING), and the receiving system has since been repaired.
  • A webhook has permanently failed (status: DEAD_LETTER), and you want to retry it after fixing the problem.
  • You want to react quickly without asking IT staff for database access.

Workflow: replay failed webhook deliveries​

  1. Open the External Notifications app from the Launchpad.

  2. The list shows all webhook deliveries with their status values:

    • PENDING — pending, being processed, or waiting for the next attempt.
    • DELIVERED — successfully delivered.
    • DEAD_LETTER — failed after 5 attempts.
  3. Find the row with the failed webhook. Click it to select it.

  4. In the toolbar of the table (at the top) you can see the Replay button:

    • Enabled — when the row has status DEAD_LETTER or PENDING.
    • Disabled — when the row has status DELIVERED (these webhooks need no replay).
  5. Click Replay. DRE resets the status to PENDING and re-queues the delivery for processing.

  6. The webhook worker processes it asynchronously. The list view refreshes automatically and shows the new status.

Limits and security​

Max replay limit = 5: Each time you click Replay, a manual replay is counted. After 5 manual replays of the same delivery, the button is disabled and an error message is shown: "Max replay limit (5) reached for this webhook." This protects against infinite loops.

Note: The 5 manual replays are counted separately from the 5 automatic attempts. A delivery with 5 automatic attempts and 0 replays can therefore be replayed manually 5 times.

Audit trail: Every manual replay is recorded in the Audit log (section 6.1 Audit log and compliance) with the action WEBHOOK_REPLAY_TRIGGERED. This ensures that compliance auditors can trace who triggered the replay.

Common questions​

Why is the "Replay" button disabled? The button is only active for status DEAD_LETTER or PENDING. With status DELIVERED, it means the webhook was already delivered successfully — a replay is not necessary. If you try to resend a DELIVERED row, the platform shows the message: "Cannot replay a DELIVERED webhook."

What happens if the receiving system still does not respond? The worker makes a new attempt. If it fails, the delivery is set back to DEAD_LETTER. You can then trigger a replay again — up to 5 times. If all 5 replays fail, contact your system administrator to check the receiving system.

Can I replay multiple webhooks at once? This version supports single replays only: you select a row and resend it.

Next steps​

  • Open the External Notifications app and look for deliveries with status DEAD_LETTER.
  • Contact the operator of the receiving system to diagnose the problem.
  • When the problem is resolved, resend the delivery and observe the new status.
  • In the audit log, you can look up the replay event later.

Phase 8 — Appendix​

8.1 Troubleshooting​

1. Local connection status shows "Offline" persistently​

Symptoms: The connection status in the Local admin app shows persistent red (Offline). Checkouts run locally but no synchronisation occurs.

Possible causes:

  • BTP URL is incorrect or not reachable from the store network.
  • OAuth2 credentials (client ID / client secret) have expired or are invalid.
  • Firewall rules block outbound HTTPS connections from the local server to the cloud.

Solution:

  1. Open Local admin → BTP Connection → click Test Connection.
  2. Check the error message. If it reads "Auth OK, but missing SyncService permission", have the XSUAA service key recreated with the correct permissions.
  3. Make sure the BTP URL is correct (must start with https://).
  4. Check network connectivity from the server.

2. Promotions data seems stale — new promotions do not appear​

Symptoms: The Last sync field in the Local admin app is hours or days old. New promotions from the cloud do not appear.

Possible causes:

  • The sync service is not running (BTP credentials not configured).
  • The connection status is Offline and delta sync cannot reach BTP.

Solution:

  1. Open the Local admin app → BTP Connection. Check Last sync and Last sync status.
  2. Click Sync now to trigger an immediate sync and observe the result.
  3. If the sync fails, the app shows a detailed error message (success or error reason).

3. Pending transactions are growing — no transfer to the cloud​

Symptoms: The Pending transactions counter in the admin app is growing. Transactions are not reaching the cloud.

Possible causes:

  • Cloud is not reachable (offline mode active).
  • All transactions have exhausted their 5 retry attempts and are marked as FAILED.

Solution:

  1. Check the connection status. If offline, the connection must be restored first.
  2. Wait for the back-off timers to expire (max 8 minutes).
  3. Click Sync now in the admin app.
  4. If transactions are FAILED, check the error messages in the Docker logs. Failed transactions are automatically purged after 30 days.

4. A promotion does not apply even though it is active​

Symptoms: In the simulator or at the checkout, an expected promotion does not appear.

Solution:

  1. Open the Simulator and run the same basket.
  2. Check the Missed promotions block — it explains exactly why each promotion did not apply (phase and rejection reason).
  3. Common reasons:
    • Promotion is inactive or outside its validity window (Pre-filter).
    • POS group does not match — the checkout terminal is not in the promotion's allowed POS groups.
    • Budget exhausted (Budget exhausted).
    • Conditions not met — for example, minimum quantity not reached (Conditions not met).

5. "Invalid EAN" error during item import​

Symptoms: The CSV import shows errors for certain rows with the message "Invalid EAN".

Solution:

  1. On CSV import, each EAN must consist of exactly 13 digits (EAN-13) and pass GS1 check-digit validation. 8-digit EAN-8 codes and invalid check digits are rejected.
  2. Make sure the affected rows contain only 13 numeric digits with a valid check digit — use an online GS1 check tool to verify.
  3. Correct the affected rows in the CSV and start a new import with only the failed rows.

6. Webhook not delivered or stays pending​

Symptoms: An external notification (webhook) shows status DEAD_LETTER (permanently failed) or PENDING (pending/stuck).

Solution: See section 7.4 External notifications — replay failed deliveries. You can manually re-queue failed webhooks through the admin UI.


Get help​

If you cannot resolve the problem yourself:

  1. Note the exact error message and timestamp.
  2. Note the steps you took.
  3. Contact your system administrator or DRE support with this information.

8.2 Glossary​

  • Approval Workflow: The four-stage lifecycle a promotion goes through before it can influence customer baskets: DRAFT (author edits) → PENDING_APPROVAL (waiting for reviewer) → APPROVED or REJECTED. A reviewer (typically a marketing manager with the role PromotionApprover) decides between approving and rejecting. Rejected promotions can be returned to DRAFT status via the action Resubmit for approval — nothing is ever deleted.

  • Exclusion group (MutualExclusionGroup): A named group of promotions where only the one with the highest discount for the specific basket is applied. Other promotions in the group are rejected as blocked by the exclusion group.

  • Auto-refill: Automatic top-up of a coupon code pool when the stock falls below a configured threshold.

  • Budget: A cost limit for one or more promotions. The budget tracks how much of a predefined amount has been consumed through promotions.

  • Draft Activation: The direct path DRAFT → ACTIVE. Only available when the tenant flag Approval required before activation is set to false.

  • Exclusivity level (ExclusivityLevel): Defines how a promotion interacts with other simultaneously active promotions. Values: NONE (stacks with everything), PROMOTION (only the best within the same priority rank), GROUP (only the best within the exclusion group), GLOBAL (no other promotion may apply at the same time).

  • Campaign: A group of thematically related promotions (for example, "Grill Season 2026"). Enables shared date shifting and a calendar group view.

  • Receipt Promotion: A promotion applied to the total amount of the receipt (for example, "5% off everything over €50"), not to individual items.

  • Tenant: A logically separate organisational unit in DRE. Promotions, budgets, and configurations of one tenant are not visible to other tenants.

  • Near-miss: A situation where a basket narrowly did not meet a promotion (for example, at 85% of the required quantity). The platform can issue a hint at the POS.

  • Pilot mode: Trial operation of a promotion in selected stores with statistical evaluation against a control group.

  • POS group: A named group of POS terminals (for example, "Stores South"). Promotions can be restricted to specific POS groups.

  • Priority: A number that determines which promotions are evaluated first when several apply at the same time. The higher the number, the higher the priority. Default value is 0 for promotions without a priority group.

  • Simulator: A test tool app in the Fiori Launchpad that lets marketing planners test promotions against test baskets without triggering real transactions.

  • Stakeholder: A person or organisation that funds a promotion budget (in whole or in part). Types: INTERNAL, BRAND, SUPPLIER, EXTERNAL_SUPPLIER.

  • Tab hijacking: The symptom where two FLP tabs in the same browser window accidentally share URL state via the storage event. Resolved by a tab instance ID.

  • Template Materialize: Clicking Create Promotion from Template on a PromotionTemplate clones the template into a fresh, editable Promotion in DRAFT status.

  • CMF (Co-op Marketing Funds): A financial contribution from an external supplier or brand partner to your promotion costs. In DRE, CMF is managed through the stakeholder type EXTERNAL_SUPPLIER.

  • Recurring Pattern: This feature is no longer surfaced. Its launchpad tile is hidden, so it is not reachable through normal navigation. You now maintain day-based activation through the Days of Week setting on the promotion (see the next entry).

  • Days of Week: A setting on the promotion that restricts activation to specific weekdays (empty = every day). Replaces the former "Recurring Pattern" feature.


Appendix — Technical Integration

The technical interfaces — POS API, Public API, webhooks, article import via DRFOUT, wire formats, and authentication — are aimed at developers connecting their systems to the Digital Retail Engine. You will find these topics in full in the Developer Integration Guide, with the reference for endpoints, fields, and examples.