Stack¶
Status: Bootstrapping. Record path and Registry write surface are live; UI shell under Quinoa. Version: 0.3 Date: 2026-08-12
Every choice here has to survive the question why not the boring option? Where the boring option wins, we take it.
Two deployables, two Quarkus lines¶
Kogito 10.2.0 pins Quarkus 3.27.2. Bundling DMN into the record server would force the whole platform onto that older line. So Kovent is deliberately two artefacts:
| Deployable | Quarkus | Role |
|---|---|---|
kovent-server |
3.38.1 | Record path — Registry, Strata, Seal, Cadence, Bench, Prism, Docket, Projections, Quinoa UI |
kovent-automation |
3.27.2 (via fords-automation-platform) |
Assay decision host — Kogito DMN/BPMN, worksheets, decision audit |
Assay in kovent-server calls kovent-automation over REST. That is the one place we accept a
network hop in the write path, and it is forced by the platform version conflict rather than by a
taste for microservices.
Fordsworth standard extensions on the server line: fords-scheduler (Cadence deadlines) and
fords-comm (reminders and outcome notices). Both independently number Flyway migrations from
V1.0.0, so each gets its own Postgres schema, its own named Flyway configuration, and its own
schema_history table — see KD-011.
fords-automation stays on the automation line only.
Runtime¶
| Layer | Technology | Rationale |
|---|---|---|
| Compute | Quarkus 3.38.1 (server), 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 10.2.0 on kovent-automation |
Validation and prudential computation as decision tables a supervisor can read. Hosted via fords-automation-platform so the version pin stays off the record path. |
| Workflow | Kogito BPMN on kovent-automation |
Review and enforcement lifecycles that need long-running process state. Hand-rolled state machines here become the thing nobody dares change. |
| Scheduling | fords-scheduler (Quartz, clustered JDBC, own scheduler schema) |
Cadence materialises obligations and escalates lapsed deadlines once per cluster, not once per node. |
| Communications | fords-comm (own comm schema) |
Reminders and outcome notices. |
| Web tier | Quarkus REST (JAX-RS) + Quinoa | Quinoa serves the front-end from the same artefact, so there is one origin and no CORS story for the UI. |
| Front-end | Angular 22 + Tailwind 4 + Lucide (src/main/webui) |
One SPA under Quinoa. Signals and Signal Forms; no NgRx or UI kit on bootstrap. The design system is prototyped in Next.js for velocity; production tokens and screens land in Angular. Conventions: Front-end. |
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. The only extra deployable is kovent-automation, forced by Kogito's Quarkus pin — not a taste for distribution. |
Embedding Kogito in kovent-server |
Would pin the record path to Quarkus 3.27.2 and fight every Quarkus upgrade thereafter. |
| 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 UI is Angular under Quinoa. |
Related¶
- Architecture doctrine — the laws these choices serve
- Platform overview — the engines
- Front-end — Angular / Quinoa conventions
- Decision log — dated records of the calls above