Add optional signature upload to invoice PDF #7

Merged
odweta merged 2 commits from odweta-urban-goggles into main 2026-09-10 17:27:57 +02:00
odweta commented 2026-09-10 17:27:19 +02:00 (Migrated from github.com)

Why

Some invoices need a hand signature or stamp on the printed PDF, and there was no way to attach one.

What changed

  • Added a drag-and-drop / click-to-browse upload field on the invoice editor for an optional signature image. Only 420x210 JPG/PNG is accepted; the client validates exact dimensions before accepting the file and shows a preview with a remove option.
  • The signature is stored as a base64 data URL alongside the rest of invoice_data, so it persists with saved invoices and round-trips through the editor.
  • On the server, normalizeInvoiceData validates the signature is a well-formed data:image/(png|jpeg);base64,... string (or null), and the JSON body limit was raised to 2mb to accommodate it.
  • renderInvoicePdf draws the signature directly above the payment/QR footer card, right-aligned with the same margin as the QR code.

Notes for reviewers

  • This branch also merges in main (including #4's footer-anchored payment card and text-sized QR code), and I resolved the resulting layout conflict so the signature sits immediately above the now-bottom-anchored payment card rather than pushing it down the page.
  • Verified with the existing + new Jest suite (npm test, 3/3 passing) and by rendering a test PDF with a 420x210 placeholder image to confirm placement.
## Why Some invoices need a hand signature or stamp on the printed PDF, and there was no way to attach one. ## What changed - Added a drag-and-drop / click-to-browse upload field on the invoice editor for an optional signature image. Only 420x210 JPG/PNG is accepted; the client validates exact dimensions before accepting the file and shows a preview with a remove option. - The signature is stored as a base64 data URL alongside the rest of `invoice_data`, so it persists with saved invoices and round-trips through the editor. - On the server, `normalizeInvoiceData` validates the signature is a well-formed `data:image/(png|jpeg);base64,...` string (or `null`), and the JSON body limit was raised to 2mb to accommodate it. - `renderInvoicePdf` draws the signature directly above the payment/QR footer card, right-aligned with the same margin as the QR code. ## Notes for reviewers - This branch also merges in `main` (including #4's footer-anchored payment card and text-sized QR code), and I resolved the resulting layout conflict so the signature sits immediately above the now-bottom-anchored payment card rather than pushing it down the page. - Verified with the existing + new Jest suite (`npm test`, 3/3 passing) and by rendering a test PDF with a 420x210 placeholder image to confirm placement.
Sign in to join this conversation.