Skip to content

Stack

Technology and rationale

Status: Proposed. Nothing below is running yet. Version: 0.1 Date: 2026-08-11

Every choice here has to survive the question why not the boring option? Where the boring option wins, we take it.

Runtime

Layer Technology Rationale
Compute Quarkus 3, GraalVM native image Sub-second start, ~64 MB resident. A supervisor's dashboard should not wait on a JVM warming up, and a regulator's infrastructure budget is not elastic.
Reactive core Mutiny Non-blocking IO on the write path. Validation fan-out over dozens of rules must not hold a thread each.
Decision rules Kogito DMN Validation and prudential computation as decision tables a supervisor can read and, eventually, edit. The alternative — rules in Java — puts the regulator back in the vendor queue.
Workflow Kogito BPMN Review and enforcement lifecycles are long-running, human-centric, and auditable. Hand-rolled state machines here become the thing nobody dares change.
Web tier Quarkus REST (JAX-RS) + Quinoa Quinoa serves the front-end from the same artefact, so there is one deployable and no CORS story.
Front-end Web components + lit-html, Redux Toolkit Web standards first. A supervisory tool has a ten-year life; a framework rewrite every three years is a liability. The design system is prototyped in Next.js for velocity, then expressed as custom elements.

Data

Concern Technology Rationale
System of record PostgreSQL Returns are template-shaped, so submitted values live in jsonb keyed by field id and validated against the template version. Structural data — licences, obligations, cases, audit — is fully typed and constrained.
Current state Redis Hydrated current submission documents and idempotency keys. A read of "the return as it stands" must not reassemble versions on every request.
Events Kafka via transactional outbox The outbox keeps event emission in the same transaction as the state change, so a projection can never diverge from the record that caused it.
Documents S3-compatible object store Attachments are content-addressed and checksummed. The checksum goes in the audit trail; the bytes do not go in the database.
Search PostgreSQL full-text Sufficient for firm and return lookup at supervisory scale. Revisit only if measurement demands it.
Analytics Projection tables in PostgreSQL Flattened, typed, denormalised read models. Separate schema, separate credentials, no writes.

Why jsonb for submitted values

This is the load-bearing data decision, so it gets argued rather than asserted.

A configurable return template means the column set is not known at build time. The three options:

Option Verdict
A table per return type, generated by DDL Rejected. Migrations become a runtime concern and thirty returns become thirty schemas that drift.
Entity-attribute-value rows Rejected. Every read becomes a pivot, and the query plans get ugly fast.
jsonb document per submission, validated against the template version Chosen. One shape, indexable with expression indexes on the fields that matter, and the template version is the schema.

The cost is that jsonb will not enforce field types — so Assay validates on write and the write is rejected if the document does not conform to its template version. The schema guarantee moves from the database to an engine we control and can cite. Projections then flatten the fields analysts actually query into typed columns, so reporting gets real types and real indexes.

Platform

Concern Technology Rationale
Identity OIDC (Keycloak), per-firm realms or groups Firms authenticate as their own tenant. Maker and approver are distinct roles, not a flag on a user.
Authorisation Attribute-based, evaluated per firm and return A firm user may only see obligations for licences they are mandated to act on.
Observability OpenTelemetry, Micrometer, structured JSON logs Trace a submission from portal to projection through one trace id.
Deployment OCI containers, Kubernetes or plain hosts Native images run anywhere. No requirement for a managed platform the regulator cannot procure.
Docs MkDocs Material, Cloudflare Pages This site. See Publish docs.

What we are deliberately not doing

Not doing Why
Microservices per engine Engine boundaries are module boundaries first. One deployable until measurement says otherwise; a regulator does not need a distributed systems problem on day one.
An event-sourced write model Append-only versioning gives us the audit properties we need without the replay complexity. Revisit if a real requirement demands it.
A rules DSL of our own DMN is a standard with tooling and a specification. Ours would have neither.
Excel as an integration contract Excel import is a convenience for firms. It is never the source of truth; the template is.
A React production front-end The prototype is React for speed of design. The product is web components.