feat: place PDF artwork in print files, add card payment, count only failed logins
All checks were successful
Build and deploy / Validate source (push) Successful in 6s
Build and deploy / Integration suite on a real stack (push) Successful in 2m23s
Build and deploy / Secret scan and release gate (push) Successful in 5s
Build and deploy / Publish images and notify Portainer (push) Has been skipped

PDF artwork: a single-page PDF source is placed in the print file as a
vector form through pikepdf, never rasterised, using the CropBox and
inherited /Rotate the Site measured with pdf.js. Multi-page and protected
PDFs go to hand preparation. PyMuPDF was not used because of its AGPL
licence. Raster tests cover crop, page rotation, placement rotation and
mirroring, and fail when the rotation or crop handling is broken.

Card payment: Mercado Pago's Card Payment Brick on the Site when
MP_PUBLIC_KEY is set; the card becomes a one-time token in Mercado Pago's
secure fields. Each card attempt has its own idempotency key, and the intent
route refuses new attempts once a payment is approved or a card is in
review, so a quote cannot be charged twice. The Site CSP admits Mercado
Pago's origins only through PAYMENT_CSP_SOURCES, empty by default.

Logins: every attempt counts against the source address, only failures
against the account. Counting successful sign-ins let ordinary use lock an
operator out and made CI's final browser sign-in fail.

No new required settings; production behaviour is unchanged until the
provider credentials are configured. Verified with the full CI integration
sequence locally.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Cauê Faleiros
2026-09-24 13:14:56 -03:00
parent e3d5558198
commit 4c01e932c3
23 changed files with 703 additions and 64 deletions

View File

@@ -230,8 +230,15 @@ From the report already sent. These are dated promises, not backlog.
binds each provider payment to its quote; `/api/payments/intent` starts a
PIX and the Site shows its QR code. Refused paid events and refunds on
existing orders now stay on the Kanban until an operator records a
resolution. Unit-tested against a fake transport only; card form (needs the
public key), sandbox run and refund policy remain.
resolution. Unit-tested against a fake transport only.
**Card form (2026-09-24):** Mercado Pago's Card Payment Brick on the Site,
shown when `MP_PUBLIC_KEY` is set; the card becomes a one-time token in
Mercado Pago's secure fields. Each card attempt has its own idempotency key
(a decline can be retried with another card) and the intent route refuses
any new attempt once a payment is approved or a card is in review, so a
quote cannot be charged twice. The Site CSP gains the Mercado Pago origins
only through `PAYMENT_CSP_SOURCES`, empty by default. Not yet rendered
against a real public key; sandbox run and refund policy remain.
- `[ ]` 1.2 — Real freight quotation. **Blocked on client inputs** (see
`PRODUCTION_INPUTS.md`): source platform, credentials, origin CEP, services,
packaging weight/dimensions per length, subsidy policy.
@@ -268,8 +275,13 @@ From the report already sent. These are dated promises, not backlog.
mirror, and `tests.print_file_test` passes on the running stack (generate,
download, approve as final, queue; hand-preparation routing and retry).
**Still open:** a FlexiPRINT import of real
generated files (including one longer than 5 m, which uses `UserUnit`), and
PDF artwork, which this generator does not compose.
generated files (including one longer than 5 m, which uses `UserUnit`).
**PDF artwork (2026-09-24):** a single-page PDF source is placed as a vector
form through pikepdf (MPL-2.0; PyMuPDF was rejected for its AGPL licence),
using the CropBox and inherited `/Rotate` the Site measured with pdf.js.
Raster tests cover crop, page rotation, placement rotation and mirroring,
and were shown to fail when the rotation or crop handling is broken.
Multi-page and protected PDFs go to hand preparation.
- `[~]` 1.5 — Main Kanban production states consolidated. The six states and
their transitions are unchanged; cards now show the delivery address, the
print-file status per item, and a panel lists payments that need a person
@@ -692,13 +704,12 @@ print-file evidence still need correction before this item can close.
storage and storage-init now use Chainguard's MinIO build (ships `sh` and
`mc`, non-root), pinned by digest. Verified with a fresh local build and the
full integration sequence. Production uses R2 and is unaffected.
- `[ ]` 5.16 — The operator login limit (10 per account per 15 minutes) counts
successful logins too, and every test client signs in separately. The CI
sequence sits close to that limit: one extra login made the final browser
test's sign-in fail with 429 until `print_file_test` was changed to reuse
one session. Either count only failures toward the account bucket or give
the suites a shared operator session, so adding a suite cannot break
another.
- `[x]` 5.16 — The operator login limit (10 per account per 15 minutes) counted
successful logins too, so ordinary use could lock an operator out, and one
extra test login made CI's final browser sign-in fail with 429. Now every
attempt counts against the source address and only failures count against
the account; registration still counts every attempt. The security suite's
lockout check (ten failures, then 429) is unchanged and passes.
- `[ ]` 5.13 — Define production recovery: scheduled encrypted offsite database
and object backups, a consistent snapshot boundary, Swarm data placement and
a restore rehearsal that opens every required live order file.