Skip to content
Open to AI implementation, consulting and solutions roles

Bhavesh Narsai

Technical Consultant AI-Assisted Builder Problem Solver

I spent nine years taking other people's software apart to prove it could be rebuilt. Now I use AI to help me build my own.

My background is IT support, software escrow verification and technical consulting, not a computer science degree and a decade of shipping features. What I already had was the habit of picking up unfamiliar systems, working out how they really fit together, and taking problems through to an answer with the people involved. AI-assisted development turned that into the ability to build working software myself. This page is what that looks like in practice.

Download this page as a PDF (A4, 10 pages)
The Story

An extension, not a reinvention

AI did not turn me into a different person. It gave the person I already was a way to build things. Each stage below left something behind that I still use every day.

  1. 2013 to 2014

    IT Support

    Antler, Vita Cellular Foams

    Gave me Troubleshooting and systems thinking. Someone has a problem now, on a system you did not build.

  2. 2014 to 2019

    Software Verification

    NCC Group

    Gave me Reading unfamiliar code, testing it, and finding out on client sites what a build really depends on rather than what the documentation claims.

  3. 2019 to 2023

    Technical Consulting

    NCC Group

    Gave me Clients, requirements and delivery. Helping turn around a service line and grow its team from two people to five.

  4. 2024 onwards

    Independent Consulting

    BAV Tech Solutions

    Gave me Ownership. Pricing the work, selling it, supporting it, and solving problems that have to make commercial sense.

  5. Now

    AI-Assisted Building

    SaaS, automation, tools

    Gives me The ability to turn an idea into working, deployed software myself, quickly, and then keep it running.

Selected Builds

Things I have built and run

Small products, built for real local businesses, with payments, logins and other people's phone numbers involved. Open any of them for the case notes: what the problem was, how it is put together, where AI helped and where it needed checking.

SmartReply

In production

Missed-call auto-SMS for small businesses. When nobody can answer, the owner gets an alert, the caller gets a text back, and the lead is recorded.

  • FastAPI
  • Supabase
  • Postgres RLS
  • Twilio
  • Stripe
  • Docker
  • Nginx
  • pytest

The problem

A tradesperson up a ladder cannot answer the phone, and the person ringing usually tries the next number on the list. A missed call is often a missed job.

The approach

One FastAPI service reacting to Twilio's call status webhook, with Postgres doing the consistency work. Multi-tenant from the start: each business has its own Twilio subaccount and number, so the number that was called identifies the tenant.

Architecture

  1. Caller
  2. Twilio number
  3. Nginx, HTTPS
  4. FastAPI webhook
  5. Supabase Postgres
  6. SMS to owner and caller

Walk through every decision on this request path further down the page.

AI's role

Built with AI coding assistants throughout. The commit history shows the webhook engine, invites, auth and Stripe billing landing over two days of sprints in February 2026. A hardening pass in May went back over all of it, and that is where most of the fixes below came from.

My role

Setting the constraints: one service, no queues or extra infrastructure, tenant isolation on every query, and a webhook that must never fail loudly. I wrote those down as project rules for the AI assistant, so every change starts from them.

Challenges

  • Twilio can deliver the same event more than once. A database function now acquires a per-caller cooldown atomically, so a caller cannot be texted twice in quick succession.
  • A route ordering bug where /contacts/all was being matched as a phone number by /contacts/{phone_number}.
  • The admin basic-auth check was not actually rejecting bad credentials. Admin routes are now gated at Nginx instead.

Security and quality

  • Twilio signatures validated per tenant, with that tenant's own token.
  • Row level security on every table. Anonymous access denied; signed-in users read only their own business's rows.
  • Stripe webhook idempotency, a CSRF origin check on checkout, phone numbers masked in logs.
  • A pytest suite covering the webhook's short-circuit paths and helpers.

What I would take forward

The first version worked. The second version was safe. Idempotency, log redaction and tests all arrived in a hardening pass, and they belong in the first one.

ReviewPing

In production, invite only

SMS review requests for trades and local businesses. Send one from the dashboard, or let a job system trigger it through a private webhook.

  • Next.js
  • TypeScript
  • Clerk
  • Turso
  • Drizzle
  • Stripe
  • Twilio
  • Upstash
  • Vercel

The problem

Small businesses get reviews when they remember to ask, which is not often. A text straight after the job works, but only if it happens every time.

The approach

Two ways in: a manual send from the dashboard, or a per-business secret webhook URL that tools like Zapier or Make can post to. A Stripe subscription sets the monthly SMS allowance. Serverless on Vercel, so nothing assumes a long-running process.

Architecture

  1. Dashboard or webhook
  2. Clerk auth or secret
  3. Rate limit
  4. Opt-out check
  5. Atomic quota reserve
  6. Twilio
  7. Log

AI's role

Built in short sprints with AI assistance. Auth, settings, the webhook engine and the full Stripe subscription lifecycle came together in the first week of March 2026. Later work was mostly refactoring and review: pulling duplicated send logic out of two route handlers into one tested path.

My role

Product and compliance decisions. Who can send, to whom, how often, and what happens when someone says stop. The project rules tell the assistant which parts are off limits: auth, signature checks, rate limits and the opt-out path.

Challenges

  • The quota check had a race: two concurrent sends could both slip under the limit. Replaced with a single conditional UPDATE that reserves the slot before sending and releases it if Twilio fails.
  • The plan limit was defined in two places with two different values. Consolidated to one source of truth.
  • UK alphanumeric sender IDs are one way, so "Reply STOP" cannot work. Branded messages now link to a web opt-out page instead, backed by a platform-wide suppression list checked before every send.

Security and quality

  • Clerk middleware on the dashboard, settings and admin routes.
  • Rate limiting on the webhook and send API, in case a secret URL leaks.
  • Stripe and Twilio signature verification; zod validation on input.
  • Critical auth-bypass CVEs in the auth and framework packages patched, and key dependencies pinned, with a written dependency update routine.

What I would take forward

SMS is regulated territory. Opt-outs, sender ID ownership and consent took as much thought as the product itself, and they are not things an assistant will raise unless you ask.

Local Enquiry Audit

localenquiryaudit.co.uk

A scored audit of how a local business shows up online, with a free preview and a paid full report that reads the business's own website.

  • Next.js
  • TypeScript
  • Prisma
  • Postgres
  • Stripe
  • Search APIs
  • Vercel cron

The problem

Local businesses lose enquiries without knowing why. No Google listing, too few reviews, no tap-to-call button, a website that never says which town they work in.

The approach

Find the business online, score what exists, and explain it in plain English. A readiness crawl reads the homepage plus up to four key pages, runs checks over what it actually found, and rolls them up into five questions a business owner would ask.

Architecture

  1. Audit form
  2. Discovery: search and places
  3. Scoring engine
  4. Postgres
  5. Free preview
  6. Stripe checkout
  7. Full report and crawl

AI's role

AI helped build it. It is deliberately not inside it. Every finding is a deterministic check over pages that were actually fetched, and the checks stay quiet when unsure rather than guess. A language model writing the findings would have been quicker to build and harder to trust.

My role

The scoring model and the honesty rules. Findability and contact count for most because those decide whether an enquiry happens. The report never implies it tested live rankings or what an AI assistant says about the business.

Challenges

  • Discovery accuracy: matching the right business among similar names took several rounds of name matching, URL normalisation and validating local listings.
  • Discovery moved search providers part way through, and scoring moved onto real Google review data.
  • The discovery step costs money per call, so it is rate limited per IP in Postgres.

Security and quality

  • No customer accounts: the full report needs both an unguessable token and a paid status.
  • Admin by Google sign-in, restricted to one account, signed httpOnly session cookie.
  • Machine endpoints behind separate secrets.
  • A daily job deletes audits after 12 months, plus per-record deletion for erasure requests.

What I would take forward

If AI goes into the report later, it is for polishing the wording of findings a check has already proved, not for producing the findings.

Site Monitor

websitemonitor.app

Watches a website for the quiet breakages nobody notices, and emails the owner only when something that was working stops.

  • Cloudflare Workers
  • D1
  • Cron
  • HTMLRewriter
  • Resend
  • Stripe
  • Zero npm deps

The problem

Nobody re-checks a website once it is built. A plugin update strips the structured data, a redesign drops the tap-to-call link, and enquiries leak for months before anyone notices.

The approach

"The product is silence until something breaks." Each check is diffed against the last snapshot and only a change sends an email. The first check is a silent baseline, and a site has to fail three times in a row before it counts as down.

Architecture

  1. Hourly cron
  2. Due sites from D1
  3. Guarded fetch
  4. Parse and run rules
  5. Snapshot
  6. Diff
  7. Email on change

AI's role

Built with AI from a written specification rather than a loose prompt. The spec covers cadence, cost per check, what an alert says and what the product must never do, and the assistant works inside it.

My role

Product boundaries. It reuses the check engine behind the free website tools instead of forking it, it never crawls, never stores page HTML, and treats alert fatigue as the biggest product risk: any new check defaults to quiet.

Challenges

  • Scheduling without a queue: one hourly cron drains whichever sites are due, with uptime checked more often than full content.
  • Deciding what counts as a change worth an email, which is a product question more than a code one.

Security and quality

  • Fetching arbitrary URLs safely: timeouts, size caps, SSRF guards and re-validation of every redirect.
  • Admin behind Cloudflare Access; subscribers use magic links.
  • Zero-dependency Node test scripts covering the checks, the diffing and the domain logic.

What I would take forward

A clear spec is the best prompt. The more of the thinking happens before the assistant starts, the less of its output needs undoing.

First Impression Audit

bavtechsolutions.com

Opens a web page in a real mobile browser the way a first-time visitor would, taps the main button, and reports what actually happened, with a screenshot at every step.

  • Cloudflare Workers
  • Browser Rendering
  • Puppeteer
  • Queues
  • R2
  • D1
  • Stripe

The problem

Website checkers, including my own free one, read what is written on a page. They cannot tell you that the main button does nothing when tapped, or that the cookie banner covers half the screen on a phone. Only an actual visit finds that.

The approach

A £15 one-off audit, no account. A headless mobile browser lands on the page, screenshots it before touching anything, deals with the cookie banner, scrolls like a person, taps the main button, records the outcome and opens the enquiry form. The report is the screenshots in the order a visitor meets them, each with a plain English note.

Architecture

  1. Free scan
  2. Stripe checkout
  3. Signed webhook
  4. Queue
  5. Headless browser visit
  6. Screenshots to R2, facts to D1
  7. Findings
  8. Private report

AI's role

Built with AI assistance on top of the existing scanner. The commit history shows the audit, its landing page, the print view, refunds and promotion codes landing over two days in August 2026, followed by a pass to make the report consistent and credible.

My role

Separating evidence from judgement. One phase drives the browser and records raw facts, judging nothing. A second phase turns stored facts into findings and can re-run without a browser. Every finding traces back to a measurement, a screenshot or a recorded outcome, and the report never estimates what a fix would earn, because that number would be invented.

Challenges

  • Keeping the paid audit and the free scan from ever disagreeing. Both now run the same scoring code over the same parse of the page.
  • Deciding when a buyer gets their money back. Automatic refund when the audit failed to collect evidence; never because the page turned out to be broken, since finding that is the product.
  • Cloudflare's rate limiting is per location and approximate. Documented and proven with a diagnostic rather than assumed.

Security and quality

  • Stripe webhook signatures verified; jobs deduplicated on the checkout session, so a redelivered event cannot run twice.
  • Reports and screenshots served only behind unguessable tokens.
  • Hard caps on every run: a 120 second deadline with the browser always closed, plus limits on steps, screenshots and screenshot size.
  • Checkout rate limited, and only reachable from a valid free-scan token.

What I would take forward

Measure before paying for infrastructure. Cold browser launches measured under two seconds, so there is no warm pool and no fixed monthly cost, and because jobs only exist behind a payment, spend scales with sales.

Also built

Everything, live and in development: Software & tools · Free tools

  • Landing page conversion scanner

    Scores a page out of 100 on how well it turns visitors into enquiries. Quotes the actual headline, counts the actual form fields and names what is missing, with no predicted conversion rates. Runs on the shared Cloudflare Worker check engine that Site Monitor and the paid audit reuse.

    Scan a page
  • Contact checker Chrome extension

    Checks whether a customer can actually reach the business from the page you are on. Reads the fully rendered page, compares it with the raw code crawlers see, and measures the phone-screen view. Collects nothing, with the two narrowest permissions Chrome offers.

    About the extension
  • OrderFlow

    Multi-tenant takeaway ordering: a storefront per shop, collection orders, an owner dashboard and a live kitchen display. Next.js and Firebase.

    See it with the other apps
  • Transcript CLI with an LLM fallback

    Python tool that pulls YouTube captions first and only falls back to the Gemini API when there are none, parsing its timestamped output back into text, SRT or VTT.

  • Agent-ready repositories

    Every repo I maintain carries an AGENTS.md: stack, commands, layout and hard rules. Any coding agent starts with the same constraints a new engineer would get on day one.

  • Website build tooling

    Templates first, prompts only where no template fits, and a validator that fails a build containing an invented testimonial or an unsupported claim, because a model will happily write both.

How I Work

AI-first, not AI-only

AI speeds up the middle of the process a great deal. It does not change who is responsible for the start and the end. Pick a stage to see what it involves and where it showed up in the builds above.

Understand the problem before the tool

Who has the problem, what it costs them, what they have already tried, and what done looks like. Most of the useful decisions are made here, and none of them need code.

  • Business problem
  • Users
  • Constraints
  • Desired outcome
From the buildsSite Monitor's spec opens with the problem and the customer, and has one rule that overrides everything else in it: the product must complement the consulting work, never compete with it. Every feature is checked against that before it is built.
Consulting + Building

Two halves of the same job

Anyone can prompt a coding tool now. The harder part is knowing what to ask it for, and then explaining what was built to the person paying for it. I am most useful where the two overlap.

Consulting

  • Understanding ambiguous problems
  • Client and stakeholder communication
  • Translating technical concepts
  • Requirements
  • Investigation
  • Managing issues through to resolution
  • Working across technical and non-technical teams

Where I work best

  • Discovery that ends in working software
  • Getting to grips with an unfamiliar system fast
  • Explaining trade-offs to whoever signs them off
  • Taking a problem from report to fix
  • Helping people use AI tools well

Building

  • AI-assisted development
  • APIs and webhooks
  • Databases and permissions
  • Integrations and automation
  • Web applications
  • Docker, Linux and VPS
  • Debugging, testing, security awareness
A Real Technical Example

One missed call, step by step

This is SmartReply's actual request path, in the order the code runs it. It is a public endpoint that spends money every time it sends a text, so most of it is about deciding when not to. Pick a scenario to see which checks stop it, or select any component to see why it is there.

Scenario
  1. 1

    Was the call actually missed?

    Twilio reports every call status. Only no-answer continues.

    ignored_status
  2. 2

    Which business owns this number?

    The called number identifies the tenant. Unknown numbers stop here.

    no_client
  3. 3

    Did this really come from Twilio?

    Signature checked with that business's own subaccount token, not a shared one.

    bad_signature
  4. 4

    Is the service switched on?

    A per-business switch, so it can be paused without a deploy.

    bot_inactive
  5. 5

    Under this month's SMS limit?

    Usage is capped per business, so a bad day cannot run up a bill.

    sms_limit_reached
  6. 6

    Record the lead

    Logged for the dashboard. A failure here is logged and does not stop the texts.

    insert lead
  7. 7

    Alert the owner

    The owner always hears about a missed call, whatever happens next.

    sms owner
  8. 8

    Is the caller a saved contact?

    Uploaded contacts never get the auto-reply. Your supplier does not need a "sorry we missed you".

    known_contact_suppressed
  9. 9

    Outside the cooldown window?

    Acquired atomically in a Postgres function, so retries and repeat calls cannot double-text.

    cooldown_blocked
  10. 10

    Text the caller back, count the usage

    Sent from the business's own number on its own subaccount.

    ok

Choose a scenario to run it through the checks.

Every exit returns HTTP 200 with a reason code. An error response invites a retry, and a retry here can mean a second text to the same person. The reason goes to the logs, with the phone number masked.

Components

Caller
A customer ringing a business. They never see any of this. They just get a text back instead of silence.
Twilio subaccount number
Each business has its own Twilio subaccount and number. The number that was called is how the system knows which business this is, and each subaccount has its own credentials, so one tenant cannot sign requests for another.
Nginx on a VPS
Terminates HTTPS in front of the app, and gates the admin routes with its own authentication so the application does not have to get that right on its own.
FastAPI in Docker
One service doing one job. The webhook handler runs the checks in order, and never returns an error, because an error invites a retry. Deliberately no queue or extra moving parts: a small business tool should be cheap and boring to run.
Supabase Postgres
Holds tenants, leads, contacts, usage and subscriptions. The cooldown is acquired inside a database function so two near-simultaneous events cannot both win. Row level security on every table means a signed-in user can only ever read their own business's data.
Stripe
Subscriptions and checkout. Its webhook is idempotent: each event is recorded once, so a redelivered event cannot apply twice. Checkout also checks the request origin.
Dashboard
Where the owner sees missed calls, usage and status. Contacts who should never get the auto-reply can be loaded from CSV, VCF or plain text. Sessions follow Supabase Auth token lifetimes, with refresh rotation.

Select a component

Each one is there for a reason. Most of the reasons are about what happens when something goes wrong.

AI + Human Judgement

AI can generate the implementation in minutes. The harder questions are still there.

  1. 01Should this exist at all?
  2. 02What problem are we actually solving?
  3. 03How should the system be structured?
  4. 04What data should it be able to touch?
  5. 05What happens when something fails?
  6. 06Is the generated code secure?
  7. 07Can another person understand it?
  8. 08How do we know it actually works?

None of that is generated for you. It is judgement, and judgement is built rather than prompted. I wrote more about this: AI has not replaced learning, it has accelerated it

Career Foundation

The building sits on ten years of the other bit

Nine of those years were at NCC Group in software escrow verification: taking client software I had never seen, working out what it really needed to build, and proving it could be rebuilt from source in an independent lab without the original developers.

That meant working through each client’s own codebase and build toolchain, visiting development teams in the UK and abroad, and writing it all down so somebody else could repeat it. Before that, first and third line IT support.

10+

years in software and IT

9

years at NCC Group

2→5

build team grown

  1. 2024 to nowIndependent Technical ConsultantBAV Tech Solutions Ltd
  2. 2019 to 2023Software Build ConsultantNCC Group
  3. 2015 to 2019Verification ConsultantNCC Group
  4. 2014 to 2015Integrity Test AnalystNCC Group
  5. 2014IT Analyst / Developer, contractVita Cellular Foams
  6. 2013IT Support Assistant, contractAntler

BSc (Hons) Business Information Technology, University of Salford. Azure Administrator Associate (AZ-104), AWS Cloud Practitioner, Google IT Automation with Python, ISTC-accredited technical writing.

Have an interesting problem?

Let's talk.

contact@bavtechsolutions.com · Bolton, Greater Manchester · remote across the UK