Thande Roy

Selected work

Things I've built.

Systems I build on my own time to go deeper than the day job allows.

Side project · Android app
Expense tracking at the source: M-Pesa

mTagger

An Android app that reads M-Pesa SMS, parses each transaction and files it with a rule engine that learns from your corrections. No accounts, no backend, no sync. Published on Google Play.

KotlinJetpack ComposeRoomHilt
Read the case studyHide the case study

The problem

Most Kenyans pay with M-Pesa, and the only record of that spending is a stream of SMS receipts. Budgeting apps want a bank login or your data on their servers. I wanted the categorised picture without either.

How it flows

  1. SMS arrives
  2. Parser
  3. Rules engine
  4. Room database
  5. Notification
  6. Confirm or override
  7. Learned rule

Decisions and trade-offs

Data stays on the device
No accounts, backend, sync or analytics, and cloud backup is disabled. CI pins the exact permissions the release build may hold, so a dependency can't quietly add one.
Guesses wait for an answer
Every guess waits in a review queue until you answer it. Three consistent corrections turn into a rule, and a correction says how many waiting payments it would also file before it does.
Money as BigDecimal
Amounts are stored as strings and handled as BigDecimal. Transactions are keyed by the M-Pesa receipt code, so reprocessing the same message is idempotent.
Versions from commit messages
Version numbers come from Conventional Commit prefixes, and one workflow builds the signed APK and the Play bundle, with release notes generated from the history.

Where it stands

Live on Google Play.

Open source
Price-time priority

Thande Stonks Exchange

The same price-time matching model as the London Stock Exchange's SETS order book, built small to understand it. A continuous matching engine written in Rust: per-symbol engine shards over tokio channels, a BTreeMap order book with price-time FIFO matching, a 4-check pre-trade risk pipeline, write-ahead-log + Postgres trade persistence, and a real-time WebSocket market data stream. 70 tests, Dockerised.

Rusttokioactix-webPostgreSQLWebSocket
Read the case studyHide the case study

The problem

I wanted to understand how an exchange actually decides who trades with whom: matching that is fair, risk checks that run before an order touches the book, and trades that survive a crash.

How it flows

  1. REST / WebSocket
  2. Pre-trade risk
  3. Per-symbol shard
  4. Order book + matcher
  5. Market data bus
  6. WAL + Postgres

Decisions and trade-offs

One writer per order book
Each symbol runs as its own tokio task fed by a bounded channel of 10,000 messages. A book has a single writer, so there are no locks on the matching path, and symbols spread across cores.
BTreeMap price levels
Price levels stay sorted, so the best bid and ask are an end-of-map lookup, and a FIFO queue at each level gives time priority.
Risk checks before matching
Four checks run first: symbol active, price collar, notional limit and position limit. Sessions can be opened, halted by a circuit breaker and resumed per symbol.
Write-ahead log, optional Postgres
Trades go to a length-prefixed write-ahead log. Postgres is an optional ledger behind it, switched on by a single environment variable.

Where it stands

Six crates and 70 tests, with Swagger docs and Docker Compose. Compared with the LSE it is missing opening and closing auctions, richer order types such as icebergs, binary protocols and replicated failover. Next are an auction with uncrossing and a benchmark of the matching core, so I can put real throughput and latency figures here.

Open source
One binary, one Postgres

AIS Tracker

A maritime intelligence platform in Go, running as one binary against one Postgres instance. Streams live AIS vessel positions over a WebSocket feed, detects port calls, geofence crossings and dark-vessel gaps, and surfaces it all on a Leaflet map. Along the way it pushes Postgres into PostGIS, TimescaleDB, pgvector and CDC territory.

GoPostgreSQLPostGISTimescaleDBpgvector
Read the case studyHide the case study

The problem

Tracking ships usually means a queue, a search engine, a pub/sub system, a vector store and a time-series database. I wanted to see how much of that one Postgres can do in a real system.

How it flows

  1. AISStream WebSocket
  2. Bounded channel
  3. Batched writer
  4. TimescaleDB + cache
  5. Queue workers
  6. REST, WebSocket, map

Decisions and trade-offs

Drop messages under load
When the ingest channel fills, it drops messages instead of pushing back on the socket, so a slow database never stalls the network read.
An UNLOGGED cache for current positions
"Where is it now" comes from an UNLOGGED last-position table that is rebuilt from the archive on startup.
Jobs on Postgres with SKIP LOCKED
Enrichment, port calls, geofences and anomaly scoring run as jobs claimed with SKIP LOCKED, so many workers drain the queue without a broker.
NOTIFY for alerts, replication for history
LISTEN/NOTIFY fires real-time alerts. Logical replication carries the durable change feed, because NOTIFY can't be replayed.

Where it stands

Twelve Postgres capabilities in one working system, from PostGIS and TimescaleDB to pgvector and CDC. The repo documents each one with a representative query and where it stops scaling.

Open source
Works offline

Luna

A GNOME Shell extension showing the current moon phase in the top bar. Phase, illumination, distance and lunar age are computed locally with the Julian Date algorithm, so it needs no internet. Published on extensions.gnome.org with 2,800+ downloads.

JavaScriptGNOME ShellAstronomy
About

I'm a backend engineer who cares about reliability, observability, and architecture that's safe to change and scale.

For five years I've built and led production Python/Django systems in health-tech. That includes multi-tenant platforms, data pipelines processing millions of records daily, and API integration and identity layers holding it all together. I drop into Rust and Golang for the performance-critical paths.

I follow proper TDD with pytest and prefer a written RFC before significant code changes. I currently lead a product engineering team of six, and work best with real ownership in async-remote environments.

  1. 01

    Health-tech, Insure-tech domains

    Insurance, claims and data privacy, across many tenants.

    • OAuth2 / OIDC
    • Microsoft Entra
    • IAM
    • ABAC
    • OWASP Top 10
    • Multi-tenant Architecture
  2. 02

    Test Driven Development

    Tests first, and nothing merges until the pipeline is green.

    • pytest
    • TDD
    • CI-gated pipelines
    • GitLab CI/CD
    • GitHub Actions
  3. 03

    RFC/PRD Driven Design Process

    Sound architectural decisions, written down before the code.

    • Python
    • Django / FastAPI / Flask
    • Django REST Framework
    • REST, SOAP, gRPC
    • Celery, Redis, RabbitMQ
    • SQLAlchemy, Django ORM
    • SQL, PostgreSQL / MySQL
    • TypeScript / JavaScript, React
  4. 04

    Performance, Observability & Reliability

    Data-driven optimisation, with Rust and Go on the hot paths.

    • Rust
    • Go
    • Sentry, Grafana, Loki, Alloy, Prometheus
    • Kubernetes / Docker
    • Terraform, Ansible
    • AWS, GCP cloud environments
    • Incident management
Get in touch

Let's build something impactful.

I'm open to senior backend and platform roles, remote-first or on-site in Nairobi. Email is the fastest way to reach me.