Skip to content

Stack

One honest sentence per tool about how I actually use it. No proficiency bars — a self-assessed score out of five tells you nothing you can act on, and the second section below is more useful than the first.

Backend

NestJS
My default for anything that will outlive the first release — modules, DI and DTO validation earn their keep once more than one person touches the code.
Node.js
Most of what I know about backpressure and memory came from getting streams wrong first.
TypeScript
Strict mode, no implicit any. The types are for the next person, who is usually me in four months.
Express.js
What I reach for when the service is genuinely small and a framework would be ceremony.
REST API design
Resource-shaped routes, correct status codes, a consistent error envelope, and a documented contract before the first client is written.

Data

PostgreSQL
Schema design and query work — most of my latency wins have come from reading a query plan rather than adding a cache.
MongoDB
Used where the documents genuinely were documents; the e-commerce catalogue was a fair fit.
MySQL
Product and variant synchronisation for a catalogue importer.
Prisma ORM
Schema, migrations and generated types. The generated client is what keeps the API and the database from drifting.
Sequelize
Older projects. Model definitions mirroring an existing schema I did not control.
Elasticsearch
Indexing and incremental sync for mailbox search — the interesting part is keeping the index consistent, not the queries.

APIs & documentation

OpenAPI / Swagger
On every project I have shipped. This site publishes its own spec — that is the fastest way to judge whether I mean it.
Postman
Collections kept alongside the spec so the documented contract and the tested one stay the same thing.

Security

JWT
Access and refresh token flows, short expiry, and rotation on refresh.
OAuth 2.0
Third-party authorisation flows including refresh paths that survive expiry without a human re-authorising.
Role-based access control
Server-enforced, checked at the boundary. Client-side role checks are a UI convenience, not a control.
Input validation
class-validator DTOs with a whitelist, so unknown fields are stripped rather than trusted.
Rate limiting
On every public write endpoint. The contact form on this site is throttled per IP for the same reason.

Integrations

Paystack
Invoicing and collection for a small-business payments service.
Stripe
Checkout and webhook handling, including raw-body verification before the JSON parser runs.
Wise / Airwallex
Cross-border payout flows.
IMAP / SMTP
Mailbox authentication and sync, and transactional delivery. SPF and DKIM are part of the job, not an afterthought.
LLM APIs
Claude and OpenAI in paid production workflows — vision, summarisation, transcription and recommendation. The engineering is in what happens when the model returns something malformed.

Delivery

Docker
Multi-stage builds, compose for local dev, health checks in the image.
GitHub Actions
Lint, typecheck, test, build, deploy. This repository runs the same pipeline.
Jest / Cypress
Unit and integration in Jest, end-to-end in Cypress. Coverage is a signal, not a target.
nginx / PM2
Reverse proxy, TLS via Certbot, process management. This site is deployed exactly that way.
AI-assisted development
Claude Code daily, across the stack. It is why I take full-stack tickets end to end instead of handing off the UI — and I keep it away from schema design, auth boundaries and anything touching money.

What I haven’t done

Kubernetes and orchestration
I have containerised everything I ship, but I have never operated a Kubernetes cluster in production. Docker and Compose are where my experience actually stops.
AWS / GCP
My production systems run on VPS infrastructure and managed platforms rather than deep AWS or GCP service estates. I know the deployment path I use end to end; I would be learning a large cloud’s primitives on the job.
Message brokers
I have used Postgres-backed job queues and cron for scheduled and deferred work, and Socket.io for realtime fan-out. I have not run Kafka, RabbitMQ or SQS in production.
Observability
Structured logging with Winston, and health checks. I have not run a metrics or tracing stack — no Grafana, no OpenTelemetry — and that is the gap I am closing first.

If one of these is a hard requirement for the role, that is worth knowing before either of us spends an hour on a call.