Commit Graph

2 Commits (4477a7699eded40cc3ada89d41de569f8e42564c)

Author SHA1 Message Date
nexxo d7d116e9a5 Jede Mail faehrt wieder ueber ihren eigenen Mailer
Mail::to(...) loest den Standard-Mailer auf, und dessen queue() schreibt
danach `$view->mailer($this->name)`. Damit war der im Konstruktor gewaehlte
Mailer (cp_mail_<typ>) durch 'smtp' ersetzt, bevor der Auftrag ueberhaupt
gebaut war.

Mit dem Mailer fiel alles weg, was an ihm haengt: MailboxTransport, die
Postfachsuche samt passendem Absender — und der Notschalter aus
App\Support\MailDelivery, der genau dort sitzt. Eine abgeschaltete Zustellung
schaltete deshalb nichts ab, und die Mails meldeten sich mit den Zugangsdaten
aus der Konfiguration an, waehrend der Absender aus der Mail kam: „553 Sender
address rejected". Das lief hier im Minutentakt.

Zwei Stellen hatten es schon richtig — MaintenanceNotifier und MailPreview,
beide mit der Erklaerung an der Zeile. Neun andere nicht. Alle beginnen jetzt
mit Mail::mailer($mail->mailer), sodass das Ueberschreiben denselben Wert
zurueckschreibt.

Die Attrappen in drei Tests zielten auf to() und trafen damit nicht mehr den
Einstieg; drei von ihnen bestanden ohnehin nur zufaellig, weil ein Aufruf auf
null ebenfalls warf. Sie zielen jetzt auf mailer().

Erzwungen durch tests/Feature/MailDispatchTest.php: Mail::to( ist in app/
verboten, und ein Gegentest haelt das Framework-Verhalten fest, damit die
Regel fallen darf, wenn Laravel sie eines Tages unnoetig macht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 20:36:20 +02:00
nexxo fed4acf31c Accept terms instead of a start date, and fix the sender no server accepts
**The test mail was rejected: "553 5.7.1 Sender address rejected: not
owned by user no-reply@…".** Every purpose mailbox here has its own SMTP
account, and a mail server lets an account send only from the address it
owns. Mail::to() hands back a pending mail bound to the DEFAULT mailer and
sendNow() then ignores the mailer the mailable asked for, so a mail
addressed support@ went out over the no-reply@ login. It sends through the
mailable's own mailer now, and the cloud-ready preview — the one mailable
with no mailbox at all — takes the provisioning mailbox like the real
notification does.

Writing the test for that found the same bug in production code:
**InvoiceMail and OrderConfirmationMail set their From to billing@ and
never named a mailer**, so both went out over mail.default's no-reply@
login. On this installation no customer had ever received an invoice mail
or an order confirmation; they rendered perfectly, queued without
complaint and were refused at the door. MailSenderOwnershipTest now scans
for the mismatch: a mail that takes a mailbox From must use that
mailbox's mailer.

**The box on the order page accepts the terms now**, not an immediate
start. It used to carry the whole FAGG §16 sentence, which read like a
choice between "now" and "in fourteen days" — and there is no second
option. The terms are what regulate the sale, so they had to exist:
resources/views/legal/terms.blade.php replaces the placeholder with
fourteen sections written from what this software actually does — the
delivery, the capacity queue, the full refund on withdrawal, the
cancellation at period end, the deletion deadlines. The company data
comes from CompanyProfile, so the page and the invoices cannot drift. No
availability figure and no liability cap has been invented.

No order goes through without it: the button is unusable until the box is
ticked and says why, and CheckoutController still refuses server-side —
the browser half refuses nothing. The request field is `terms_accepted`;
the Stripe metadata key stays `immediate_start`, because a session opened
before a deploy is paid after it and the webhook would find nothing under
a new name.

**"Wird der Account nach fünf Tagen gelöscht?"** Only an unconfirmed one.
That was the whole of what we said, so the answer looked like yes. The
second rule now exists and is stated: PruneDormantAccounts removes a
confirmed account after a year when it never had a package — no customer
record at all, which is where every order, contract and seven-year invoice
hangs. A fortnight's notice goes out first, once, and `dormant_warned_at`
is what permits the deletion: an account whose warning never went out is
never removed. Signing in resets the clock, measured off the device rows
because users has no last_login_at.

Both deadlines are said in the portal settings, on the verification page,
and in the terms — each reading the number off the command that enforces
it.

Also: the wordmark scan matched any element whose text merely BEGINS with
the company name, which a paragraph of terms does. It looks for the lockup
form now (no whitespace after the tag), which is what it was always about.
The seven checkout tests in the parallel session's files were posting the
old field name and now post the new one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 15:22:35 +02:00