Email workspaceProduct import completed contract
Purpose/audience: $user, the importing user.
Implementation: App\Mail\InfoMail (Product Import Completed outcome). Baseline view: resources/views/emails/info.blade.php. Usage evidence: app/Http/Repository/ItemRepository.php:1053, processItemImport success callback. These are static references, not proof of current production delivery.
Suggested subject: Product Import Completed. HTML title alone does not set the mail header.
Suggested preheader: Product import completed for {{business_name}}. Review the import counts.
Portable placeholder contract
| Token | Existing source / derivation | Requirement |
|---|---|---|
| {{logo_url}} | Existing Built app_name PNG | Optional deployment override; the concrete project HTTPS PNG is the default. Approved HTTPS or matching CID only. |
| {{preheader}} | Suggested text above, assembled only from already available values | Required escaped text; not a new backend record or processing guarantee. |
| {{first_name}} | $user->first_name in ItemRepository::processItemImport callback | Required escaped name of the importing user; not a field currently passed separately to InfoMail. |
| {{business_name}} | $business->name in that callback | Required escaped importing-business identity. |
| {{processed_count}} | $data['processed_items']; failure fallback: $chunkSize | Required supplied count; preserve zero. Current chunkSize is 100. |
| {{created_count}} | $data['created_items']; failure fallback: 0 | Required supplied count of newly created products; not a synonym for processed or submitted. |
| {{submitted_count}} | $data['total_items']; failure fallback: $total | Required supplied submission count; do not infer skipped, duplicate or failed counts. |
Content, states and integration decisions
- Keep processed items, newly created products and submitted total distinct. The current success body says products were imported successfully, but the counts need not all match. Do not claim every submitted item created a new product, calculate a skipped/duplicate count or invent an explanation for the difference.
- A zero-created fixture preserves a supplied zero without treating it as empty or inventing a failure state. Other states are standard and long identity/large counts. This remains one success notification type.
- The success callback reads processed_items, created_items and total_items directly from its cache result; unlike failure, it defines no fallback for those values. Do not silently fabricate zero in a success integration.
- There is no source action URL or attachment. The draft remains informational and must not create a retry/view-products button. InfoMail implements ShouldQueue, despite the caller using send(); preserve that behavior.
Required import integration adapter
The structured fields above exist in ItemRepository’s callbacks, not as separately bound InfoMail view values. InfoMail currently accepts a title and a prebuilt message, then maps message to body; emails.info renders body as raw HTML. The title maps to the subject listed above, and the old body contains the same greeting/business/counts/instructions shown in this design.
Do not drop this HTML into emails.info and assume first_name/business_name/counts will appear. A later authorized integration must explicitly pass structured callback values into a dedicated import view/Mailable or a deliberate typed extension of the existing wrapper, preserving subject, recipient, queue behavior and all existing body content. Do not scrape HTML to recover counters, blindly replace generic InfoMail for unrelated uses or insert the old untrusted body as raw HTML.
No caller change is made in this design folder. This is a documented integration decision, not a claim of drop-in compatibility or new application fields. The markup escapes all dynamic strings; explicit numeric counts remain visible even when zero.
Portable HTML/text and safe handling
ready/product-import-completed.html and ready/product-import-completed.txt provide the portable extracts. Every populated state has matching .html and .txt files under previews/. All sample links are local design explanations; no real invitation, report or account action is executed. Placeholder {{names}} are not automatically Laravel Blade syntax. Convert each mapping explicitly using existing data and server-side URL generation; retain all required values and do not insert untrusted raw HTML.
Escape text and attribute values. Validate any application/CFO AI URL separately against approved HTTPS hosts before escaping it; preserve complete generated links and encrypted/signed parameters. Use the provided concrete public PNG or an approved HTTPS/CID override. There are no hidden optional content sections to populate here; required identities/counts should not be silently omitted. Unsupported data has not been invented.
All drafts use the approved compact transactional shell with 16px body text, a minimal Built footer and native light/dark CSS. Email-client rendering and blocked-image behavior remain separate tests. See integration-notes.html for shared provider/image limitations, and easy-wins-batch.md for the whole batch. No production template, sender, transport or application behavior is changed.