Adnaan Ismail · Full Stack Engineer
Open to junior full stack, AI
TypeScript front to back · Postgres underneath · LLM pipelines in production · Durban, South Africa
Shipped and live
5 products
Real domains, real DNS, real users. Every link on this page opens.
Core stack
TS · React · Node
Next.js App Router, Prisma, PostgreSQL, Express.
AI in production
Vision + evals
Structured outputs, prompt and context design, model graded evaluation.
How I have worked
Solo, 3 years
Schema to UI with nobody to catch my mistakes. Now I want code review.
01Live right now, click any of these
rent-invoicer.vercel.app
Full stack invoicing dashboard. Next.js 16, Prisma, Postgres, server generated PDFs, deployed on Vercel. The login is what you will see, because behind it is a real client's tenant data.
LIVEPASSWORDWalkthrough on request
essconreadymix.co.za
Ready mix concrete supplier. Hand coded, no framework, mobile first, deployed to Cloudflare Pages from the CLI.
LIVEClient work
washrdetailing.co.za
My own mobile detailing business. Storefront, direct booking, and the marketing system behind it.
LIVEFounder
zephyrops.co.za
Astro 5 on the Cloudflare adapter. Contact endpoint reads secrets from the Worker runtime with a local dev fallback. The hero respects prefers-reduced-motion.
LIVEOwn brand
saas.zephyrops.co.za
Lead capture funnel on its own subdomain. Custom domain through Cloudflare, form wired to a real inbox, tested end to end.
LIVEOwn brand
React Native
no URL to open
SplitSnap · mobile
Expo and React Native, so there is nothing to link. Receipt scanning through Claude vision with structured outputs. Happy to demo it live or screen share the build.
MOBILE APPDEMO ON REQUEST
02What I have built
1
Rent Invoicer
Multi property invoicing for 60+ tenants. Next.js 16, React 19, Prisma 6, Postgres, react-pdf
DEPLOYED
2
SplitSnap
Receipt to line items via Claude vision and structured outputs, behind an Express service
BUILT
3
Agency OS
Model graded evaluation harness, prompt and context engineering, MCP tool integration
IN DAILY USE
4
Client and personal sites
Astro, Shopify Liquid, hand coded static, Remotion programmatic video, all self deployed
4 LIVE
03The engineering, in detail
Rent Invoicer
01 · 2026
TypeScript · Next.js 16 App Router · React 19 · Prisma 6 · PostgreSQL · react-pdf · Tailwind v4 · Vercel
A property company was invoicing more than sixty tenants by hand every month. Rent, refuse, deposit fees, fifteen percent VAT, and the constant problem of somebody paying part of what they owe. Now that month takes one click.
Auth is a signed cookie verified in middleware before any route renders. PDFs are generated server side. The parts worth talking about are less about the stack and more about the modelling.
Multi tenancyEverything scopes to a Property: its own renters, invoice prefix and number sequence, banking details and VAT treatment. Renters are keyed @@unique([propertyId, unitCode]), which is what makes the CSV importer idempotent. Fix the spreadsheet, run it again, and it matches on property plus unit instead of quietly creating a second copy of every tenant.
Two VAT modesReal landlords do not price the same way. One building is tax exclusive and itemised, matching the invoices the client already sent from Xero. Another charges a flat all in rent with VAT already inside it. A single boolean on the property changes how every charge line, total and PDF renders, so the client did not have to change how they do business to use the software.
Derived balancesOutstanding is computed as openingBalance + Σ(charges) − Σ(payments) rather than stored as a running total. Nothing can drift out of sync, short payments carry forward on their own, overpayments become a credit. It removed a whole category of bug before it could exist.
Documents as recordsThe PDF is generated once and kept, not re-rendered on demand. A statement re-opened eight months later looks exactly like the one the tenant received, even if the rent or the banking details have changed since. For anything financial, a document is a record, not a view.
Why it is password protected
The live instance holds a real client's tenant names, unit numbers and outstanding balances, so it sits behind a login rather than open on the internet. The link above will show you the auth screen, which is the honest proof it is a real deployment. Happy to walk through the running app, the schema and the code in an interview.
SplitSnap
02 · 2026
TypeScript · React Native · Expo SDK 56 · Node · Express · Anthropic API · vision · structured outputs
Photograph a restaurant bill, tap who had what, everyone finds out what they owe. This is the project where I worked out how I want to build with a model.
The photo goes to an Express service, the service calls Claude with vision and structured outputs, and what comes back is typed line items rather than prose that then has to be parsed and hoped over. The API key lives on the server and never goes near the app bundle.
The model reads. It does not do arithmetic. Splitting is a pure function in src/lib/split.ts with its own tests. Shared items divide equally, tax and tip apportion by share, and cent rounding is reconciled back against the bill total so the parts always add up to the whole. A model that is ninety nine percent right about extracting text is genuinely useful. A model that is ninety nine percent right about money is just wrong, and the person holding the bill notices immediately.
TestabilityThe split logic is unit tested independently of the app and of the network, so the money rules can be verified without a phone, a camera or an API key anywhere in the loop.
Degrading wellThe whole flow runs end to end on a bundled sample receipt with no API key set at all. It made the app testable from day one and meant the interesting logic was never blocked behind credentials.
Where it standsScaffold builds clean and the flow works through to payment. Wallet payments are stubbed at the collect step, waiting on Stripe and an Expo dev build, since wallets do not run inside Expo Go. I would rather show you a stub I can explain than claim a checkout I have not wired up.
Agency OS
03 · 2026
Anthropic API · Claude Code · Cursor · MCP · rubric design · subagents · Node
A working system of Claude Code skills, subagents, hooks and MCP servers that runs the delivery side of my own business. It is the project that taught me the part of AI engineering that is not calling an API.
The problem it solves is quality control on generated output. A deterministic linter catches a banned word, a leaked placeholder, a formatting rule. What a linter cannot do is look at a plausible sounding statistic and ask where it came from. So the interesting piece is two graders that gate anything before it ships.
Claim graderTakes a piece of copy plus a file of verified claims, then extracts every concrete assertion in the text: numbers, named results, quotes, dated events, first person anecdotes. It classifies each as grounded, generic, or specific but unsupported, and only returns a pass when nothing in that last category survives. It exists because the failure mode of a language model writing marketing copy is inventing a testimonial that reads perfectly.
Hook graderScores the opening line of a piece against a fixed rubric across several dimensions, matched to a reference set of archetypes, and fails the batch if any single hook is weak. A rubric turns a taste judgement into something repeatable, which is what makes it an evaluation rather than an opinion.
Context designSkills load only when the task calls for them instead of everything being pushed into one giant prompt. Session hooks establish state at the start of a run. The practical lesson has been that most bad model output is a context problem before it is a prompt problem.
Tool integrationMCP servers wired in for commerce data and browser control, so the system can read real state rather than reason about a description of it.
This is also just how I work. Claude Code is my daily development environment, and I have gone past using it into configuring it: custom skills, subagents with their own tool permissions, hooks on session lifecycle.
Client and personal builds
04 · 2022 to 2026
Astro 5 · Shopify Liquid · Cloudflare Pages and Workers · Remotion · Shopify Admin API
Everything in section 01 is mine end to end: build, deploy, DNS, custom domain, SSL, and forms that actually deliver. Nobody hands me a pipeline.
Programmatic videoA Remotion project that renders square and vertical product promos from supplier photographs, driven from the command line rather than a timeline. Code as the source of truth for media, which meant a new product became a render instead of an afternoon in an editor.
Ecommerce depthShopify builds including custom Liquid sections and a theme's own component contracts, plus catalogue work through the Admin API.
Before developmentYears keeping a two thousand product retail catalogue accurate in Sage, which is where I learned that data quality is an operational problem before it is a technical one.
04Two things that broke, and what was actually wrong
!
A deploy that failed silently
Every push to Vercel stopped deploying. No build log, no stack trace, nothing failing. The cause was that the machine's default git author email did not match the GitHub account on the project, so Vercel refused before it ever started building. The message said Deployment Blocked and I had been reading it as Build Failed. Fixed by setting the repository's git author to the account's noreply address. The lesson was to read what the failure surface literally says before assuming which system is broken.
!
Knowing when to stop
I tried to run Rent Invoicer on Cloudflare Workers with OpenNext and D1. Three walls in a row: Windows could not build OpenNext because of symlink and wasm path handling, Prisma needed its engine free client generator to work on Workers at all, and the final one was the bundled worker exceeding the free three megabyte limit, because react-pdf and the Prisma wasm are both large and neither was optional. I moved the whole thing to Vercel and Postgres and shipped it. Persistence is a virtue right up until the constraint is structural, and reading the size limit properly would have saved me a day.
05Where I am strong, and where I am not yet
Confident
TypeScript, JavaScript, React, Next.js App Router, Node, PostgreSQL, Prisma, REST route handlers, Tailwind, Git. The set I reach for without thinking about it, and what Rent Invoicer is built from.
Working
Express, React Native and Expo, Astro, Shopify Liquid, Remotion, SQL, Java, C#. I have shipped with each of these. I would need a little ramp up before moving fast in them.
AI
Anthropic API, vision, structured outputs, prompt engineering, context management, model graded evaluation, MCP. Claude Code and Cursor are how I write software day to day, including building my own skills and subagents on top of them.
Cloud
Cloudflare Pages and Workers, Vercel, Prisma Postgres. I own my deployments, DNS and domains rather than handing them to somebody else.
Not yet
AWS. I have not shipped on it. Everything I have deployed has been Cloudflare or Vercel, the concepts carry over, but I would be learning the specifics rather than pretending otherwise. Same for Sentry and CloudWatch, where I have done the debugging without having used those particular tools. This is the first gap I would close.
TypeScriptReactNext.jsNodeExpressPostgreSQLPrismaReact NativeAstroTailwindAnthropic APIMCPEvalsCloudflareVercelGitAWS: learning
06Why this role in particular
A platform that drafts funding applications and carries the administration around them is a bigger version of a problem I have already built for. Rent Invoicer generates correct documents on a schedule where the rules are unforgiving, because a rounding error is not a failing test, it is a wrong invoice in a real tenant's hands. Forms, deadlines, money and a document that has to be right are familiar ground.
The division of labour described in the role is also the one I arrived at on my own. In SplitSnap the model reads the receipt and deterministic code handles the money. In Agency OS the model drafts and a grader checks it against evidence before anything goes out. Letting AI do the part that scales while a person keeps the part that carries judgement is not a policy I would have to be talked into.
I am early enough in my career to be taught properly, and I have spent the last three years being the only person who could catch my own mistakes. Working next to a CTO who has done this before, on a codebase with other people's standards in it, is exactly the thing I have not had yet and most want.