Email workspaceInternal automatic subscription review contract
Implementation: App\Mail\FailedSubscription. Baseline view: resources/views/emails/users/automatic-subscription-failed.blade.php. Usage: app/Http/Repository/PaymentRepository.php:1020–1027, resolveMobileMoneyCollection(). Static references are evidence, not proof of current production delivery. Original templates use mail::message; the standalone draft uses the shared compact table shell.
Suggested subject: Automatic subscription needs review (proposed; source envelope subject is Failed Automatic Subscription). HTML document title does not set the actual mail header.
Suggested preheader: An automatic subscription collection has an undefined subscription type.
Portable placeholder contract
| Token | Existing source / derivation | Handling |
|---|---|---|
| {{logo_url}} | Original Built app_name PNG | Optional deployment override; concrete project HTTPS image is already present. Approved absolute HTTPS or matching CID. |
| {{preheader}} | Suggested text above, assembled only from existing context | Required escaped text; no new backend record or timing promise. |
| {{business_id}} | $business->id | Required internal business reference; never a customer login token. |
| {{business_name}} | $business->name | Required escaped text; preserve the existing value. |
| {{collection_amount}} | $collection->amount | Required raw source amount display. Source supplies no currency prefix in this view, so none is invented. |
| {{channel}} | $collection->network | Optional source network display; explicit escaped em dash when absent. Do not guess channel from provider. |
| {{cycle_reference}} | $collection->transaction_id | Required source value labeled Cycle in the original. This is a reference, not proof of months or a billing-cycle count; no field is discarded. |
Content, states and integration decisions
- Internal finance/operations audience only. Caller iterates an internal address list and uses synchronous send(); FailedSubscription does not implement ShouldQueue. Preserve routing and behavior. It is not sent to the business customer or business owner in this source path.
- Critical trigger: inside code === 00 branch (source collection success handling), transaction_type == subscription-undefined. This supports undefined-subscription classification review, not a claim that the customer debit failed. Source Mailable/subject call it failure, but the redesigned heading/body/subject describe the evidenced review condition. No payment/refund or subscription activation guarantee is added.
- This Mailable uses Content(view: ...) rather than markdown despite its source file containing mail::message syntax. That wrapper mismatch is an integration concern; recommend a dedicated full HTML Blade view rather than nesting the portable document in a Markdown component. Do not silently change mail delivery code here.
- Retain business ID, name, raw amount, network and transaction_id. Cycle reference clarifies the last field while mapping it explicitly. The old generic Hello/for you language is replaced with an internal operations context. No customer greeting, currency, retry URL, payment status or PDF attachment is added.
- States: ordinary internal review, unavailable channel, and long IDs/names/reference/amount. No production recipient data or live collection references appear in samples.
Safe integration, text and images
ready/automatic-subscription-review.html and ready/automatic-subscription-review.txt are portable extracts; every populated state under previews/ has HTML and text. No separate project-owned plain-text alternative was found for these four views, so the supplied text versions are proposed equivalents.
Portable {{placeholder_name}} tokens are not automatically Laravel Blade variables. Prefer an explicitly mapped full Blade view and a separate text alternative inside the existing Mailable, retaining constructors, sender/header choices, recipient routing, attachments and queue behavior. A full document should not be nested inside mail::message. No new templating framework is needed.
Escape all dynamic text, attribute values, failure reasons and internal references. Never insert provider text as raw HTML. Validate any image override separately against approved HTTPS hosts or an actual attached CID before escaping it. If string replacement is chosen, use one pass; inserted token-shaped text must remain text. There are no application action destinations or duplicate legacy action-link fields in this batch; the source failed-attempt button is empty and intentionally removed. Only the confirmation tax block is conditional; remove its entire marked section when false in both HTML/text. Other documented fields are required except the explicit channel fallback.
Default logo: https://built-storage.ams3.cdn.digitaloceanspaces.com/Built/app_name.png. Retain the unchanged assets/built-logo.png original. Use absolute HTTPS hosting or a matching CID attachment, preserve its proportions and account for remote-image blocking. Dark mode is progressive enhancement and needs real client tests.
Fixtures use fictional names, amounts, reasons and references. No payment, subscription change, mail send or provider action is executed. Browser rendering is not proof of Gmail, Outlook or iOS Mail compatibility, actual attachment generation or production delivery. See subscriptions-batch.md, subscriptions-validation.md and integration-notes.html.