Vanvora

Quoting

How we run Vanvora's own quoting on the same stack we'd build for you

Every quote we send comes out of software we built for ourselves: a React portal, an ASP.NET Core API and a PostgreSQL database. This is what it replaces, how it works, and what building it taught us about quoting in a small business.

, Founder

Published

The system at a glance

Quote numbers
VNV-Q-2026-0001, never duplicated
Lines per quote
Up to 200, fractions allowed
Totals
Always recalculated on the server
What clients see
Sent quotes only, never drafts

What it replaces

Most small firms do this job by hand, with the tools already on the desk. This is that version, next to the system.

Without it

The usual version

  • Open the last quote in Word, save a copy, and hope every old price and client name gets changed
  • Work out the totals, discount and tax in a spreadsheet, then type them back into the document
  • Pick the next quote number by looking at the last file in the folder
  • Export a PDF, attach it to an email, and lose track of which version the client actually has
  • Chase the answer on WhatsApp, then scroll back for it when it is time to invoice

With it

With the system

  • A quote is a set of line items: service, description, quantity, unit price and tax
  • The server recalculates every total, so a figure edited in the browser is never the one that counts
  • The database issues the quote number, so two quotes can never share one
  • Sending emails the client a branded message with the PDF attached
  • The client opens, downloads, accepts or rejects it in their own portal, and we hear by email
  • Larger work gets a proposal: priced modules and a payment schedule that must add up to 100%

How it works

Step by step, in the order it happens.

  1. Start from the enquiry

    A quote can start with one button on the lead it came from, and stays linked to both the lead and the client.

  2. Add the lines

    Service, description, quantity (fractions allowed), unit price and a tax percentage per line. Up to 200 lines, in any currency, with an optional discount across the whole quote as a percentage or a fixed amount.

  3. Let the server do the maths

    Totals are always recalculated on the server, with any whole-quote discount spread across the lines. Any total sent from the browser is ignored, so the figure of record is always the server's.

  4. Send it

    A quote needs at least one line before it can be sent, and only drafts can be edited. Sending emails the client a branded PDF with our header, their billing details, the services table, totals and terms.

  5. The client decides

    They sign in to the client portal to open, download, accept or reject. Each download and decision is written to the audit log, and a decision emails our team.

  6. Revise without losing history

    Changing a sent quote means making a new version: a fresh draft with its own number and a link back to the one it replaces. A quote with a newer version cannot be deleted, so the record of what the client saw is kept.

Safeguards we built in

The parts nobody sees until something goes wrong. They are what make it safe to use with real clients and real money.

  • Totals are recalculated on the server, so a number changed in the browser changes nothing
  • Quote numbers are issued inside the database, so two people saving at once cannot get the same one
  • Drafts are never visible to clients
  • Asking for a quote you do not own returns the same 'not found' as one that does not exist, so guessing reveals nothing
  • Every client download and decision is recorded in an append-only audit log
  • A quote that has a newer version cannot be deleted
  • Sign-in uses 15-minute access tokens, and refresh tokens that rotate on every use

The stack

  • React portal
  • ASP.NET Core API
  • PostgreSQL
  • QuestPDF
  • Azure Communication Services email

What we learned

What building it taught us, and what we would tell anyone building the same thing.

  1. 01

    The number on the PDF has to be the number in the database. Recalculating totals on the server is a little more work to build, and it means the figure a client accepts is always one we can stand behind.

  2. 02

    Editing a sent quote is the wrong feature. A new version with its own number keeps a clean record of what the client saw and when, and that record matters most on the day there is a disagreement.

  3. 03

    A button is easier to answer than an email. Accept and reject in the portal give the client one obvious next step, and give us a clear decision on record instead of a 'sounds good' buried in a thread.

  4. 04

    Keep the quote simple and put the richness in a proposal. Plain line items suit most jobs; larger work gets modules and a payment schedule, rather than one form that tries to do both.

Questions this usually raises

In our system they sign in, because accepting a quote is a decision we want tied to a named person and recorded. For your business it depends on who your customers are. Some would happily use a login; for others a secure emailed link is the better fit. We decide that with you, not by default.

Ours applies a tax percentage per line and an optional whole-quote discount, as a percentage or a fixed amount. That covers a lot of small businesses. If your rules are more involved, that is part of the build and we would scope it with you before quoting.

Want a system like this in your business?

The first conversation is free. We look at how the work runs today and send a written summary of what we would build first, whether or not you go ahead.