Behind every product,
a system that works.

I build backend systems that stay understandable after handover — from APIs and integrations to the boundaries that keep distributed software reliable.

Backend by focus.Full-stack by practice.Systems by curiosity.

Selected engineering work

The code is the evidence.

A closer look at public projects: the problem, the boundaries, and the decisions behind the implementation.

Authentication · Open source

typed-totp

Read the code
  • TypeScript
  • Web Crypto
  • RFC test vectors
  1. 01Public API
  2. 02TOTP / HOTP
  3. 03Injectable ports
  4. 04Web Crypto
Simplified architecture based on the public repository documentation.

problem

Generate and verify time-based and counter-based passwords without tying core logic to a particular clock or cryptographic backend.

requirements

Correct HOTP and TOTP output, a testable clock, no runtime dependencies, and an API usable both as plain functions and as a configured instance.

architecture

A functional API wraps application services. TOTP delegates to HOTP; pure counter and formatting functions sit behind injectable clock, HMAC, encoding, and comparison ports.

decision

Use platform Web Crypto and zero runtime dependencies. Keep I/O behind interfaces for deterministic tests, while leaving pure mathematics as simple functions. A functional API makes adoption easy; an object API supports reusable configuration.

Read the full case study

Engineering profile

Start with the problem. Design the boundaries.

Backend & APIs

I build production backend services and REST APIs — data modeling, business logic, and integration with external systems — using Java/Spring Boot and Node.js/TypeScript.

Distributed Systems

I'm building depth in the patterns that keep multi-service systems reliable: asynchronous processing, message-driven communication, and designing for graceful failure.

Fintech & Insurance Technology

Since late 2024 I have worked at iPF Softwares, building digital platforms for banking, fintech, and insurance teams across Africa. The work has sharpened my interest in the engineering demands of regulated, transaction-heavy systems.

Full-Stack Delivery

I move comfortably across the stack, from backend services and data layer through to React/Next.js frontends, so I can own a feature end-to-end from API to UI.

Expertise by responsibility

Backend

Model business rules, define service boundaries, and make API contracts explicit before writing handlers.

Java · Spring Boot · Node.js · NestJS · REST API design

Data

Relational modelling, transaction boundaries, and migrations treated as part of the design rather than an afterthought.

PostgreSQL · JPA · TypeORM · Schema design

Distributed systems

Message-driven communication, idempotent handlers, and deciding where consistency has to be strict and where it can wait.

Messaging & queues · Idempotency · Caching · Eventual consistency

Infrastructure

Reproducible environments and a path from a local run to a deployed service that anyone on the team can follow.

Docker · Kubernetes · CI/CD · Environment configuration

Frontend

Typed interfaces built directly against the API contract, so the boundary stays honest on both sides.

React · Next.js · TypeScript

Engineering practices

Tests that describe intent, security boundaries made explicit, and systems that can be understood after handover.

Testing · Security · Observability · Documentation

Experience

A path across the stack.

From product interfaces to full-stack engineering. Public project case studies above provide the implementation detail alongside this professional timeline.

Full history on LinkedIn
  1. Sep 2024 — Present

    Full-stack Engineer

    iPF Softwares

    Current role

    Responsibility

    Building digital platforms for banking, fintech, and insurance teams across Africa. My work spans backend services, integrations, and the interfaces on top of them, in a domain where correctness and reliability are requirements rather than preferences.

  2. 2024 — Aug 2024

    Frontend Engineer

    Senjaro Group

    Responsibility

    Implemented product interfaces against backend APIs, working close to the contract between the two.

  3. 2022 — 2023

    Frontend Developer

    Bato Informatics

    Responsibility

    Delivered application features end to end and took on the technical decisions behind them.

  4. 2021

    Product Designer

    Bato Informatics

    Responsibility

    Started in product design — where I learned to ask what a system is for before deciding how to build it.

References

What the people I worked with can speak to.

Ownership
Ayubu took the tenant-scoping work from a vague requirement to a design the rest of us could review, then carried it through implementation and tests without needing to be chased for status.
Jeremiah LusatoBackend · iPF Softwares
Code quality
His pull requests are small, explain the decision in the description, and the tests describe what the behaviour is meant to be. Reviewing his work is genuinely faster than reviewing most of the codebase.
Christopher ShayoFrontend · iPF Softwares
Reliability after handover
We inherited the service six months after delivery. The documentation matched the code, the migrations ran clean, and we were shipping changes to it in our first week.
Happyness SylvesterQA · iPF Softwares

Architecture notebook

System design notes, written out in full.

Five problems I think about, each written as a problem statement, a component flow, and the trade-offs I would accept. Two draw on production work; three are conceptual design notes.

Design note (conceptual)

What happens when the happy path ends?

A provider can accept a request while its response is lost. A reliable design keeps the payment pending, verifies the provider outcome, and reconciles before retrying the money movement.

  1. 01Client + key
  2. 02Payment record
  3. 03Provider adapter
  4. 04Reconciliation
Duplicate callback → deduplicate → apply valid transition

Problem: the response can disappear

A network timeout cannot tell us whether a provider accepted a payment. Retrying immediately can move money twice. The system needs to distinguish a rejected request from an unknown outcome.

Make the request durable

Scope an idempotency key to the caller and operation, enforce uniqueness in the database, and store a fingerprint of the request. Reusing a key with different input should fail. Persist a pending payment before calling a provider.

Handle callbacks as untrusted, repeatable events

Authenticate the provider callback, validate amount and currency, and deduplicate its event identifier. Apply allowed state transitions in a transaction using a lock or conditional update. A late pending event must not overwrite a confirmed success.

Reconcile before retrying

For an unknown outcome, query the provider or reconcile against settlement records. Use bounded retries with backoff for safe status checks. If the provider cannot confirm an outcome, route it to manual review instead of guessing.

Keep ledger updates atomic

Where a ledger is required, balanced debit and credit entries should commit together with the local payment transition. An outbox can publish follow-up events after that commit; consumers still deduplicate.

Trade-off: more states, more operational work

Durability buys correctness with extra states, reconciliation jobs, and a manual-review path. That cost is only worth paying where a duplicated or lost payment is unacceptable.

Open source

Built to be read, extended, and reused.

Two maintained open-source projects, one inspectable interview exercise, and smaller applications built to explore product and engineering ideas.

Projects I maintain

Exercises and technical samples

Java API · interview exercise

ems

Local setup, dependencies, package boundaries, and API documentation make the interview exercise inspectable.

Java · Spring Boot · PostgreSQL · OpenAPI

Side projects

Data modeling & full-stack delivery

tasks-tracker

A task and milestone management system for teams — built with Next.js server actions, Prisma, and MongoDB for collaborative project tracking.

Next.js · TypeScript · Prisma · MongoDB · Server Actions

Payments integration & full-stack delivery

baimi-ecommerce

A B2C e-commerce storefront with product browsing, cart, and checkout — integrating Stripe for payment processing and Sanity as a headless CMS for product content.

Next.js · React · Sanity CMS · Stripe · Tailwind CSS

Full-stack delivery

eventos

An events management platform for discovering and organizing community events, built end-to-end with Next.js and TypeScript.

Next.js · TypeScript

Content modelling

portifolio-react-sanity

This portfolio itself — a Next.js site with Sanity as the content source, so projects and case studies are edited as structured content rather than hardcoded.

Next.js · Sanity · TypeScript

Engineering challenges

The hard part is rarely writing the code.

Individual problems worth writing down, each traced from the symptom through to the result. Client specifics are deliberately abstracted.

Two callbacks, one payment

Idempotency
Problem

A payment provider retried its callback after a timeout, so a single transaction could be recorded twice — a failure the original happy-path tests did not cover and one that was costly in production.

Investigation

Traced the duplicate to a handler that treated the callback as a command rather than a fact, with no natural key to recognise a repeat delivery.

Solution

Derived a deterministic key from the provider reference, made the write conditional on that key not existing, and returned the original result on a repeat instead of processing again.

Result

Repeated delivery of the same provider reference now returns the original result without creating another ledger write.

A query that only got slow with real data

Data access
Problem

An endpoint that was comfortable in development degraded badly once tables held production volumes and concurrent users.

Investigation

Read the query plan rather than guessing: a filter on a non-indexed column plus a per-row lookup inside a loop turned one request into hundreds of round trips.

Solution

Replaced the loop with a single joined query, added the index identified by the query plan, and added a regression test for the joined-query shape.

Result

The query plan removed the per-row lookup and response times stabilized for the observed production workload. The reasoning is documented next to the query.

Untangling a module that knew too much

Maintainability
Problem

One service had accumulated responsibility for validation, persistence and notification, which made every change risky and every test slow.

Investigation

Mapped what actually called what. Most of the coupling was incidental — shared helpers reaching across boundaries rather than genuine domain overlap.

Solution

Introduced explicit interfaces at the seams, moved side effects behind ports, and split the tests into fast unit checks and a smaller set of integration checks.

Result

Behaviour stayed identical while the module became changeable — new work touches one boundary instead of three.

Engineering decisions

Every choice costs something. Here’s what.

Short decision records — context, the options on the table, what I would choose, and what that choice gives up.

Why start with PostgreSQL instead of a document store?

  • PostgreSQL
  • Document store
  • Both, split by aggregate

context

Most systems I work on hold money, entitlements or records that other parties depend on, and the relationships between them are known up front.

decision

Start relational. Model the entities and their constraints in the schema, and let the database enforce what must always be true.

tradeoffs

Migrations become a deliberate step and horizontal scaling takes more thought than sharding a document store. In exchange, invalid states are rejected rather than discovered later.

consequences

Reach for a document store when the shape genuinely varies per record or the data is a cache of something authoritative elsewhere — not to avoid designing a schema.

Production engineering

Shipping it is where the work starts.

What I put in place so a service can be deployed, watched, debugged and reversed — and what I am still building depth in.

Build & release

Working

Automated pipelines that build, test and produce a versioned artefact, so a release is a repeatable action rather than a manual sequence.

CI/CD · Versioned artefacts · Environment config

Containers & deployment

Working

Services packaged so local, staging and production run the same image, with configuration supplied from outside the build.

Docker · Kubernetes basics · Twelve-factor config

Database migrations

Working

Schema changes as reviewable, ordered migrations that run as part of deployment, written so they can be applied to a live database.

Versioned migrations · Backwards-compatible changes

Observability

Building depth

Structured logs with request correlation, health endpoints, and metrics chosen to answer a specific question rather than to fill a dashboard.

Structured logging · Health checks · Metrics

Failure & rollback

Building depth

Timeouts and retries with limits, graceful degradation when a dependency is unavailable, and a rehearsed way back to the previous version.

Timeouts · Retries with backoff · Rollback path

Incident debugging

Building depth

Reproducing from logs and data rather than intuition, then closing the loop with a test or an alert so the same failure announces itself next time.

Log tracing · Alerting · Post-incident notes

About

Correctness first, then everything else.

I'm a software engineer focused on designing and building reliable backend systems using Java, Spring Boot, and modern distributed-system architectures.

My work involves building production systems where correctness, maintainability, integrations, and reliability matter — including APIs, payment workflows, event-driven processes, and complex business domains.

Engineering practice / Automated tests, code review, documentation, and observability. AI-assisted development with human review and verification remains an area of active practice.

More on LinkedIn

Core engineering interests

  • Service boundaries and API contracts
  • Data modelling and transaction design
  • Reliability in message-driven systems
  • Making security boundaries explicit
  • Systems that survive handover

Start a conversation

Have a system worth building?

Tell me what the system has to do and what it must not get wrong. I read every message and reply to the ones with a real problem in them.

Dar es Salaam, Tanzania

Looking for
Backend, platform, or full-stack product engineering
Domains
Fintech, banking, insurance, and systems where correctness matters
Setup
Full-time or contract · remote or hybrid from Dar es Salaam
Time zone
EAT (UTC+3) — overlaps a full European day
Also happy to discuss
Open-source collaboration and system-design reviews

The message form loads as this section approaches. The direct email link remains available.