Skills

Rated by what I've shipped.

Most skill lists are a wall of logos. This one is a claim I can defend. Every entry says what I built with the thing and how far that took me, and where I'm shallow the meter is short and the note explains why. The low ratings are the reason you can trust the high ones.

Built & hardened in production Shipped with it, still deepening Learning, not yet shipped

01THE SCALE

What the ratings mean

So that a 4 from me means something specific rather than just confidence.

RatingWhat it means
I've built it, broken it, fixed it and run it in production. I could take responsibility for it on day one.
It's load-bearing in a deployed system I built and still maintain. I know how it fails, not only how it works.
I've shipped real features with it and I'm productive, though I still reach for the docs on the harder cases.
Wired up and working, but untested by scale, by an incident, or by anyone else's expectations.
I've studied it and I understand the shape of the problem. I haven't shipped it, and I won't claim I have.
02EVIDENCE

The skills, with the evidence attached

The code behind all of it is public: backend, web, mobile.

Backend engineering

Java 21 My strongest language. All 21 modules of RentManager's backend are modern Java: records for value types, sealed hierarchies where the domain has a closed set of cases, and the standard library where a framework isn't earning its place.
Spring Boot 3 Web, Data JPA, Security, Validation, Actuator and scheduled jobs, in a production deployment. I've tuned it to fit a 512 MB free-tier container without the scheduled payment sweeps failing to start.
Modular-monolith architecture Ports and adapters with explicit module boundaries. One ArchUnit rule currently enforces that the property module's application layer never depends on its infrastructure, so CI catches that particular drift rather than me remembering. The other modules rely on convention so far, which is a gap I'd rather name than paper over.
Spring Security · JWT / JWKS Clerk-issued tokens verified against a JWKS endpoint. The most important decision here was that the frontend sends a tenant id on every request and the backend ignores it completely, taking tenancy from the signed claim instead.
Multi-tenant data isolation Enforced at two layers instead of one. In a multi-tenant system a single missed where clause is a data breach rather than a bug.
Concurrency & idempotency A tenant tapping "pay" twice must not produce two charges. I've built idempotency windows, transactional boundaries around the ledger and a database-backed outbox. I also know which of those I'd want a second pair of eyes on.

Databases & data modelling

PostgreSQL Schema design, constraints that make invalid states unrepresentable, indexing, and an append-only rent ledger. A row is written once, and a mistake is corrected with a new linked reversal instead of an edit.
Flyway migrations 99 sequential migrations, the latest at V104, none of them edited after running against a database. You can read the migration history back as the schema's real history.
JPA / Hibernate Productive with entity mapping, fetch strategies and transaction boundaries. I'm still building judgement about when to stop fighting the ORM and just write the SQL.
Domain modelling The part I enjoy most. Leases, occupancies, ledgers, commissions and payouts all carry real-world rules, and getting the model wrong costs far more than getting the code wrong.

Frontend

TypeScript Client types are generated from the backend's own OpenAPI contract. Change a response shape in Java and the TypeScript build fails before anyone sees a broken screen.
React 19 258 components across four user roles, each seeing a different view of the same data.
Next.js (App Router) 62 routes, using server and client components, route handlers that proxy the backend, middleware-level auth, and a production build that's deployed.
TanStack Query Query keys, invalidation after mutations, and optimistic updates only where rolling back is safe. On anything touching money, that's rarely.
Tailwind CSS · design systems A consistent token-driven UI with light and dark themes. This portfolio is hand-written CSS with no framework behind it, which is its own kind of evidence.
Accessibility Keyboard paths, focus states, semantic landmarks and honest alt text go in as I build rather than afterwards. I haven't yet tested a full product with real screen-reader users.

Mobile

React Native · Expo A 44-screen RentManager app built on Expo Router, sharing the same generated API client as the web app. It runs, but I haven't published it to an app store yet, so that distribution step is still ahead of me.
Push notifications Chosen over SMS for most alerts because SMS costs money per message and push doesn't. That decision came straight out of what the product could afford.
Offline & secure storage Tokens live in the device keystore instead of plain storage, and connectivity detection means the app says it's offline instead of failing silently.

Payments & integrations

M-Pesa Daraja Both directions: STK push to collect rent, B2C to pay landlords out. Callbacks are the hard part. They arrive late, twice, or out of order, and the ledger has to stay correct through all three.
Clerk authentication JWKS verification, webhook handling for user lifecycle events, and role and organisation mapping shared by the web and mobile clients.
Africa's Talking SMS Sent through a database-backed outbox with a scheduled sweep, so a provider outage delays a message instead of losing it.
Kenyan tax rules (VAT, MRI) I read the Finance Act instead of a blog post, and built the module fail-closed, with every gate off until a human confirms it applies. I'm an engineer and not a tax adviser, and the software says as much.

Testing & quality

JUnit 5 · Mockito 1,588 tests across 261 test classes, written money-path first. Anything irreversible gets covered before the screen around it does.
Testcontainers Integration tests run against a real PostgreSQL container. An in-memory database that doesn't enforce the same constraints will happily pass a test that production would reject.
ArchUnit Architecture encoded as a test. A boundary that exists only in a diagram has usually been crossed already. Mine covers one module today, which makes it a start rather than a safety net.
Vitest · RN Testing Library Component and hook coverage on the frontend. It's thinner than the backend suite, and I'd rather say so than imply they're equal.

Infrastructure & delivery

Docker Multi-stage builds producing the image that runs in production, plus a Compose setup for local development against real Postgres.
Deploying a real system RentManager is live, with the API on Render, the web app on Netlify and Postgres on Neon, plus a keep-awake ping and scheduled encrypted backups. I put that stack together under a hard constraint: it had to cost nothing. There's a runbook for it.
Git & CI My daily driver, with GitHub Actions running the build and the nightly backup job.
Observability at production scale Sentry, health checks and structured logs are in place. What I haven't done is run a system through real load and real incidents, and that's the gap I most want a team to help me close.
Distributed systems Avoided on purpose. A modular monolith with a database outbox was the right call at this scale. Reaching for a message broker would have bought me a better architecture diagram and a worse system.
03NEXT

What I'm working on closing

The honest version of "areas for growth", listed in the order I care about them.

GapWhy it matters to me
Operating under real loadI've built a system carefully, but I've never watched one degrade at 3am. Metrics, alerting thresholds and knowing which dashboard to open first are things you learn on a team, which is the main reason I want to be on one.
Working in someone else's codebaseEverything I've built, I also designed. Reading into a large existing system, respecting conventions I didn't pick, and getting a first PR merged is a different skill, and I know it.
Code review, in both directionsSolo work has no second pair of eyes. I want my assumptions challenged by people who have been wrong in ways I haven't been yet.
Performance work with real numbersI've reasoned about query shapes and indexes. I've never profiled a slow endpoint under production traffic and made it measurably faster, which is the version that counts.
Open to work · available now

If that's the shape of engineer you need, let's talk.

Graduate and junior roles, internships and contract work. Remote anywhere, on-site in Kenya, or relocating. I'd rather you test these claims than take them on trust.