Skip to content
John Ndigirigi
WorkAboutWritingResumeContactBook a call (opens in a new tab)
  • Work
  • About
  • Writing
  • Resume
  • Contact
Book a call (opens in a new tab)
John Ndigirigi

Full-stack & AI Engineer · Nairobi, working remotely worldwide.

  • Work
  • About
  • Writing
  • Resume
  • Contact

© 2026 John Ndigirigi

Built with React + Vite + Tailwind

All work

Case study

QuoteKamili

Quote requests in any format become complete, priced quotes in under a minute, and every price is calculated in tested code rather than by the model.

Role
Founder & Lead Engineer
Dates
Sep 2026 – Present
Links
  • quotekamili.com (QuoteKamili site, opens in a new tab)
Stack
  • TypeScript
  • React
  • Node.js
  • PostgreSQL
  • pgvector
  • AWS ECS Fargate
  • AWS RDS
  • AWS CDK
  • Capacitor
  • Tauri
  • Vitest
  • Playwright
  • fast-check
  • axe-core

The problem

Trade and industrial suppliers in the UK, Ireland and the US, from electrical and plumbing to building materials and metals, get requests for quotes in every format: emails, PDFs, faxes, scans, spreadsheets, photos of handwritten lists, bills of quantities. Turning each one into a priced quote means hours of retyping lines, looking them up in the supplier's catalogue, and remembering the delivery or cutting charge.

The obvious shortcut is to hand the whole request to a language model. But a quote is a commitment to a price. A model that misreads a unit or miscounts a total, or that sees a supplier's pricing, is a risk a supplier can't take.

What I built

  • An AI pipeline that reads requests in any format (emails, PDFs, faxes, scans, spreadsheets, photos of handwritten lists, bills of quantities, several purchase orders in one file) and matches each line to the supplier's catalogue, including customers' own part numbers. Correct one once, and it sticks.
  • Pricing in tested code. Prices, totals, unit conversions and fees such as delivery, cutting and minimum-order charges come from the supplier's own price lists and fee rules, never from the model, and supplier pricing is never sent to one. Missing fees and prices that differ from a contract or list are flagged.
  • Source tracing and review. Every quote line links to its place in the source document, and a rep approves each quote before it goes to a customer or the ERP.
  • Sending and export. An approved quote goes out as a branded PDF from the supplier's own email, phone or WhatsApp, with a notice when the customer opens it, or as an import file for their ERP.
  • Safe handling of customer documents. Text inside a document is treated as content, never as instructions, and every file is checked for malware and opened in isolation. Customer data never trains AI models, the service that reads requests keeps nothing afterwards, and data is stored and read in EU data centres, encrypted in transit and at rest.
  • A multi-tenant platform on AWS (ECS Fargate, RDS PostgreSQL with pgvector, CDK) with row-level security in the database.
  • Idempotent background jobs, so a retry never creates a duplicate quote or charge.
  • Property-based tests (fast-check) on pricing and credit rules, and UI tests in real Chromium, WebKit and Firefox across time zones with Vitest, Playwright and axe-core.
  • One React codebase, shipped to web, to iOS and Android through Capacitor, and to desktop through Tauri.

How it works

QuoteKamili: from quote request to priced quoteA request arrives as an email, a PDF purchase order, a photo of a handwritten list or a fax or scan. A model reads the request into lines. Each line is matched to the supplier's catalogue. Tested code calculates prices, fees, totals and unit conversions, and supplier pricing is never sent to a model. A rep reviews the quote, with every line linked back to its place in the source, and approves it. The priced quote then goes to the customer or the ERP.REQUEST, ANY FORMATEmailPDF purchase orderHandwritten list photoFax or scanModel reads the requestTurns it into lines: item, quantity, unitCatalogue matchingEach line matched to a catalogue itemPricing in tested codePrices, fees, totals, unit conversionsSupplier pricing never sent to a modelRep review and approvalNothing goes out unapprovedPriced quoteTo the customer or the ERPEvery line links to its sourceModel (reads only)Tested code
From request to quote. The model only reads the request. Prices, fees, totals and unit conversions run in tested code, and a rep approves every quote with each line linked back to its source.

Key decisions

  1. The model reads; code prices

    Instead ofLetting the model produce prices and totals

    The model only extracts what the customer asked for. Prices, fees, totals and unit conversions run in code covered by property-based tests, so the same request always gets the same price, and supplier pricing is never sent to a model.

  2. A person approves every quote

    Instead ofSending quotes out automatically when extraction looks confident

    Every quote line links to its place in the source document, so a rep can check each line against what the customer actually wrote. Nothing reaches a customer or the ERP until a rep approves it.

  3. Document text is content, not instructions

    Instead ofPassing a document's text to the model as if it were part of the prompt

    Customers' documents can contain anything, including text written to steer a model. QuoteKamili treats everything inside a document as content to read, never as instructions, and opens each file in isolation after a malware check. With prices outside the model's reach and a rep approving every quote, a hostile document can't change what a customer is charged.

  4. Tenant isolation in the database

    Instead ofFiltering by tenant in application code only

    A supplier's catalogue and pricing are the most sensitive data in the system. Row-level security in PostgreSQL enforces isolation in the database itself, so one missed filter in application code can't expose another tenant's data.

  5. Idempotent background jobs

    Instead ofAssuming each job runs exactly once

    Background jobs get retried after timeouts and failures. Every job is idempotent, so a retry never creates a duplicate quote or charge.

Results

Requests that took hours of retyping become complete, priced quotes in under a minute. Every price and fee comes from tested code, every line can be traced back to the customer's document, and nothing goes out without a rep's approval.

Screenshots

QuoteKamili's share card: "Fast, accurate quotes from any customer request. Built for trade and industrial suppliers." A three-line faxed order becomes a quote with each line priced, a delivery charge added and a total excluding VAT.
QuoteKamili in one picture: a faxed order becomes a priced quote, with the delivery charge added from the supplier's own fee rules.
The QuoteKamili site: a faxed purchase order from an electrical contractor and the quote drafted from it, with matched, priced lines, two lines flagged to check, and a delivery fee.
A faxed purchase order becomes a drafted quote. Lines show where they came from in the PO, and unclear ones are flagged to check before a rep approves.
Next →Children's digital wellness app