Engineering

We build systems meant to outlive the people who wrote them.

This page is the long answer. It covers how a system gets designed, what we refuse to take shortcuts on, how failure is handled when it arrives, and what a release actually looks like. If you are going to be responsible for running what we build, this is the page written for you.

Ownership
Source, infrastructure and data belong to the client
Dependencies
No third party in the critical request path
Deployment
Cloud, on-premise or hybrid, same codebase
Lifecycle
Reviewed and advanced every quarter
What we hold to

Five positions we do not trade away.

These are not slogans. Each one costs us something on delivery day and pays the client back for years, which is exactly why they survive contact with a deadline.

  1. 01Build from primitives, not from plug-ins

    An assembled stack inherits every dependency's release cycle, breaking change and security advisory. We write the capability instead. It is slower in month one and enormously cheaper in year three, because nothing in the critical path can be deprecated by someone we have never met.

    The trade: more code to own. Accepted deliberately, because owned code can be fixed in an afternoon and a vendor's roadmap cannot.

  2. 02Determinism over cleverness

    Given the same inputs, the system must produce the same output, and it must be possible to explain why. We avoid implicit magic, hidden global state and behaviour that depends on wall-clock timing. When a decision is non-obvious, the reasoning goes in a comment at the call site, not in a wiki nobody opens.

  3. 03Fail loudly, never silently

    The worst class of bug is the one that swallows an error and returns success. Every boundary either succeeds, or reports precisely what went wrong and where. Validation runs on the client for speed and again on the server for truth, because anything enforced only in a browser is not enforced at all.

  4. 04Durability before delivery

    When data arrives, it is persisted before anything else is attempted. Notification, enrichment and downstream calls all come after the write. A failed email should never cost you the enquiry that triggered it.

  5. 05Measure, then optimise

    We do not guess at performance. We measure at the origin and at the edge, and we act on the number that dominates. Frequently the answer is unglamorous: on one system the application answered in 7 ms while the user waited 670 ms, so the entire cost was network round trips and nothing in the code was worth touching.

Delivery

How a system actually gets built.

Six phases. Each one has an artifact that has to exist before the next begins, which is what stops a project drifting into a demo that cannot be operated.

01

Discovery

We map the operation before writing anything: who touches the process, where the data already lives, which constraints are regulatory and which are habit, and what breaks today.

Artifact: a written constraint map and a failure inventory, both agreed with you.

02

Architecture

Layer boundaries, data model, interface contracts and a threat model. Decisions that are expensive to reverse are made here, on paper, while reversing them is still cheap.

Artifact: a layer diagram, the schema, and a list of decisions with their rejected alternatives.

03

Implementation

Small increments against the agreed contracts. Every change is reviewed for correctness, for what it does under failure, and for whether it makes the next change harder.

Artifact: working software you can operate, not a slide of one.

04

Hardening

We attack it. Malformed input, absent dependencies, exhausted disk, concurrent writes, hostile submissions, and the boring one that catches everybody: a cache that will not let go of an old file.

Artifact: a fixed list of failure modes, each with the behaviour we chose.

05

Deployment

Configuration is validated before it is applied and rolled back automatically if it fails. Releases are atomic. A bad deploy must never be able to take down what was already running.

Artifact: a repeatable one-command release with a proven rollback path.

06

Evolution

Quarterly review against how the operation has actually changed. Systems do not decay because the code rots; they decay because the business moves and nobody moves the software with it.

Artifact: a prioritised change list, and the work to execute it.

Architecture

Five layers, and why they stay separate.

Every system we build is assembled from the same five layers with explicit contracts between them. The point is not tidiness. It is that a change at the interface must never be able to force a change to your data.

05

Integration

Adapters to the systems and hardware you already run. Every external call is treated as hostile: timeouts, retries with backoff, and a defined behaviour when the far side is simply gone.

04

Interface

What the people on the ground actually use. Server-rendered where it must be fast and indexable, progressively enhanced so a failed script degrades the experience rather than removing it.

03

Workflow

Rules, approvals, escalations and state machines. Transitions are explicit and auditable; there is no path where a record can reach a state nobody can explain.

02

Intelligence

Detection, scoring and decision logic tuned to your operating conditions. Every automated decision is traceable to the inputs that produced it, because an unexplainable output is not usable evidence.

01

Data

Capture, schema, retention and access control. Writes are atomic. Nothing above this layer is permitted to leave it in a half-written state.

Reliability

Failure is a design input.

Anyone can build the happy path. The work is in the other paths, so here are real ones with the decision we took in each case.

Configuration that breaks the server

What if a bad config reaches production?

Config is written, validated by the server's own validator, and only then reloaded. If validation or reload fails, the previous file is restored automatically and the service keeps running on it. A deploy cannot take down what was already live.

Caches that never let go

What if a browser pins an old file forever?

Long-lived immutable caching is only ever applied to URLs carrying a content hash. The document itself is always revalidated. Without that pairing, a one-year cache header on a stable filename means users never receive another update, and the failure is invisible to everyone testing on a fresh browser.

Silent data loss

What if the notification fails?

The record is written to durable storage first, then the notification is attempted. A delivery failure is logged and surfaced, never allowed to discard the submission. The user still gets a truthful confirmation, because we actually have their data.

Hostile and automated traffic

What about bots and abuse?

Per-address rate limiting on write endpoints, bounded request bodies, strict field validation, and traps for automated submissions. Anything hidden from a human is hidden with inline styles, so a stale stylesheet can never expose it and silently discard genuine traffic.

Interrupted background work

What if the tab is throttled mid-task?

Timed work is driven by elapsed time rather than a fixed tick count, with a guaranteed completion path. Browsers clamp timers in background tabs; anything counting ticks quietly stalls and never finishes.

Degraded capability

What if a device cannot run it?

Heavy visuals and effects are progressive. Where hardware acceleration, motion preference or a slow connection make them inappropriate, the content renders complete and static rather than broken or blank.

Security

Fewer moving parts means fewer ways in.

Perimeter

On-premise deployments keep processing and storage entirely inside your network, with no operational data crossing the boundary. Hybrid keeps the sensitive half on site. The same codebase serves all three shapes.

Credentials

Secrets never live in source or in a repository. They are held in root-only configuration on the host, and passwords are stored as salted scrypt hashes, never as recoverable text. We do not ask to see them and we do not need to.

Sessions

Signed with HMAC, marked HttpOnly, Secure and SameSite=Strict, with an explicit expiry and constant-time comparison on verification. Authentication endpoints are rate limited independently of everything else.

Transport and headers

HTTPS everywhere with automatic certificate renewal, HSTS, nosniff, frame and referrer policy set at the edge. Administrative surfaces are marked noindex so they never reach a search engine.

Data at rest

Operational records are stored outside the web root with restrictive file permissions, so a server misconfiguration cannot turn them into a public download.

Supply chain

The smaller the dependency surface, the smaller the attack surface. Where we can implement it correctly against the standard library, we do, and every third-party component we do adopt is pinned to an exact version.

Boundaries

What we will not do.

The refusals define the work more sharply than the capabilities do.

  • We will not ship a number we have not verified. If a figure appears in a report we produce, it came from a run, not from an estimate that sounded reasonable.
  • We will not hide a failure behind a success message. If something did not work, the interface says so.
  • We will not build on a foundation we cannot support. If a technology would leave you dependent on a vendor we cannot answer for, we say so before the contract, not after.
  • We will not take a project we cannot do well. A polite no is cheaper for both of us than a mediocre delivery.

Bring us the difficult one.

Describe the problem rather than the technology. If it is something we can engineer properly, we will tell you exactly how we would approach it. If it is not, we will tell you that instead.