Skip to content
Back to work

Nova Bill

Lab invoicing that satisfies the Saudi tax authority and cannot quietly be altered

The Nova Bill invoice screen in Arabic
Status
Internal
Role
Solo developer
Client
Nova Dental Lab, Jeddah
Timeline
May 2026 – August 2026
Stack
Next.js, React, TypeScript, Supabase, PostgreSQL, shadcn/ui, Tailwind CSS, React Hook Form, Zod, ZATCA e-invoicing, jsPDF, ExcelJS, Arabic RTL layout

A management and invoicing system for the dental laboratory at Nova International Medical Complex. It issues simplified tax invoices that meet ZATCA requirements, links credit notes to the invoices they correct, and keeps an audit trail that no role can delete from.

Highlights

  • Invoices carry the QR code ZATCA requires, encoded in the TLV format the specification defines, so a tax inspector can scan one and read the seller, the VAT number, the timestamp and the totals.
  • Each invoice is hashed and chained to the one before it, so altering an old invoice breaks every hash after it rather than passing unnoticed.
  • Nothing is ever deleted. A mistake is corrected by a credit note that points at the original, which is what an audit trail means in practice.
  • Four roles, from administrator to employee, get per-page create, read, update and delete permissions enforced by row level security in the database, not only in the interface.
  • Accountants get a posting workflow and a tax report, and every table exports to PDF or Excel, because that is how the finance office actually works.
4
Roles with distinct permissions
12
Pages in the system
0
Invoices deletable by any role — Corrections go through credit notes

This handles a real business's invoices, so it is not publicly reachable and the recording uses demonstration data. I can walk through it on a call.

The problem

The lab invoiced its clinic clients on spreadsheets. Totals were recalculated by hand, outstanding balances were whatever the last person remembered, and a corrected invoice was simply an edited file.

Saudi e-invoicing rules are not optional, and they are specific: a defined QR payload, invoice integrity, and records that survive an audit.

The approach

I treated the tax specification as the schema rather than as a feature. The QR payload, the field lengths and the hash chain were built first, and the interface was fitted around what a compliant invoice has to contain.

Deletion was removed from the design entirely. Every correction is an additional record that references what it corrects, which is both the legal requirement and the only honest way to represent a mistake.

Permissions live in the database. Row level security means a request with the wrong role gets nothing back even if it bypasses the interface completely.

Results

The lab issues compliant tax invoices, tracks partial payments against each clinic's balance automatically, and can produce the tax report the accountant needs without assembling it by hand.

Compliance is a data-model decision, not a checkbox

It is tempting to treat a rule like ZATCA's as a formatting step applied on the way to the printer. It is not. Hash chaining only means anything if nothing can be edited behind it, and that constraint reaches every table, every mutation and every role in the system.

What I would carry forward

  • Designing a system that cannot delete forces you to decide what a mistake actually is. That question turned out to shape the whole data model.

Watch the walkthrough