Skip to main content
All services

Software Engineering

Built to be run.Not just shipped.

Scalable web applications, APIs, enterprise platforms, and backend systems designed to stay maintainable as they grow.

  • TypeScript
  • Node.js
  • Python
  • PostgreSQL
  • MODULES · CONNECTIONS · SYSTEM
  • SIX TIERS
  • DESIGNED FOR THE SECOND YEAR

Software Engineering.

  1. 01ArchitectBefore the first commit
  2. 02BuildIn small, reviewable pieces
  3. 03ScaleWhere the load actually lands
  4. 04MaintainFor the years after launch

Most software is not hard to write. It is hard to keep. The second year is where the cost shows up — when the person who made a decision has left, when a feature has to be changed rather than added, and when the shortcut that saved a fortnight is now the reason a release takes one.

That is an architecture problem, and it is decided early. Where a boundary sits, what a module is allowed to know about its neighbour, which state is authoritative, and what happens at the seams between your system and someone else's — those choices are cheap to make and expensive to revisit.

So we design for the operating years rather than the launch. Boundaries drawn where the system will actually be cut. Contracts that can be versioned instead of broken. Data models that survive the second feature. Deployment that is boring on purpose. And enough observability that a problem in production is a question with an answer rather than an argument.

Capabilities

What we actually build.

Engagements are usually a subset of this list, scoped to the system in front of us. This is engineering work carried out on your platform — not a template, not a page builder, and not a framework we resell.

01Web Applications
Product surfaces rather than brochures: authenticated flows, real data, permissions, long-running state, and the rendering strategy chosen per route because a dashboard and a marketing page have nothing in common operationally.
02APIs & Integrations
REST and GraphQL contracts designed to be built against and versioned rather than broken, plus the connective work with systems we do not own — payments, identity providers, webhooks and queues — where correctness at the seam is the whole job.
03Backend Systems
The part of a product that has to be right: domain logic with explicit boundaries, transactional correctness, background processing that is safe to retry, and services written so a failure is contained rather than propagated.
04Enterprise Platforms
Internal systems that a real organisation depends on — roles and permissions, audit trails, administrative tooling, reporting, and integration with the systems already in place, including the ones nobody wants to replace yet.
05Database Architecture
Schema design, migration strategy, indexing, and the query patterns a feature is allowed to use. Designed early, because the schema is the part of a system that is hardest to change once it holds records people care about.
06Cloud & Deployment
Environments defined as code, pipelines that make releasing routine, and the observability to answer production questions. The aim is that deploying is the least interesting thing that happens in a week.

Where an existing system can be repaired rather than replaced, we will say so. A rewrite is the most expensive option available and it is very rarely the correct first answer.

System architecture

Six tiers, drawn where they get cut.

A system is not a stack of technologies, it is a set of boundaries. These are the six we draw, what each one is responsible for, and the controls that keep it separable from its neighbours — because the boundaries are what decide whether the thing can be changed in three years.

Client · Application · API · Services · Data · Infrastructure

06 tiers · 30 controls

  1. 01

    Client

    What the user touches

    Frontend05

    The web and mobile surface. Rendering strategy chosen per route rather than per project, state kept as local as it can be, and a bundle whose growth is something someone is accountable for. The client is treated as one consumer of the API, not as the application itself.

    • Rendering strategy
    • State boundaries
    • Bundle budget
    • Accessibility baseline
    • Error and empty states
  2. 02

    Application

    Where the product's rules live

    Backend05

    Business logic, kept out of the transport layer and out of the database. Modules with explicit boundaries, dependencies pointing one direction, and domain rules written so they can be tested without a running server. This is the tier that ages worst when it is skipped.

    • Module boundaries
    • Dependency direction
    • Domain rules
    • Transaction scope
    • Unit-testable core
  3. 03

    API

    The contract between systems

    The one tier that is not a technology choice — it is an agreement, and it outlives the code on both sides of it. Versioned rather than broken, validated at the edge, paginated before anyone needs it to be, and documented as the thing other people build against.

    • Schema and validation
    • Versioning policy
    • Authorisation per object
    • Pagination and limits
    • Error contract
  4. 04

    Services

    Work that happens out of band

    Integrations07

    Background jobs, scheduled work, webhooks and the third-party systems we do not own but still have to be correct with. Retries that are safe to repeat, failures that are visible rather than silent, and the assumption that any external call can hang rather than fail.

    • Idempotent jobs
    • Retry and backoff
    • Webhook verification
    • Timeouts and circuit breaking
    • Dead-letter handling
  5. 05

    Data

    State, and how it is queried

    Database04

    The schema is the part of a system that is hardest to change once it holds real records, so it is designed rather than accumulated. Migrations that run forward safely, indexes that exist because a query needs them, and caching added where it has been measured rather than assumed.

    • Schema design
    • Migration safety
    • Index strategy
    • Caching policy
    • Backup and restore
  6. 06

    Infrastructure

    Where it runs, and how it ships

    Infrastructure04

    Environments defined as code so they can be reviewed like any other change, a pipeline that makes releasing unremarkable, and enough logs, traces and metrics that production questions have answers. Boring on purpose: this is the tier where surprises are most expensive.

    • Infrastructure as code
    • CI and deployment
    • Environment parity
    • Observability
    • Rollback path
Stage 01
Modules00:01
Stage 02
Connections00:03
Stage 03
Scale00:07
Source
1920 × 108030fps · 1.34MB

Still frame

Client · Application · API · Services · Data · Infrastructure

Engineering lifecycle

How the work is sequenced.

The order is the point. Architecture decisions taken after a system is running are the expensive kind, and most of what makes software maintainable is decided in the first two stages — long before most of the code exists.

  1. 01

    Architect

    Draw the boundaries before the code.

    What the system is responsible for, where it is cut, which state is authoritative, and what talks to what. Also what is deliberately not built yet. The output is a set of decisions with reasons attached, so the next engineer can tell what was chosen from what was accidental.

  2. 02

    Model

    Design the data before the features.

    Schema, relationships, invariants and the migration path. The database is the hardest part of a running system to change, so it is designed against the second and third feature rather than only the first one being built.

  3. 03

    Build

    In small, reviewable pieces.

    Vertical slices that are shippable on their own, behind a review and a test suite that runs on every change. Contracts written before the consumers of them, so integration is a scheduled step rather than a discovery at the end.

  4. 04

    Harden

    Find the edges before users do.

    Failure paths, timeouts, retries, permission checks and the states nobody demos: empty, partial, offline, unauthorised, and the third simultaneous click. Load characteristics examined where they actually land rather than assumed to be uniform.

  5. 05

    Operate

    Run it, watch it, and keep it changeable.

    Deployment that is routine, observability that turns incidents into questions with answers, dependency and migration upkeep, and documentation aimed at the engineer who inherits this in two years — who may well be us.

Built for growth

What makes it hold.

These are the properties that decide whether a system can still be changed in three years. They are also the ones that are invisible at launch, which is exactly why they get skipped — and why we would ask about them if we were buying this work rather than doing it.

01Boundaries that survive
Modules that can be understood and changed independently, with dependencies pointing one direction. The test is whether a new engineer can change one part without reading all of it.
02Contracts, not assumptions
Typed interfaces at every seam, validated at runtime where data crosses a trust boundary. An integration that breaks should fail loudly at the edge, not silently three layers in.
03Tests that are worth running
Coverage aimed at domain rules and failure paths rather than at a percentage. A suite that is fast and trusted gets run; one that is slow and flaky gets skipped, and then it is worse than nothing.
04Migrations that run forward
Schema changes designed to deploy without downtime and to be reversible while there is still a reason to reverse them. The database is where irreversible mistakes actually live.
05Observability from day one
Structured logs, traces and the handful of metrics that matter, added while the system is being built. Retrofitting them during an incident is the worst possible time to discover what you did not record.
06Written to be handed over
Decisions documented with their reasons, environments reproducible, and onboarding measured in days. Work that only its author can maintain is a liability regardless of how well it runs today.

What we build

Shapes of system this work suits.

These are system shapes rather than case studies — the situations where architecture is the deciding factor. Our published project work lives under Selected Work; nothing below is presented as a delivered engagement.

01A product with real users and real state
Accounts, permissions, billing, long-lived data and a surface that has to keep working while it changes. The point at which a prototype has to become a system that a team can operate.
02An internal platform an organisation runs on
Roles, audit trails, administrative tooling and reporting, integrated with systems already in place. Usually replacing a spreadsheet, an inbox, and a person who remembers how it works.
03An API other teams build against
A contract with consumers you do not control, which means versioning, authorisation per object, rate limits, and an error format someone can actually handle. Breaking it is a business event, not a deploy.
04Systems that have to agree with each other
Payments, identity, third-party APIs, webhooks and queues, where the hard part is not the happy path but reconciliation, retries, and what happens when the other side is down or answers twice.
05A codebase that has become expensive to change
Where every feature takes longer than the last. The work is finding the boundaries that were never drawn and introducing them incrementally — usually without a rewrite, which is rarely the right first answer.
06A system whose load has moved
Where the shape of usage no longer matches the shape of the architecture. Query patterns, caching, background work and deployment topology examined where the load actually lands rather than uniformly.

Systems layer

What it is built on.

Read from the same engineering stack the rest of the site publishes, not a separate list for this page — so this section cannot claim a technology Moonpie does not already work in. It is deliberately conservative: these are the tools we are prepared to support in production.

01Frontend05What the user actually touches, on the web and on a phone
  • React
  • Next.js
  • TypeScript
  • Tailwind CSS
  • React Native
02Backend05Where the product's rules live, and the contracts it exposes
  • Node.js
  • Python
  • REST APIs
  • GraphQL
  • WebSockets
03Database04State, and the queries a feature is allowed to make against it
  • PostgreSQL
  • Redis
  • Supabase
  • Vector Databases
04Integrations07The systems we do not own but still have to be correct with
  • Stripe
  • Paystack
  • Flutterwave
  • Third-party APIs
  • Webhooks
  • OAuth
  • Message Queues
05Cloud04Where the workload runs and how it reaches people
  • AWS
  • Vercel
  • Cloudflare
  • Object Storage
06Infrastructure04How a change gets from a branch to production, and stays observable
  • Docker
  • CI/CD
  • Observability
  • Infrastructure as Code

Have a system that has tooutlive its launch?

The most useful first conversation is about what the system has to be able to do in two years, not what it has to do on day one. That is usually where the architecture decisions are hiding.