Commit Graph

2 Commits (feature/host-bootstrap)

Author SHA1 Message Date
nexxo c354ad1463 Make mails readable on a phone, and let an operator look at one
Three things the owner reported, and one sentence that promised something
this product does not do.

**The mails had a fixed width.** components/mail/layout.blade.php set
width="600" and width:600px, so every phone showed a 600px canvas in a
390px window and one had to scroll sideways to read a sentence. Now the
table is width="100%" with max-width:600px — fluid, with 600 as a ceiling
rather than a floor. A mail cannot fix this with a media query (Outlook
renders with Word and drops <style> blocks), which is why the whole file
is inline attributes and why the shrinking has to be built in. Side
padding went 40px -> 24px in the layout and in all nine mail views:
40 each side leaves 278px of a 390px screen to read in.

**There was no way to look at a mail.** An invoice mail needs an invoice,
a maintenance announcement needs a window, and "register an account to
see whether the confirmation reads well" is not a workflow — which is how
the fixed width survived for months. App\Services\Mail\MailPreviews
builds all nine from sample data, every record with make() and never
create(), so a preview leaves no invoice, order or window behind and
draws no number from a series. Two ways to see one: in a tab as the
document itself, or sent to the signed-in operator's own address. There
is no recipient field — that would be a form for mailing strangers.

sendNow(), not send(): every mailable here implements ShouldQueue, and
send() defers to the queue for those, which would have put a failure in a
worker's log while the button reported success to somebody waiting for
the mail. The test caught that.

**The booking page had no shell.** Order declared layouts.portal — the
bare shell the sign-in pages use, no navigation and no padding — so the
page sat flush against the top and bottom of the window with no way back
to anything. layouts.portal-app, like every other portal page.

**The consent box said something untrue.** Its refusal read "otherwise we
can only build your cloud once the withdrawal period has ended", which
describes a path that does not exist: nothing here delivers fourteen days
later, and an unticked box simply means no order. Said plainly now, and
said on the page before somebody runs into the refusal.

Also: GrantedPlanPortalTest asserted assertDontSee('179'), which matches
any id containing those digits — and ids climb through a suite run
because a rolled-back transaction does not reset an auto-increment
counter. It passed alone and failed in company. Asserts on '179,00' now,
which is what a leaked price would actually look like.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 14:50:37 +02:00
nexxo 92bcdcd186 Send the invoice with the invoice attached
tests / pest (push) Failing after 7m32s Details
tests / assets (push) Successful in 22s Details
tests / release (push) Has been skipped Details
The PDF is rendered when the mail goes out rather than fetched from anywhere,
because nothing stores it — and rendering from the frozen snapshot means the
attachment is the document as issued no matter when the queue gets to it or how
often it retries. fromData rather than fromPath: there is no path.

Three attempts at testing it, and the first two were wrong in ways worth
recording. Attachment::$data does not exist — the closure lives in a protected
$resolver, and reaching for it was me testing the framework's internals rather
than my own code. And a byte comparison of the PDF cannot work at all: TCPDF
embeds a creation time and a document id, so two renders of one invoice differ.

Split into the two things that can actually go wrong. The mail carries an
attachment with the right filename and type — that is metadata, and it is
asserted as metadata. And the renderer produces a real PDF rather than an empty
one, asserted where the renderer is, because an attachment closure that returns
nothing still makes a perfectly valid mail with a nought-byte file on it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 02:13:41 +02:00