Skip to content

Platform and services

Audience: partners & internalStatus: implemented

The canonical description of what esz-backend is and where an external system fits. Other pages link here rather than restating it.

What esz-backend is

esz-backend is the internal backend platform of ESZ. It holds the company's canonical business data — customers, employees, products, procurements and certificates — and keeps that data in sync with the external systems the business actually runs on (HR software, ERP, CRM, procurement and mail).

It is not a single application. It is a set of independent services, each owning one business domain and its own database.

Service Owns Talks to today
auth Login, identity, sessions Microsoft Entra / Microsoft OAuth
certificates Certificate records and document files S3-compatible object storage
customers Customer master data Büro+ (Microtech), Salesforce, Business Central
employees Employee master data Personio, Microsoft 365
products Sellable products, technical models and prices Büro+, Salesforce
procurements Suppliers, purchased items, supply options, and catalogue reconciliation Büro+, Hivebuy
integrations Cross-cutting flows: inbound webhooks, generated documents, outbound e-mail Hivebuy, mail relay
logging Central audit + external-call log —

Three rules explain most of the design:

  1. Each service is independent. Separate database, separate deployment. A broken release in customers cannot take down auth. Services do not read each other's databases.
  2. External systems never own our data. Every external system is mirrored into a quarantined layer, then written into our canonical model. Our model never depends on theirs.
  3. esz-backend is the hub. Connected systems receive the data they need for their own function — never data whose only purpose is to be forwarded to a third system. Routing between systems is our job, not the partner's. If system B needs data that system A holds, that flows A → core → B, both hops ours — a second integration, not a wider feed through the first.

Where a new external system fits

An external system ("vendor" in our terminology, regardless of whether money changes hands) is added as a vendor app inside an existing service — not as a new service. If your system carries employee data, it lives inside employees. Sellable catalogue data → products. Purchasing catalogue data → procurements. Customer data → customers. Webhook and document flows that span domains live in integrations. The vendor app is an anti-corruption layer: a translation buffer between your data model and ours.

flowchart LR
  subgraph external["YOUR SYSTEM"]
    yourapi["Your REST / GraphQL API"]
    yourhook["Your webhook emitter"]
  end

  subgraph service["esz-backend service — e.g. employees"]
    direction TB
    subgraph vendorapp["vendor app — quarantine zone"]
      direction TB
      inbound["POST /v1/yourvendor/sync/<br/><i>auth: Bearer access token</i>"]
      hookep["POST /v1/webhooks/yourvendor/event-name<br/><i>auth: signed payload</i>"]
      mirror[("mirror table<br/>keyed on YOUR id<br/>YOUR field names")]
      client["outbound client<br/><i>auth: OAuth2 client credentials</i>"]
      inbound --> mirror
      hookep --> mirror
    end
    core[("core<br/>canonical ESZ model<br/>vendor-agnostic<br/><b>source of truth</b>")]
    mirror -- "upsert — ALLOWED" --> core
    core -- "import — FORBIDDEN" --> mirror
    core --> client
  end

  subgraph platform["Rest of platform"]
    others["customers · products · procurements<br/>read core, never your mirror"]
    logsvc[("logging<br/>every external call:<br/>request · response · latency")]
  end

  yourhook -- "HTTPS + signature headers" --> hookep
  client -- "HTTPS + Bearer access_token" --> yourapi
  yourapi -. "optional: you trigger a pull —<br/>'something changed, come look'" .-> inbound
  core --> others
  client --> logsvc

  linkStyle 2 stroke:#0d9488,stroke-width:2px
  linkStyle 3 stroke:#e11d48,stroke-width:2px,stroke-dasharray:4 4

  classDef ext fill:#f9d6d6,stroke:#b04,color:#000
  classDef vend fill:#fde8e8,stroke:#b04,color:#000
  classDef corebox fill:#cfeec9,stroke:#2a6,color:#000
  classDef plat fill:#e0f0ff,stroke:#268,color:#000
  class yourapi,yourhook ext
  class inbound,hookep,mirror,client vend
  class core corebox
  class others,logsvc plat

Read the diagram as two claims:

  • The green edge (mirror → core) is the only path vendor data takes into ours. The red edge is a rule the codebase enforces mechanically — core importing from a vendor app fails the build, not just review.
  • Vendor identifiers and field names stop at the mirror. If the vendor system is replaced in three years, we delete the vendor app; the canonical model does not change.

The design rules behind the mirror boundary — bounded contexts, field authority, the vendor-removal test — are in Domain modelling.