> ## Documentation Index
> Fetch the complete documentation index at: https://docs.loyalty.xeniamoments.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Architecture overview

> The systems involved, the two integration surfaces, and where the REKOM backend sits.

## Systems

| System | Owner | Role |
| - | - | - |
| **POS** (Windows) and **mPOS** (Android) | OnlinePOS | Build the basket, trigger card payment, show and print the receipt. Generate the per-calculation GUID. |
| **OnlinePOS backend** | OnlinePOS | Holds venue, terminal (cash register) and discount configuration; calls the REKOM backend; stores transactions; exposes the REST API and Backoffice. |
| **Payment terminal** | Nexi (Viking terminals via **BAXI** on Windows) / **Softpay** on Android | Reads the card. On Windows the terminal also performs the Nexi Engage lookup (`getasset`) and store enrollment (`registerstore`) through Nexi's **DAM**. |
| **Nexi Engage** | Nexi | Maps a card to a loyalty ID. Softpay talks to the Nexi Engage backend directly; Viking terminals go through DAM, which requires the store to be enrolled. |
| **REKOM backend** | REKOM | Receives the basket and the loyalty ID, applies the guest's benefits and returns the basket. Receives one post-sale event per calculation. Pulls transactions through the OnlinePOS REST API, joined on the GUID meta attribute, for reconciliation and reporting. |

The REKOM backend is a single service from OnlinePOS's point of view, reachable at
`https://loyalty.xeniamoments.com` (production) and
`https://loyalty-staging.xeniamoments.com` (test). Both hosts are **TBC** until
DNS is live; see [Configuration and security](/architecture/configuration-and-security).

## Context diagram

```mermaid theme={null}
flowchart LR
  subgraph Venue["REKOM venue"]
    POS["POS (Windows)<br/>mPOS (Android)"]
    TERM["Payment terminal<br/>Viking + BAXI (Windows)<br/>Softpay (Android)"]
  end

  subgraph OP["OnlinePOS"]
    OPB["OnlinePOS backend<br/>+ Backoffice + REST API"]
  end

  subgraph NEXI["Nexi"]
    DAM["DAM"]
    ENG["Nexi Engage"]
  end

  subgraph REKOM["REKOM"]
    RB["REKOM backend<br/>loyalty.xeniamoments.com"]
  end

  POS -- "1. card payment" --> TERM
  TERM -- "2. getasset (cardref)" --> DAM
  DAM --> ENG
  TERM -. "Softpay: direct" .-> ENG
  TERM -- "3. loyaltyId" --> POS
  POS -- "4. basket + loyaltyId + GUID" --> OPB
  OPB -- "5. POST /v1/onlinepos/basket (sync)" --> RB
  RB -- "6. basket with discounts" --> OPB
  OPB -- "7. final basket" --> POS
  POS -- "8. one approval, final amount" --> TERM
  OPB -- "9. POST /v1/onlinepos/sale" --> RB
  RB -- "10. GET transactions (REST sync)" --> OPB
```

## Two integration surfaces

<Tabs>
  <Tab title="Nexi Engage ↔ OnlinePOS">
    **Purpose:** recognise the card and return a loyalty ID to the POS.

    * On **Windows**, the POS drives the Viking terminal through BAXI. The lookup
      is BAXI action 193 (`getasset`) carrying only the `cardref`; no token is
      distributed to terminals. Lookups only work once the store (BAX) is enrolled
      with Nexi Engage, which the terminal does with action 114 (`registerstore`)
      at every startup. See [Store enrollment](/architecture/store-enrollment).
    * On **Android**, Softpay calls the Nexi Engage backend directly. No enrollment
      is needed (Nexi, 31 Aug 2026).

    This surface is live from **Phase 1**. OnlinePOS never creates members in
    Nexi Engage (*agreed 12 Aug 2026*); enrolling guests and their cards is REKOM's.
  </Tab>

  <Tab title="OnlinePOS ↔ REKOM backend">
    **Purpose:** turn the loyalty ID and the basket into the basket the guest pays for.

    * One synchronous call per basket calculation: `POST /v1/onlinepos/basket`.
    * One post-sale event per calculation: `POST /v1/onlinepos/sale`.
    * Reconciliation and reporting: the REKOM backend pulls transactions through the
      existing OnlinePOS REST API, joined on the calculation GUID (a meta attribute on the order).

    This surface is **Phase 2** and only runs for venues where the REKOM module is
    activated. See [Phases and activation](/architecture/phases-and-activation).
  </Tab>
</Tabs>

## Design principles

These are the properties the rest of the document is derived from.

1. **One payment motion.** The guest taps to pay **once**. Behind that single tap
   the terminal reads the card, Nexi Engage recognises the member, and the basket
   goes to the REKOM backend. Then one of two things happens, and the guest notices
   neither:

   * the sale **proceeds straight on** with the original amount (no member, no
     benefit, or no answer in time), or
   * the amount is **adjusted down** with the loyalty discounts before it is
     authorised.

   Either way the guest approves exactly one amount, the final one, and is never
   asked to tap again, confirm anything or choose anything. There is no
   pre-authorisation on the original amount, no correction afterwards and no
   second approval (*agreed, V1 §11; BAXI prepurchase used as today, 6 Oct 2026*).
   Whether BAXI's timing on Windows gives the POS this window is open point ON1.
2. **No interaction during the call.** The basket call is a pure calculation. Any
   choice the guest makes (vouchers, upsell) happens before payment intent, in
   REKOM's own channels (*REKOM, 31 Aug 2026; accepted 4 Sep 2026*).
3. **The returned basket is the truth.** The REKOM backend is the source of truth
   for all discount calculation, including what happens to discounts already on
   the basket; OnlinePOS validates schema and arithmetic only (*agreed 7 Oct 2026*).
4. **Fail open.** If the REKOM backend does not answer in time, the sale completes
   normally with the original basket. Only the order's **loyalty status** is set to
   `failed`; the sale itself is not failed. Loyalty never blocks a sale
   (*agreed 4 Sep 2026*).
5. **Immutable transactions.** A finalised transaction is never changed. Loyalty
   metadata is written only while the basket is sent and received
   (*agreed 17 Aug 2026*).
6. **Separate books.** OnlinePOS's audit trail is unchanged; loyalty and discount
   reporting are REKOM's, fed by the REST sync (*agreed 7 Oct 2026*).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.