On a short page (sign-in, an empty cart) the footer followed the content
and the rest of the screen was left blank below it, more so with the Site
drawn at 80%. The body is now a column at least the screen's height with
the footer pushed to its end; under the 80% zoom that height is 125vh,
because the zoom scales viewport units too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The order page becomes the customer's area, one page at four addresses:
- /conta/entrar: sign in or create an account, side by side. "Esqueci
minha senha" points to the Dropstar WhatsApp until e-mail can be sent.
- /conta: the counts of orders waiting for payment, in production, in
correction and finished, and the latest one.
- /conta/pedidos: every order and the cart waiting for payment in one list,
newest first, filtered by group, order number and period, ten per page.
The cart shows "Aguardando pagamento" and its "Pagar" goes to the PIX
page when a PIX code is open. An order opens in place with its progress,
items, delivery, history, files and the correction form. A guest sees
the orders paid in this browser.
- /conta/dados: WhatsApp and a saved delivery address (the CNPJ is locked),
e-mail and password changes, both confirmed with the current password;
a password change signs the other devices out.
The cart fills in the account's details and saved address. New API routes
for the details, and the order list takes filters and pages and returns
the counts; only the newest unpaid quote whose files still exist is listed.
The Site's "Minha conta" and "Ver meus pedidos" point to the new addresses.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Meus pedidos" was still the prototype's plain page. It now has the Site's
stripe, header and footer, and its type, colours and cards: each order shows
its status, a progress line through production (or the correction the team
asked for), the items with metres and price, where it goes, and on request
the history, the files to download and the correction form. Carts waiting
for payment are listed with a button to pay. Sign-in and account creation
are side by side.
The header, stripe, menu, footer and tokens moved from index.html's inline
style to site-shell.css, which both pages load. The header's search box,
which did nothing, is gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The text sizes were chosen looking at the Site with the browser at 80%; at
100% everything felt too big. On screens 1100 px and wider the Site is now
drawn at 80% (CSS zoom); phones and tablets keep their sizes. The time left
while reading a large file shows the seconds under 10 s ("faltam 7 s")
instead of "quase pronto".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reading a large PNG in the browser for its preview showed "gerando a
prévia… 87%". It now shows the time left, worked out from how long the
reading has taken so far: "faltam cerca de 25 s", "faltam cerca de 3 min",
"quase pronto". The bar still fills as it goes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The browser suite reloaded the page a fixed 800 ms after the last field
was typed. The cart save waits for typing to stop and writes the files to
the browser's storage, so under load the reload came first and the cart was
not recovered ("persistent cart recovery", and once "Inspected target
navigated or closed"). It now waits until the cart is in storage.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The product page's notice about the upload time is gone. The cart's upload
bar now reads "Enviando seus arquivos · faltam cerca de 6 min", measured
from the upload's own speed (a range from the size for the first seconds),
with a line saying the time depends on the internet and to keep the page
open. The header and the pay button show the same time instead of a
percentage.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The notice stayed on the product page after the item went to the cart,
showing the last file's size on the next order. It is now redrawn wherever
the files are cleared and hidden when no product is open. The text is one
line: "Envio: até 8 min (501,2 MB), conforme sua internet. Mantenha a
página aberta."
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Removes "Complete o endereço de entrega para ir ao pagamento." The required
fields (CNPJ, WhatsApp, e-mail, and the delivery address except the
complement) carry a red asterisk, and aria-required for screen readers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each cart item has a checkbox and a thumbnail of its first file (or its
extension when there is none). Only checked items are priced, quoted,
uploaded and paid; an unchecked item stays in the cart, dimmed, for a later
order, and stays there after the others are paid. The header count is the
whole cart; the summary counts what is being paid.
Also removes the "A conta nasce aqui…" and "Carrinho salvo neste
navegador…" texts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every Site text size up to 18 px grows another pixel, the Kanban's up to
14 px half a pixel, and the icons one pixel. The pay button grows to two
lines when "Pagar os N itens de uma vez" no longer fits on one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Most of the text was 11 to 13 px and hard to read. Every size up to 16 px
grows: by 1.5 px up to 12.5, 1 px up to 14 and 0.5 px up to 16 on the Site,
and a little less on the denser Kanban. Headings and prices keep their size.
Icons grow by 2 px so they stay in proportion with the text beside them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Buttons: add to cart (bag with plus), go to payment (lock), remove from
the cart (bin).
- Delivery: a pin for pickup in Franca, a truck for home delivery.
- Payment: card and QR code on the methods, copy on the PIX code, a clock on
its countdown, a check on the confirmation.
- Status: a check when the files are sent, check, alert, redo and cross in
the quality list instead of Unicode symbols, and a check on finished steps.
- Kanban: a truck or pin for where an order goes, a speech bubble on the
WhatsApp link, a download arrow on the file buttons.
All Lucide shapes drawn inline, as in the header.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The header's search, account and cart get icons, with the item count on the
cart instead of "Carrinho (N)"; on phones only the icons show. The upload
zone, remove, rotate and mirror buttons used Unicode symbols that look
different, or are missing, depending on the system's fonts; they are now
Lucide icons (ISC licence) drawn inline, so nothing new is loaded and the
CSP is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The price depends on the grade, which the browser worked out and the API
took on trust. Before a cart is approved at checkout the API now recomputes
it from the uploaded files by the Site's own rules: the pixel size in a
PNG, JPG or WebP header across the printed width (rotation included), and
the area-weighted DPI of the images placed in a PDF of up to 150 MB, 300
for vectors. Sheets take the worst grade, artworks the average. A claim more
than 2 points above the file's grade, or a discount on a file the server
cannot grade, waits for an operator, with the reason on the Kanban.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Above 150 MB the browser cannot read JPG or WebP in parts, so a large
artwork was refused. It is now measured from its header, graded and priced
with the discount like any other, and placed on the sheet as a full box,
which is exact for JPG. The card says there is no preview and that the team
checks the art before printing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Files are uploaded before payment so the price and the security check use
the file itself, but an abandoned cart kept them for 30 days. Now a finished
upload is held 2 days, a quote waiting for review 7, an approved quote 2 more
to be paid, and the paid order keeps its originals for 30 days from upload.
A payment never starts for files that are gone; one under way holds them a
day. Files attached to an order take the order's window.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When files are picked, the product page shows the range the upload takes
between a slow (10 Mbps) and a fast (150 Mbps) connection, and asks to keep
the page open. The cart shows the same range until the real speed is
measured, then the measured time left.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The browser put the CNPJ, WhatsApp, e-mail, CEP and address back after a
reload without telling the page, which then showed them but could not pay
until they were typed again. The fields are now emptied on load and marked
autocomplete="off", and the saved cart holds only the items: the details and
address are typed again after a reload or a closed tab. The payment page
already takes them from the server.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A backup service runs pg_dump every day at 03:00 Brasília, checks the archive,
encrypts it with age to a public key and uploads it with a token for that
bucket only. The server cannot read or delete backups: the private key stays
with the owner, the bucket's lifecycle rule expires copies and its lock stops
early deletion. Each run is recorded and shown on the Kanban's Integrations
tab. tests/backup_test.py backs up, restores into a scratch database and
compares the rows in CI. Setup and restore: docs/BACKUP.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each artwork gets the same card as a finished sheet: "Suas artes" with the
count of artworks and copies, a thumbnail, the size in cm with pixels,
format and weight, a DPI chip and how many fit per row, the resolution or
width hint, then width in cm, a copies stepper, rotate and mirror, and the
usual sizes. Packing, pricing and the hints are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Opening a question moved its link out of the row into the answer, and only
that heading closed it again. The four questions are now a row of links
that always stays: the open one is highlighted, its answer shows below,
another link switches to its answer and the same link closes it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The product page is rebuilt around mockup 1. The two ways to send are
cards under the title; the PNG/CDR route choice is gone (it never changed
the price, and the picker now takes every allowed format). Each file card
has a thumbnail, its size, check chips with a plain sentence for any
problem, a "Ver detalhes da conferência" link and a copies stepper; a CDR
file says "Conferência manual · preço cheio" and asks for the length. The
buy box shows the price scale in DPI with the customer's step, the metre
and 10 cm length, the total and what the resolution saved, and "Sai em N
partes" only above 20 m. Folha já montada gets "Ampliar" instead of zoom.
Pricing, grade and checks are unchanged.
Fixes on top: the card thumbnail is a small image made once, not the full
preview re-parsed on every repaint; sizes from 1 GB up read in GB; a failed
upload is shown with "Tentar de novo" instead of retrying silently on every
cart change. The browser suites wait for the product and the reloaded page
instead of racing them, and the artwork suite delays imagemDaArte, which
the packing now uses, fixing the CI failure of f4aacb5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Artes avulsas decoded every file whole, and the packing decoded each one
again on every repaint, so a large artwork failed to load. A PNG over 150
MB is now measured from its header (pixel size, so DPI and grade stay
exact) and packed from a 1200-pixel copy read as a stream, with progress on
its card; every artwork's image is loaded once and reused by the packing.
A large JPG or WebP asks for a PNG, and the grade card no longer calls a
file unreadable while it is still being read.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reading a large sheet repainted the list and "Sua folha" on every progress
step, so the preview flickered; progress now moves the bar in place and
"Sua folha" shows a skeleton until the preview is ready. A sheet printed
N times is shown N times (up to six, then a count). The payment page shows
skeletons while the order loads and until the card form is ready.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Uploads of several GB ran behind one grey line in the cart. The order
summary now has a progress bar with the percentage, size and an estimate of
the time left from the recent speed; the header shows "enviando 45%" on
every page while it runs; the payment button says what it is waiting for;
and leaving the page mid-upload asks first.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A large sheet had no preview and no automatic check of pieces, residue,
gaps and background, because decoding it whole would crash the browser.
A PNG over 150 MB is now inflated as a stream (DecompressionStream) and
unfiltered row by row, keeping every n-th pixel: a 600-pixel-wide copy in
about 100 MB of memory whatever the file's size (6.6 s for 500 MB, 22.7 s
for 2.4 GB of random pixels, identical to Pillow's output for RGB, RGBA,
grey, grey+alpha, palette and 16-bit). The copy is the preview and what
the sheet check reads; the grade still comes at once from the header.
The preview note promising a server-side re-nesting that does not exist
is removed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without an approved card payment there was no way to try the board, the
files and the print flow in production. "Criar pedido de teste" on an
approved quote creates the order through the same path as a paid one, marked
TESTE on its card and panel and audited; neither it nor its stage moves
queue anything for Tiny or WhatsApp.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without access to the Mercado Pago panel, "Verificar conta" now also says
how many payment notifications arrived and passed the signature in the last
24 hours, how many were refused by it, and the last one received: the PIX
payments created in test mode notify the webhook, so this shows whether
Mercado Pago reaches the server.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Verificar conta" on the Mercado Pago card of the Integrations tab runs the
read-only account check (whether the token is a test user's, the card
methods, how the test card is classified) without a container console.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rule sizing the PIX code field applied to every input in the payment
area, turning the card form's instalment radios into tall boxes; the
heading rule likewise reached the form's own headings. Both now apply only
to the page's own elements.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A credit card payment with the test credentials was refused with 10113
("the payment method is excluded by a rule"). Every card was sent with
three_d_secure_mode, which only debit needs, and with the order's CNPJ as
payer instead of the cardholder's document from the card form. Debit
methods keep 3-D Secure, and the card form's document is the payer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Card payments with the test credentials are refused with 10111 and 10113,
which depend on the account behind the token. python -m
app.mercadopago_probe shows that account (and whether it is a test user),
the card methods it accepts, and how Mercado Pago classifies a card's first
digits: type, issuer and instalments. It creates and charges nothing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paying with Mercado Pago's own test card failed with 10111 ("the issuer
does not have the BIN configured"): the issuer_id suggested by the card
form did not match the card. issuer_id is optional, and without it Mercado
Pago resolves the issuer from the BIN.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The artwork suite still asserted the old 128 MB refusal. It now refuses a
file above 5 GB and checks that a 3 GB sheet is graded from the pixel size
in its PNG header (300 DPI, 3 m) without being decoded.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sheets of several GB are the normal order. The upload limit is now 5 GB.
ClamAV scans files up to 2 GB; a larger file is released only when its
first bytes match the format its name claims, and a disguised file is
refused. The Site grades a sheet over 150 MB from the pixel size in its
PNG, JPEG or WebP header without decoding it, and reads large PDFs in
ranges. The worker never opens a source over 300 MB: a finished sheet
placed whole becomes its own print file, which the Kanban offers to approve
as the final, and anything else goes to hand preparation. Files start
uploading as they enter the cart, with progress in the summary, and each
part renews the reservation so slow uploads do not expire. Quotas grow to
50 GB per customer and 500 GB in total; the Swarm config for ClamAV is
renamed because a deployed config cannot change in place.
Verified locally with a 386 MB and a 1.8 GB PNG (scanned, paid, original
as print file), a 2.3 GB PNG (format check) and a disguised 2.3 GB file
(refused).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When creating the card payment failed, the form's onSubmit rejected with no
message and Mercado Pago's button kept spinning. The page now shows the
reason above the form. A payment Mercado Pago refuses is logged with its
status, message and cause codes (payment_intent_refused) and answered 422
with that reason; other failures log their type.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The number in the Kanban's order panel is now a formatted wa.me link, so a
correction or a question about the artwork can be sent by hand in one
click.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The CRITICAL scan of dtf-api failed on a 404 from the database mirror and
was reported as a CRITICAL vulnerability. The image step now downloads the
database once into a cache volume, with three attempts, scans all four
times from it, and exits 5 only on findings: a scan that does not run fails
with its own message, and nothing is published unscanned.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mercado Pago's form titled both card options "Cartão de crédito ou débito";
the option above it already names the card.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Integrations tab always said freight was not configured. It now reads
the server's adapter and, with Jadlog on, shows the package weight rule and
the production days the Site prices with.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Going back to home delivery with a CEP already typed, or restoring a saved
cart, now quotes the freight again by itself; before, only pressing Calcular
did. With every case covered, the button is gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A complete CEP now looks up its address on the server (ViaCEP, rate
limited, keeping the Site's CSP to its own origin) and fills street,
district, city and state, moving the cursor to the first field left, and
quotes the freight without pressing Calcular. The CEP keeps its mask when
the cart is restored. Freight and its delivery time appear in the order
summary instead of a line under the CEP, the delivery option says it ships
with Jadlog, and the address reminder is a hint rather than an error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Jadlog issues the account as 000000-0 and documents a six-character field;
stripping the dash sent seven digits. The value now goes as typed, so the
accepted form can be found on the account without a new release.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FREIGHT_ADAPTER=jadlog prices "Receber em casa" through Jadlog's Simulador
de Frete from the order's billed metres and value, adding production days
to Jadlog's delivery time. The package weight is a base plus a weight per
metre from the client, with no default: the adapter refuses to start
without it and without the credentials. The cart re-quotes when the package
changes, and approval quotes again from the server-priced items. The
production stack takes the Jadlog settings, so the read-only probe runs
from the worker's console.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A PIX is created with a 30-minute date_of_expiration, and the PIX page
counts down to it. When it runs out the page says the code expired and
offers a new one. The API keeps one open code per quote: the same code
until it expires, then exactly one new attempt (serialised per quote, with
its own idempotency key), the old one marked expired.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>