Shipped work

Software engineering & featured work

Production platforms I built end to end, and I spend the rest of my time proving how platforms like them fail. The security work is not a side interest; it is my quality control.

FLAGSHIPCORPORATE PLATFORM

B-Lord Group

blordgroup.ng

I built the official B-Lord Group website from the ground up. It is a public-facing platform for a group whose name carries weight across entertainment and business in Nigeria, which meant it had to load fast on a mobile network, read clean on first contact, and give an attacker nothing to work with.

Architecture & information design

Mapped the group's divisions into a structure a first-time visitor can navigate in one pass, then built the page hierarchy and content model around it.

Responsive front end

Built the interface to hold its shape from a small Android handset to a wide desktop. The majority of Nigerian traffic arrives on mobile, so that is the case I optimised first.

Back end & content delivery

Server-side wiring, forms and content plumbing, with page weight kept low enough to load quickly on a congested mobile network.

Deployment & hardening

Shipped to production, and I reviewed the security posture myself with the same eye I bring to breaking platforms like it. No exposed endpoints, no unauthenticated data paths.

Visit blordgroup.ng →
CLIENT
B-Lord Group
DOMAIN
blordgroup.ng
ROLE
Sole developer
SCOPE
Design → build → deploy
TYPE
Corporate platform
Case studies

Systems where the hard part was everything around the happy path

APPLIED AI · VECTOR SEARCHSole engineer

Prep50 Coverage

Semantic duplicate detection and exam forecasting over a ~40,000-question WAEC archive.

~40K
questions indexed
~2 min
verdict per paper
54-82%
of a paper with precedent
4
verdict tiers

Nigerian examiners recycle questions far more than published policy admits, but nobody could prove it: “is this a repeat?” was a human judgement made one question at a time. Drop in a new paper and this returns a per-question verdict in about two minutes: word-for-word template repeat, same concept reworded, or genuinely new.

WHAT BROKE, AND WHAT I DID ABOUT IT

Calibration killed the obvious design

The plan was cosine similarity above a threshold. Measuring first showed the 5th percentile of true repeats (0.674) sat below the 95th percentile of unrelated questions (0.847), so no cutoff separates them. Cosine was demoted from a decision to a retrieval mechanism, and the hard verdict now needs a deterministic fingerprint match.

A question is not similar to itself

Re-embedding a question as a query and comparing it to its own stored vector gave a median cosine of 0.862 and never reached 1.0, a task-type asymmetry between RETRIEVAL_DOCUMENT and RETRIEVAL_QUERY. That single measurement invalidates the “just use cosine > 0.9” intuition, and moved the shipped thresholds from 0.92/0.80 to 0.80/0.75.

An LLM reranker that can never block a batch

Embeddings are lexically biased, so the top 20 candidates go to gpt-4o-mini with their answer options attached, because the options carry the meaning cosine cannot see. Any failure falls back to cosine ordering and keeps going, every score ships with a one-sentence reason for the reviewer, and it costs about a cent per batch.

PII already committed to git history

Auditing before open-sourcing turned up CSV exports of live user tables, with emails, phone numbers and addresses, committed months earlier. Fixed with a git filter-repo rewrite, verified by walking every object in the rewritten history rather than trusting the file listing. A private repo is not a security control.

STACK

  • Python
  • FastAPI
  • PostgreSQL 17
  • pgvector
  • Vertex AI
  • OpenAI
  • Next.js 16
  • React 19
  • TypeScript
  • Docker
  • Nginx
DATA ENGINEERING · DOCUMENT AISole engineer · ~10 months, ongoing

From exam paper to vector index

A six-stage pipeline turning two decades of WAEC and JAMB papers, from printed booklets to screenshots to inconsistent Word documents, into a classified, queryable corpus.

Private repo
55,106
questions in production
11,000+
extracted and verified
3,730
learning objectives
12
subjects covered

An exam-prep product is only as good as its question bank, and this one existed as paper: scanned booklets, tutor videos recorded off a projector, and Word documents typed by a dozen people across fifteen years. The interesting engineering is not the AI. It is everything built around the AI so that when it is wrong, and it is regularly wrong, nothing downstream silently breaks.

WHAT BROKE, AND WHAT I DID ABOUT IT

A one-character typo hid 793 questions

The uploader wrote to a prep50/ prefix; every downstream filter tested for pre50/. Nothing errored, no test failed, every run reported success, and 793 verified questions were quietly skipped for months. A filter clause that matches zero rows is now treated as a failure, not a valid result.

Two databases cannot share a transaction

Migration writes to production Postgres, then records the ID back in MySQL. Instead of pretending that gap does not exist, the Postgres insert and its objective link share one transaction, and a failure on the second write journals the new ID to a recovery file with enough context to reconcile by hand. Loud, bounded and repairable beats silent.

Knowing when not to call the model

Mathematics documents already carried human-authored subtopics, so sending them to an LLM would have been slower, costlier and less accurate than the people who tagged them. The classifier takes a direct path when an objective already exists: 425 of 445 questions on the last run matched production taxonomy exactly, at zero API cost.

Every destructive operation is a plan and an apply

Nothing mutates data in one step. The taxonomy cleanup planner is strictly read-only. It normalizes, groups duplicates, picks a canonical row by actual usage and writes a reviewable plan, flagging the risky cases. Only then does the applier run. It retired 202 objective IDs, 3 of which needed human judgement.

STACK

  • Python
  • GPT-4o vision
  • Gemini 2.5 Pro
  • EasyOCR
  • OpenCV
  • PyMuPDF
  • PostgreSQL 17
  • pgvector
  • MySQL 8
  • FastAPI
  • Docker
ML INFRASTRUCTURE · AWSSole engineer · design, build, operation

Textbook digitization pipeline

An event-driven GPU pipeline turning ~96 scanned curriculum textbooks into clean, structured Markdown, unattended, recovering from the failure modes of open-source ML inference at scale.

Private repo
~96
textbooks digitized
~31,000
pages processed
A10G
GPU worker, 24GB VRAM
0
recurrences after the fix

Scanned exam-prep textbooks, dense with tables, multi-column layouts and diagrams, that off-the-shelf OCR mangled badly enough to be unusable. A PDF leaves a field laptop, lands in S3, fires an SQS job, and a GPU worker returns structured Markdown with images preserved. No polling, no manual triggering, least-privilege IAM scoped per component.

WHAT BROKE, AND WHAT I DID ABOUT IT

Poison pages sent the model into runaway generation

Dense answer-key pages hung the VLM indefinitely. A live py-spy stack trace pinned it inside HuggingFace's _calc_banned_ngram_tokens, whose cost scales with what has already been generated. The fix kills the whole process group on a page-count-scaled timeout, because MinerU spawns its own child server and a naive kill would orphan it still holding GPU memory.

A leak that only appeared after days of uptime

A wave of unexplained crashes with nothing in dmesg or the kernel journal. The real signal was buried in the model server's own subprocess output: CUDA out of memory from VRAM fragmentation accumulating across hundreds of sequential invocations. One allocator setting fixed it, verified across a full backlog re-run.

Rejecting the clever fix on purpose

Recursively bisecting a failing chunk to isolate the exact bad page worked, and cost 45 to 75 minutes per book, because every bisection level pays its own full timeout. Against a 90-book backlog that is GPU time stolen from 89 other books. Fail-fast to a dead-letter queue won, and the rejected approach is documented so it does not get silently re-proposed.

Graceful degradation instead of total loss

A chunk timeout used to cost the entire remaining book. Now it drops to one page at a time under a smaller timeout and skips only the pages that are genuinely unprocessable, marking each one as a red callout in the viewer so QA goes straight to it. Books that would have been a total loss now land complete with a handful of flagged pages. One hit this three times and still produced 372 files.

STACK

  • Python
  • Bash
  • AWS EC2
  • S3
  • SQS + DLQ
  • IAM
  • CloudWatch
  • systemd
  • MinerU
  • PyTorch / CUDA
  • Flask
  • py-spy
Also built

Other notable work

SECURITY TOOLING

Disclosure workflow tooling

Scripts and report templates that turn raw findings into structured, reproducible reports, the format that got a national CERT to validate a finding in 48 hours.

  • Python
  • Automation
  • Reporting
WEB APPLICATIONS

Client platforms & dashboards

Authenticated web applications with role-based access control, audited data flows and an authorisation model designed before the first endpoint is written.

  • JavaScript
  • REST APIs
  • RBAC
PRODUCT SITES

Marketing & brand sites

Fast, accessible, search-visible sites for organisations that need to be taken seriously the moment the page loads.

  • Next.js
  • Tailwind CSS
  • SEO
Toolkit

What I build and break with

FRONT END

  • JavaScript
  • React
  • Next.js
  • Tailwind CSS
  • HTML5
  • CSS3

BACK END

  • Node.js
  • PHP
  • Python
  • REST APIs
  • MySQL
  • Auth & RBAC

SECURITY

  • Burp Suite
  • Nmap
  • OWASP Top 10
  • Access-control testing
  • API recon
  • Threat modelling

DELIVERY

  • Git
  • Linux
  • CI/CD
  • Cloudflare
  • Performance
  • Technical SEO
Available for work

Have a system worth protecting, or one worth building?

Security assessments, responsible disclosure and full-stack engineering. Tell me what you are working on.