A static invoice/bill generator with cloud bill history and configurable saved items, built on the original PDF template. Zero server, zero monthly cost (Firebase Spark plan).
- New Invoice — same form as the original app. Produces a byte-identical PDF (same template, same jsPDF 1.5.3, verified draw-for-draw).
- Bill History — every printed invoice's metadata is saved to the cloud: dated, searchable, re-downloadable (identical PDF), duplicable as a new draft, deletable.
- Items — a preset manager that replaces the old fixed list of 6 products. Add unlimited products with default GSM / HSN / Size / Rate; picking one on an invoice auto-fills those defaults.
Only PDFs are regenerated on demand — never stored — because generation is deterministic. The cloud only holds lightweight metadata + your item presets.
| File | Purpose |
|---|---|
index.html |
UI: 3 tabs + login gate. Loads all scripts in order. |
template.js |
The base64 invoice background image (imgData). |
invoice.js |
Data-driven PDF generation — line-for-line port of the original. |
db.js |
Firebase init, owner login, CRUD for bills + itemPresets. |
app.js |
All UI wiring (form, tabs, presets, history). |
firebase-config.js |
Public Firebase project config (safe to commit). |
.verify/parity.js |
Dev-only: proves byte-identical output vs the original. |
firebase-config.jsis not a secret — it only identifies the project.- Data is protected by two things working together:
- Authentication — only the single owner account can sign in
(
arnav.kr.grv@gmail.com), by typing the password. - Firestore security rules — locked so only that owner's UID may read or write. Anyone with the public config still gets denied.
- Authentication — only the single owner account can sign in
(
- The password unlocks history + saved items. Anyone can still "Skip & just print" to generate PDFs offline (print-only mode) — no data is exposed.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null
&& request.auth.uid == "X83o8gVkVkdV3FVXocgLzCg8pz42";
}
}
}
To change the password later: Firebase Console → Authentication → Users → the
owner → reset password. To add a second operator, create another user and add
their UID to the rule with ||.
Project ts-invoices (Spark / no-cost, region asia-south1 / Mumbai):
- Created the project (no billing, no credit card).
- Registered a Web App → copied config into
firebase-config.js. - Authentication → enabled Email/Password; created the owner user.
- Firestore Database → created in production mode → published the rules
above. Collections (
bills,itemPresets) are created automatically on first write.
Because the scripts are loaded as files, use any static server (opening the
file with file:// also works for jsPDF, but Firebase auth prefers http):
cd invoicegen-v2
python3 -m http.server 8000
# then open http://localhost:8000
- Create/replace the repo contents with this folder.
- Commit & push to
main. - Repo → Settings → Pages → Source:
main/ root → Save. - Site goes live at
https://<user>.github.io/<repo>/.
No build step — it's plain static files.
Requires bun (or Node). Confirms the refactor draws exactly what the original
did:
bun .verify/parity.js
# -> ✅ IDENTICAL DRAW SEQUENCE — output is byte-for-byte the same.
bills (one per printed invoice)
{ invoiceNumber, invoiceDate, transport, vehicle, consignee,
items: [{ name, gsm, hsn, size, quantity, bundles, rate }],
carriageOutward, otherCharges, igst, sgst, cgst, lessAdvance,
totals: { itemCost, totalQuantity, carriageOutward, otherCharges,
igst, cgst, sgst, tax, extraCost, roundedTotal,
lessAdvance, gross },
createdAt }
itemPresets (the configurable product list)
{ name, defaultGsm, defaultHsn, defaultSize, defaultRate, active, createdAt }