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.