Skip to content

Architecture overview

Think of SpeculaPro as a security control room for payments. Your systems send it a copy of every transaction as it happens. Inside, a set of specialist workers each do one job: one answers “should this payment go through?” in a few milliseconds, one keeps running tallies per customer (“how much cash came in this week?”), one looks for slow patterns over months, and one files everything away as evidence. When something looks wrong, an alert lands in front of a person who investigates it.

All of those workers live in one program. A small institution runs the whole program on one or two servers. A large one runs many copies, each switched to the job that needs more capacity.

Your systems SpeculaPro Your people
┌──────────────┐ ┌──────────────────────────┐ ┌──────────────────┐
│ Payment app │──ask────▶│ Decide (milliseconds) │──answer─▶│ │
│ Core banking │──send───▶│ Remember (running totals)│ │ Analysts, MLRO, │
│ Daily files │──upload─▶│ Look for patterns │──alerts─▶│ auditors use │
└──────────────┘ │ Keep the evidence │ │ the web app │
└──────────────────────────┘ └──────────────────┘

This page covers the big picture. The rest of the architecture section goes one level deeper on each part.

SpeculaPro is the same software whether we run it for you or you run it yourself. The only difference is how many institutions share one installation.

SaaS (we host it) Self-hosted (you host it)
Who shares it Many institutions (“tenants”). Every row of data is labelled with its owner, and the database itself refuses to show one tenant another’s rows. Only your institution. The same safeguards stay switched on.
Where it runs Our servers, pinned to a region (for example an Africa region, so Ghanaian data stays in-region) Your data centre or cloud: Postgres (via Pigsty), Redpanda or Kafka, and Valkey or Redis with Sentinel
Notifications notify.spalce.net (SMS, email) and GOWA (WhatsApp) Your SMTP server; notify.spalce.net or GOWA only if your network allows outbound traffic
Updates Continuous Versioned releases you install when ready; rule-pack updates are signed so you can check they came from us
Packaging Kubernetes Docker Compose for small installations, Helm for large ones

SpeculaPro ships as a single file, speculapro. You choose what each running copy does with --role:

Terminal window
speculapro run --role=all # everything in one process
speculapro run --role=api # only the web app and management API
speculapro run --role=ingest,persist # a comma-separated mix
Role What it does Status
api The web app, case management, rule and user administration, sign-in Available
ingest Accepts transactions, customers, accounts and exchange rates through the ingest API and puts them on the message stream Available
persist Reads the message stream and writes transactions to Postgres in large batches Available
stream Keeps per-customer, per-account and per-counterparty running totals up to date, runs the enabled post-event rules on every transaction and turns hits into alerts. See Stream evaluator Available
worker Background work: creates future database partitions, clears out old idempotency keys, sends email and SMS notifications and signed webhooks, runs scheduled rules and backtests Available
decision The real-time decision API that payment systems call before approving a payment, and outcome feedback Available
connector Reads institution Kafka topics and SFTP / S3 file drops into the ingest pipeline Available
analytics Optional. Copies transactions, decisions, rule hits, alerts and cases into the analytics store (ClickHouse), for long backtests and the 24-month Analytics page. Runs only where SP_CLICKHOUSE_URL is set Available (optional)

--role=all starts all seven standard roles in one process (and analytics too, where the analytics store is set up), which suits development and small installations. See Running roles for how to combine and separate them.

The web app is compiled into the same file, so there is no separate web server or Node.js runtime to install, patch or secure.

SpeculaPro relies on three well-known pieces of infrastructure. Each has one clear job.

Building block Plain-language job Technology
Database The permanent record: customers, transactions, rules, alerts, cases, the audit log Postgres 18 (Pigsty in production)
Message stream A conveyor belt that carries events between the workers, in order, without losing any Redpanda or Apache Kafka
Fast memory Running totals per customer, so rules can ask “how much this week?” in microseconds Valkey or Redis
Layer Choice Why
Backend Go One small, fast, self-contained program
HTTP and API documentation Huma on chi (standard net/http) HTTP/2, tracing and middleware work as expected; the API description is generated from the code
Database Postgres 18, sqlc, monthly partitions Reliable, well understood, strong row-level security
Streaming Redpanda or Apache Kafka via franz-go Ordered per customer, replayable, scales by adding partitions
Fast memory Valkey or Redis (standalone, Sentinel or Cluster) via go-redis Valkey’s licence is simpler for self-hosting
Rules CEL (cel-go) Safe, checked when saved, fast to run
Analytics (optional) ClickHouse A derived copy for long backtests and 24-month dashboards. Postgres alone is enough without it. See Analytics store
Web app Vite, React, TypeScript, Tailwind, built into the Go program Works fully offline and air-gapped
Observability OpenTelemetry, Prometheus, Grafana Industry-standard metrics and traces

The reasoning behind the less obvious choices is on Design decisions.

  • Compliance officers: every decision and alert can be traced back to the exact data, rule version and settings that produced it. See Data ownership and ingestion and Rules and versions.
  • IT and operations: you run one program plus three standard services. Start small with --role=all; split roles out only when load demands it. See Self-hosting.
  • Security teams: isolation between institutions is enforced by the database, not just by application code. See the Security model.
  1. Data ownership and ingestion: why SpeculaPro keeps its own copy of your data.
  2. Components and Kafka topics: the workers and how they talk.
  3. A real-time decision, step by step
  4. Data model
  5. Rule engine
  6. Feature store
  7. Scaling and performance
  8. Multi-region: how a hosted service keeps each workspace’s data in one region
  9. Design decisions