Architecture kata · K—05

Real-Time Fraud Decisioning for Instant Payments

Architecture kata · design study on a fictional brief

Sector
Banking
Technologies
Apache Kafka, Apache Flink, Valkey, Drools, ONNX Runtime, Quarkus, Apache Iceberg, MLflow, Keycloak, OpenBao
Flow: mainframe MQ messages enter Kafka, Flink precomputes features into Valkey, one decision service scores and replies.
The design at a glance: the one-page, 30-minute live drawing.

In short

Score every instant payment for fraud in 150 ms, keep each decision reproducible for seven years, touch the mainframe only through MQ.

Problem

A mid-size European retail bank joins an instant payment scheme. Fraud rules run in an overnight batch today. In the new setup, the fraud decision gets 150 ms of a 10-second payment window. Load is 300 payments per second on average and 3,000 at peak. The mainframe can only be reached through IBM MQ and cannot change. Every decision must be explainable and reproducible for seven years. Two active data centres are required, with room for cards and open banking later.

Approach

Two demands pull against each other: a tight latency budget and decisions that can be replayed years later. The design precomputes features, decides inside one process and stores every input. Flink computes 90-day behaviour features and writes them to Valkey. The decision service reads one feature vector, then runs Drools rules and an ONNX model in the same JVM. Each decision is saved as a snapshot with the feature vector, rule-set version, model hash and image digest.

Architecture

  • Mainframe bridge: Kafka Connect source and sink for IBM MQ. The platform never calls the mainframe.
  • Backbone: one Kafka cluster stretched across two data centres, with a KRaft witness at a third site. Schemas are Avro contracts in Apicurio Registry.
  • Features and decision: Flink, Valkey, and a Quarkus decision service running Drools and ONNX Runtime.
  • Evidence and learning: snapshots go to Apache Iceberg on object storage with Object Lock. MLflow tracks models. Analyst outcomes return as training labels.

Data flow: payment request on MQ, Kafka, decision, then decision and snapshot in one Kafka transaction, then the reply on MQ.

Architecture: payment requests enter Kafka from the mainframe, Flink precomputes features, one process returns the decision.
Solution overview: from payment channels and the mainframe through Kafka and Flink features to the in-process decision service, its stores and the case management tools.Open full size (opens in new tab)

Why these components

Need Choice Why
Mainframe bridge Kafka Connect IBM MQ source and sink The mainframe only speaks MQ. The connector reads at least once, and a replayed message is dropped by payment ID against the compacted decisions topic. IBM publishes the connector under Apache 2.0.
Event backbone Apache Kafka on Strimzi A durable, replayable log ordered by customer key, where decision and snapshot share one transaction. One cluster stretched across both data centres, not two clusters joined by MirrorMaker 2.
Schema contract Apicurio Registry with Avro Versions the canonical PaymentRequest and snapshot schemas, and incompatible changes fail in CI. Confluent Schema Registry was ruled out because of its Community License.
Streaming features Apache Flink Keeps 90-day windows such as velocity, beneficiary history and device novelty as state. Computing them at query time would eat the 150 ms. Precomputing turns the lookup into one GET.
Online feature store Valkey Sub-millisecond GET with a local replica in each data centre. A BSD-licensed Redis fork, chosen because Redis 7.x moved to source-available licences. A fast path only, not the source of idempotency.
Decision service Quarkus with Drools and ONNX Runtime Rules and model run in one process, so there is no network hop. Drools rules hot-reload and are versioned. ONNX Runtime runs a model from any training framework on CPU in milliseconds.
Snapshot archive and offline store Apache Iceberg on Ceph RGW with Object Lock Cheap, immutable storage for seven years of snapshots, in a table format that Spark and Trino both read. Ceph, because the MinIO community edition narrowed.
Training and model registry Apache Spark and MLflow Training joins snapshots with analyst labels, so it uses the features the model actually saw. MLflow holds versions, metrics and approvals, and moves the champion pointer.
Case management PostgreSQL with custom services Alert queue, analyst outcomes and rule metadata. Small, relational and auditable.
Gateway and identity Apache APISIX and Keycloak Analyst and auditor screens use OpenID Connect, federated to the bank’s identity provider, with roles and an audit log. APISIX, because Kong OSS moved features out of its open edition.
Secrets and keys OpenBao Connector credentials, encryption keys and PKI. The MPL-licensed fork of Vault, since HashiCorp Vault moved to the Business Source License.
Observability OpenTelemetry, Prometheus, Grafana, Loki, Tempo Per-stage traces show where the 150 ms goes. The Grafana stack’s AGPL licence is OSI-approved and creates no obligation for internal use.

Decisions and trade-offs

  • Model inside the decision process. The kata estimates 20–40 ms of the 150 ms budget for a separate model service. Inside the JVM, ONNX Runtime scores in about 2 ms. I gave up operational flexibility for p99 latency. Promotion and rollback stay a pointer change, because both models stay loaded. With a looser budget, a separate model service would be the more flexible choice.
  • Store features, do not recompute them. Each snapshot holds the feature vector, rule-set version, model hash and image digest. Replaying a decision means running the same image on the same vector. Recomputing would use data that arrived later and change the outcome. The same snapshots become the training set, so training and serving see identical features. The cost is archive size, estimated at about 45 TB over seven years.
  • One stretched Kafka cluster, not two with MirrorMaker 2. Idempotency rests on one compacted decisions topic where the first writer wins. That rule cannot be defined across two clusters. If a data centre fails mid-decision, the other side checks the topic before it scores. The cost is a third site for the KRaft witness, within 10 ms of both data centres.
  • Kafka on the synchronous path, not a direct MQ read. Kafka gives replay from one log, fan-out to the Flink feature jobs and an audit trail. Reading MQ directly would mean building all three separately. The cost is poll and queue wait, about 8 ms, which fits inside the estimated 40 ms at p99.
  • Ordered degradation. Without features: rules only, reported as a fallback rate. Without rules: the model with a conservative threshold. Without both: send to review. A timeout on the mainframe side also means review, never a blind approval. The cost is more held payments during an incident. False positives are the biggest risk, so the fallback rate sits on the dashboard.
  • Challenger in the same process. The challenger scores every payment in shadow mode, and only its result is logged. Promotion moves the champion pointer after a four-eyes approval. Rollback moves it back, and nothing restarts. The cost is two models in memory on every decision pod.
Flow: the 150 ms budget is split across hops, every decision can be reproduced, and models are deployed safely.
The latency budget hop by hop, how each decision is reproduced, and how a new model is deployed safely.Open full size (opens in new tab)

What I would revisit

  • Mainframe timeout default. Does the mainframe hold or approve when the reply is late? The degradation design depends on that answer.
  • A third site. Without a site within 10 ms of both data centres, the topology falls back to two clusters with MirrorMaker 2. Then the first-writer-wins rule no longer works as designed.
  • Card tokens. Can the card platform really send tokens, or will card numbers become visible? The PCI scope depends on it.
  • Feature count and windows. I assumed 40 features over 90 days. The real numbers size Valkey and Flink.

Outcome notes (design assumptions, not measurements)

This is a design exercise, not a production system. The output is a four-page diagram set, a one-page whiteboard version and a 14-page Turkish PDF. The PDF holds assumptions, component rationale, licences, capacity arithmetic and open questions. The latency budget (about 40 ms at p99 against 150 ms) is a design estimate, not a measurement.

Sources

  • Architecture PDF (Turkish, 14 pages).
  • draw.io diagrams (English labels): four-page set and a one-page 30-minute version.

Real projects on this topic

  1. P—02

    Completed

    Featured

    GA4 Analytics Modernization: Gold Layer, Streaming and Anomaly Detection

    GA4 analytics rebuilt on BigQuery with a Gold e-commerce model and drift checks: monthly cost $9K to $3K, heaviest queries 46 minutes to 8 seconds.

    • Analytics-ready data
    • Decision support
    • Data quality
    • Data observability
    • Cloud

    Role

    Program lead · Data Solution Architect

  2. P—06

    Completed

    Azure Reporting Platform for 1,200+ Business Users

    Reporting platform for 1,200+ business users migrated to Azure Data Factory, Synapse, Analysis Services and Power BI; 2nd place, IDC Turkey Awards.

    • Decision support
    • Analytics-ready data
    • Data platform
    • Cloud

    Role

    Migration · Senior Data Engineering & Data Architecture Group Manager

Decisions: projects, katas and publications

About the katas

Write to me about a similar design problem.