Software Architecture

Architecture Is the Decisions You Cannot Undo Cheaply

Frameworks come and go; structure is what survives. Our architecture practice is built on domain-driven boundaries, decisions recorded in writing, and systems designed to evolve — because the only wrong architecture is the one that cannot change.

Philosophy

Four Commitments Behind Every System

Before any diagram is drawn, these commitments are already in force. They are the difference between an architecture that photographs well and one that ages well.

Domain-Driven Boundaries

Service and module boundaries follow the business domain — records, events, monitoring, integration — not the org chart of the month. Boundaries that match how the business thinks stay stable while teams reorganize around them.

Modular Monolith First

We start with a well-modularized monolith and extract services only when scale or team topology demands it — with the seam already designed in. Microservices are a solution to an organizational problem, not a badge.

Every Decision Gets an ADR

Architecture Decision Records — the practice introduced by Michael Nygard — capture each significant choice with its context and consequences. A new engineer reads our ADRs and inherits ten years of judgment in an afternoon.

Designed to Evolve

Versioned contracts, parallel-run migrations, strangler-fig replacements. We never bet the platform on a big-bang rewrite — evolution is a feature we engineer on purpose.

System Structure

One Reference Architecture, Four Platforms

Every FiduciaWay platform follows the same layered shape. The names change; the contract discipline does not: each layer only talks to its neighbors, and every hop is authenticated, authorized and traced.

Experience Layer

SSR web apps and native mobile clients — bilingual, RTL-first, WCAG 2.2 AA, rendered close to the user.

SvelteKit SSRDesign system tokensEdge cachingFeature flags

API & Gateway Layer

Typed, versioned contracts at the door: gRPC internally, OpenAPI 3.1 externally. Rate limits, quotas and mTLS enforced here — not sprinkled through the codebase.

Envoy edgegRPC / OpenAPI 3.1mTLS everywhereContract tests in CI

Domain Services Layer

Business logic in domain-aligned services with explicit ownership. Idempotent handlers, saga-based workflows, and events as the system of record between contexts.

Bounded contextsSagas & outboxIdempotency keysTemporal workflows

Data & Integrity Layer

PostgreSQL as the default engine of truth, append-only ledgers where history must be provable, and derived stores for read-heavy paths — reconciled continuously.

PostgreSQLAppend-only ledgersEvent streams (Kafka)Continuous reconciliation

Platform & Runtime Layer

Kubernetes, infrastructure as code, progressive delivery and observability wired in at birth — the layer that makes the four above operable by humans.

Kubernetes + CiliumTerraform modulesArgo CD rolloutsOpenTelemetry + SLOs

Decisions on Record

Real ADRs, Abridged for the Web

These are actual Architecture Decision Records from our platform, lightly abridged. In the repositories they carry IDs, dates, review threads and status — accepted, superseded, or deliberately reversed.

ADR-014

PostgreSQL as the default system of record

Accepted · 2022

Context —Every new service kept debating its own storage. We needed a default with the fewest regrettable properties and the deepest operational experience on the team.

Decision —PostgreSQL unless a written, ADR-backed exception exists. Anything exotic must prove why relational discipline fails the specific workload.

ADR-021

Event-carried state transfer between contexts

Accepted · 2023

Context —Cross-context reads were coupling services at query time; one slow consumer could stall an entire flow.

Decision —Contexts publish events carrying full state; consumers keep local projections. Coupling moved from runtime to schema, where CI can watch it.

ADR-029

Feature flags gate every release

Accepted · 2023

Context —Long-lived release branches were producing integration debt and Friday-night rollbacks.

Decision —All changes merge to trunk dark, ship disabled, and wake up progressively per environment, cohort and percentage — decoupling deploy from release.

ADR-033

Append-only ledger for Ledger

Accepted · 2024

Context —Auditability required that financial history be provably immutable — no UPDATE, no DELETE, no trust in discipline alone.

Decision —Hash-chained append-only records with Merkle proofs; corrections are new compensating entries, never rewrites. Auditors verify without asking us.

Quality Attributes

The Numbers Architecture Must Defend

These are not marketing figures — they are SLOs with error budgets, reviewed weekly, and every architectural change is evaluated against them in writing.

99.99%

availability, customer-facing critical paths

52 min

yearly error budget per SLO — spent in public

p99 < 300 ms

API latency, server-side, per region

RPO ≈ 0

data loss objective on systems of record

RTO < 15 min

recovery objective for a full region loss

Documented Trade-offs

Where We Chose Boring — and Why It Won

Good architecture is the art of paying for the problems you want. These are the trades we consciously made — each one has a full ADR behind it.

Structure —Modular monolith before microservices

Distribution is a tax you pay in latency, debugging and operational surface. We pay it only when team and scale economics genuinely demand it.

Consistency —Strong consistency for records, eventual for views

Balances and ledgers get serializable transactions; dashboards and projections tolerate staleness measured in seconds. One rule per data class, written down.

Integration —Typed contracts over REST-and-hope

Contracts compiled into CI turn integration drift into a red build at the author’s desk — not an incident at the client’s.

Build vs Buy —Buy plumbing, build the domain

Message brokers and databases are commodities with deep ecosystems; our competitive ground is records, events and workflow logic. We spend engineering where it compounds.