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>
The payment page lists credit card (preselected), debit card and PIX. Each
card option limits Mercado Pago's form to its kind; debit is paid at once.
Card payments ask for 3-D Secure when the issuer requires it, and a
challenge opens the bank's page in a frame, which needs
PAYMENT_CHALLENGE_SOURCES=https: (frames and form posts only). A card left
waiting for that confirmation stops blocking a new attempt after ten
minutes, and a refusal reported by the notification returns the customer to
the payment choice. Written from the documentation; not yet run with a real
debit card.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The payment page puts paying on the left and the order summary on the
right (above it on phones). Card is preselected and paid on the page with
Mercado Pago's form, in the Site's colours and with the order's e-mail;
choosing PIX shows a Pagar button that opens /pagamento/pix with the QR code
and copy-and-paste code, waiting there for the confirmation. A confirmed
payment shows "Pagamento confirmado" with the order number and a button to
the customer's orders. The payment buttons no longer restyle every button
inside the form.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The summary above already shows the total; the line stays only beside the
local stack's simulated payment.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The PIX and card choices appeared under the cart, on the same page as the
customer's details. "Ir para o pagamento" now sends the order and opens
/pagamento, step 3 of the progress bar: the server's order summary, then PIX
or card, each opening below. The cart keeps only the sending progress and its
errors; a changed cart is sent again instead of offering the old quote.
Portal links open the payment page.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The proxy in front of production caches .js and .css for hours. After the
last release the Site got the new index.html with the old site-flow.js,
which wrote to an element the new page no longer has; the error left
"Adicionar ao carrinho" disabled. The web build now addresses every local
script and stylesheet by a hash of its content, replacing the hand-kept
?v= markers, so a new release always loads its own files.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pickup notice under the delivery options and the invoice and retention
note under the purchase summary are gone. PORTAINER.md records the R2 CORS
policy the browser's direct uploads need: without it the preflight is
refused and checkout fails with a NetworkError before payment.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every quote waited for an operator before it could be paid, so an order
placed at night waited for the morning. A cart the Site priced is now
approved when the quote is created, through the same server pricing the
operator's approval uses (app/quote_review.py). Orders above
QUOTE_AUTO_MAX_METRES (50 m) and items claiming a discount on art the Site
could not analyse still wait for review; the Kanban shows which quotes were
approved automatically and why the others wait.
The grade is still computed in the browser (roadmap 3.2, 3.9), so the
discount remains a customer-supplied value until the server computes it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
app/jadlog.py prices one package through Jadlog's Simulador de Frete as the
API manual v2.3 describes it; app.jadlog_probe prices test weights to six
regions on the client's account to confirm token, account and contract.
Tested against a fake transport. The roadmap records the Jadlog data and the
Mercado Pago account setup.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The production compose hard-coded the fake payment adapter; it now takes
PAYMENT_ADAPTER and the MP_* settings from the stack's environment, so the
sandbox can run with test credentials. A signed notification about a payment
Mercado Pago does not have, such as the panel's "Simular notificação", is
acknowledged instead of answering 500 and being retried; any other lookup
failure still raises.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The operator guide is now built from docs/guias/operador/ by
docs/guias/imprimir.sh, with the corrections on Tiny and the WhatsApp
notices. The roadmap records the guide, the history fix found while
writing it, and the Week-2 report as sent.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A move back undoes an operator's mistake and its reason is internal. The
customer's history now omits back moves and shows a reason only for a
correction; the smoke test checks both.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The client already sends WhatsApp notices from Tiny's order situação
(Tiny webhook -> middleware -> n8n). With TINY_STATUS_UPDATES on, a paid
order is set to "Aprovada" once and a finished pickup order to "Pronto
para envio"; pickup orders carry the client's pickup forma de envio
(TINY_FORMA_ENVIO_RETIRADA). The ready event now carries the order and
the Tiny id from the sale's receipt. Off by default until go-live, when
n8n stops sending the DTFIMP designer message.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Connecting now asks for offline_access, retrying once without it if Tiny
refuses the scope. Renewal failures are stored: a refused refresh token
marks the connection lost and is not sent again (the Kanban previously
still said "conectado"), a transient failure shows as a warning until the
next renewal, and a session grant with under 12 hours left is flagged.
Tiny errors on the callback return to the Kanban instead of a 422.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The grade check and the layout preview run on short timers. When the
item went to the cart inside that window, no product was open and both
threw in the customer's browser, which also failed the browser tests
intermittently. Each now returns when no product is open. The cart test
waits for the empty state, which is painted on the next animation frame.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Testar conexão" now also reads the four configured Tiny products and
requires each to be active. app/tiny_probe.py runs from the worker console
to list products, confirm the configured ids, and create one marked test
order through the worker's own delivery path, proving the duplicate guard
by search before a second delivery. Nothing is sent without --confirmar.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The operator guide covers the Kanban flow from quote review to finished
order; the Site guide walks through the customer journey, prices and the
current state of each integration. The roadmap records the Kanban and Site
redesigns, the guides, and what is left for the last day of Week 2.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each cart item has a visible "Remover" button instead of a faint ×, and
carts with two or more items get "Esvaziar carrinho". Both show a
"Desfazer" notice for 8 seconds, so a wrong click costs nothing. The
browser test covers remove and undo.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Artworks on the left; on the right a box that stays in view with the live
sheet, the grade, the price per metre, the metres charged, the total, the
resolution note and "Adicionar ao carrinho". The separate quality and
preview panels, the second sheet preview, the per-row mini sheets, the
summary box and the repeated findings list are gone: each piece of
information now appears once.
Each artwork row carries at most one hint (resolution first, otherwise a
width that saves film), the ready-sheet/loose-artwork choice is a toggle
beside the title, the upload area is one bar and the tips are collapsed.
The box only shows the item the page already priced, so it always matches
the cart.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The home, each product's Montagem and the cart now have their own
addresses (/artes-avulsas, /arquivo-por-metro, /uv-artes-avulsas,
/uv-arquivo-por-metro, /carrinho) and show only their own content, with
Back, Forward, reload and direct links working as in any store. They stay
one document so uploaded artworks survive moving between pages; nginx
serves index.html for these addresses.
"Adicionar ao carrinho" puts the item in the cart and opens it, and an
empty cart says so. Portal quote links open in the cart. Also fixes the
"57 cm" line break on the ready-sheet option, returns "Novo pedido" to
the home, and says PDF depends on the product.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>