Backend and cloud engineer with two years of production experience building systems for external paying clients across logistics, healthcare, finance, and the public sector.
My ELT pipeline has run unattended in production since August 2025, processing ~750,000 records per nightly run. I've delivered four production systems end-to-end — architecture, AWS infrastructure, CI/CD, and post-launch support — without a separate DevOps function. On the logistics platform I lead a team of five.
Currently building:
- WhizzFleet — a greenfield multi-tenant fleet management platform for trucking and logistics clients. TypeScript monorepo, Express, Prisma, PostgreSQL. Multi-tenancy designed in from the first commit rather than retrofitted.
- Neo4j knowledge graph layer over the government-sector data lakehouse, modelling sector skills relationships for multi-hop traversal queries that relational multi-joins handle badly.
Architecture case studies — write-ups of the design decisions and trade-offs behind three client-confidential production systems, with no client-identifying detail: data lakehouse · logistics platform · pharmacy delivery
AWS services I've run in production
Lambda Step Functions Glue (PySpark) DMS S3 RDS EventBridge Elastic Beanstalk CloudWatch IAM Location Service Cost Explorer
Beyond AWS
- Backend — Node.js, Express, TypeScript, REST API design, OAuth 2.0, JWT auth
- Data — PostgreSQL, Prisma, Neo4j, PySpark, Kimball dimensional modelling, SCD Type 2
- Delivery — GitHub Actions CI/CD, least-privilege IAM, multi-environment release management
- Frontend — React, Vite, Chart.js
End-to-end ELT pipeline for a government-sector skills planning client. Azure SQL source → S3-backed raw, curated, and serving layers.
AWS Glue (PySpark) DMS Step Functions Apache Iceberg S3 RDS Neo4j
- ~750,000 records ingested per nightly run, unattended in production since August 2025
- 400 entities modelled in a Kimball-compliant dimensional schema with SCD Type 2 on Apache Iceberg, enabling point-in-time historical analysis across the full dataset
- PySpark transforms in Glue applying schema normalisation, data-quality validation, and deduplication before promotion from raw to curated
- Two-level Step Functions design separating ingestion from transformation, with exponential backoff, retry limits, and SNS failure alerting — so a broken run surfaces rather than silently serving stale data
Replaced a client's entirely paper-based operation. Led a 5-person team from requirements through to production.
Node.js PostgreSQL React Lambda EventBridge
- Re-architected from single-tenant to multi-tenant SaaS — row-level data isolation via
company_idacross all tenant-scoped tables, middleware-enforced tenant context on every authenticated request, and a redesigned auth layer. Live with 4 paying clients. - Statement aging recomputed live against outstanding items rather than carried forward from last month's closing balance, so every statement is a true point-in-time snapshot instead of an accumulated ledger
- Driver rates versioned with effective-date ranges, so historical invoices stay reproducible at whatever rate was in force when the leg actually ran
- Month-end statement generation triggered by EventBridge and Lambda rather than in-process cron, eliminating a 2-day manual finance process and decoupling the run from application uptime
Driver-facing delivery module of a production pharmacy dispensing platform — route sequencing, live tracking against a metered provider, and proof of delivery over an unreliable network.
Node.js PostgreSQL Prisma AWS Location Service React
- Closed a read-check-write race reachable through the offline queue by moving the condition into the update itself and letting the affected-row count decide the winner
- Ordered driver breadcrumbs by a server-assigned sequence rather than device timestamps, after unreliable device clocks produced traced paths that doubled back on themselves
- Cut metered geolocation spend with an address-hash geocode cache, per-leg routing in place of a distance matrix, and a write cadence that adapts to movement state — roughly 1,200 requests per driver-hour collapsed to one per flush window
- Durable client-side outbox (IndexedDB) so deliveries completed without signal replay in order, treating a 4xx as an answer to report and a network error as a condition to wait out
Unified revenue, expense, and P&L reporting across three structurally different accounting providers.
Node.js PostgreSQL Prisma OAuth 2.0 Chart.js
- Integrated Xero, QuickBooks, and Sage via REST, normalising three incompatible P&L report shapes into a single
{category, amount, date}schema plus a common monthly calculation - Three credential models handled on their own terms rather than forced into one abstraction — OAuth 2.0 with DB-persisted tokens and explicit refresh for QuickBooks, SDK-delegated OAuth for Xero, and AES-encrypted per-session credentials for Sage, whose reseller API offers only HTTP Basic auth
- Diff-based incremental extraction — three years back on first connect, one year on refresh, writing only where the incoming amount differs, so a re-run is close to a no-op
- Excel P&L import pipeline as a fallback for clients without a supported accounting integration
| Bachelor of Information & Communications Technology — Cum Laude | Durban University of Technology · 2020–2023 |
I document architecture decisions, not just implementations — including the ones I got wrong. Every case study above has a section on what I'd do differently. I don't hand off to a DevOps team; I am the DevOps function.



