01
The page you edit is the page you print
The form sits beside an A4 preview that updates as you type. The preview is the same page that gets printed, and the app does its own A4 page breaks, so the PDF has exactly the pages you saw.
A private invoicing app for AED and INR tax invoices from several businesses, with five print designs and a PDF that matches the screen page for page.
[01]
// THE PROBLEM
Why it exists
One owner sends tax invoices from several businesses: some in dirhams with UAE VAT, some in rupees with GST split into CGST and SGST. Each business has its own numbering, details and look.
The PDF a client receives has to match what was written, down to the last fil or paisa, and the invoices themselves are private: there's nothing to share publicly.
[02]
// WHAT I BUILT
The rules
01
The form sits beside an A4 preview that updates as you type. The preview is the same page that gets printed, and the app does its own A4 page breaks, so the PDF has exactly the pages you saw.
02
Editorial, Minimal Swiss, Modern Accent, Classic and Corporate. Each business picks a default, and any invoice can switch.
03
Amounts are stored as whole fils and paise, multiplication goes through exact decimal maths, and each line is rounded once. Rupee invoices use Indian grouping (₹6,78,500.00) and lakh and crore in words.
04
No tax, a single tax such as VAT 5% or IGST 18%, or two taxes such as CGST 9% + SGST 9%, each rounded on its own line.
UAE
India
05
Each sending business has its own logo, signature, tax ID, payment details, number series and design. Every invoice keeps a snapshot of both parties as they were on the day it was written.
06
Passwords are hashed with scrypt and a secret pepper. Accounts lock after repeated failures, per account and per network address. Sessions end after 12 hours idle or 7 days at most, and only a hash of the session is stored. Changing the password, exporting everything or restoring a backup asks for the password again.
[03]
Request path
Amounts are integers of the smallest unit and totals are always recomputed on the server, so a rounding error can't creep in between the screen and the PDF.
There's no shared middleware to forget. Each page, route and action checks the session, and a test plus a logged-out end-to-end run enforce it.
A backup file is fully checked before import, totals are recomputed rather than trusted, and a copy of the current data is saved first. The last ten copies are kept.