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.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Why
Some invoices need a hand signature or stamp on the printed PDF, and there was no way to attach one.
What changed
invoice_data, so it persists with saved invoices and round-trips through the editor.normalizeInvoiceDatavalidates the signature is a well-formeddata:image/(png|jpeg);base64,...string (ornull), and the JSON body limit was raised to 2mb to accommodate it.renderInvoicePdfdraws the signature directly above the payment/QR footer card, right-aligned with the same margin as the QR code.Notes for reviewers
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.npm test, 3/3 passing) and by rendering a test PDF with a 420x210 placeholder image to confirm placement.