Skip to main content

Customer Design Notifications

Last updated: 2026-03-24

This document covers the event-driven notification system that keeps customers informed about their design lifecycle — from assignment through inventory linking, production, and completion.


Overview

When a design is created for (or by) a customer, the system sends email notifications at each meaningful milestone. All notifications flow through a single generic workflow that resolves the linked customer and sends a templated email.

Design Created → Assigned → Inventory Linked → Production Started → Production Completed
↓ ↓ ↓ ↓ ↓
design.assigned design.assigned design.inventory_linked design.production_started design.production_completed
↓ ↓ ↓ ↓ ↓
[subscriber] [subscriber] [subscriber] [subscriber] [subscriber]
↓ ↓ ↓ ↓ ↓
Email sent Email sent Email sent Email sent Email sent

Status transitions (e.g. In_Development, Technical_Review, Approved) are also captured via the design.updated event and send status update emails.


Events & Subscribers

EventEmitted FromSubscriberEmail Template
design.assignedcreateDesignWorkflow (when customer_id_for_link is set)design-assigned.tsdesign-assigned
design.updatedMedusa auto-emit on model updatedesign-commerce-ready.tsdesign-status-updated
design.inventory_linkedlinkDesignInventoryWorkflowdesign-inventory-linked.tsdesign-inventory-linked
design.production_startedsendProductionRunToProductionWorkflowdesign-production-started.tsdesign-production-started
design.production_completedproduction-run-task-updated.ts subscriber (when all tasks complete)design-production-completed.tsdesign-production-completed

Architecture

Generic Status Update Workflow

All design lifecycle notifications (except the initial assignment) use sendDesignStatusUpdateEmailWorkflow:

src/workflows/email/workflows/send-design-status-update-email.ts

Steps:

  1. resolveCustomerFromDesignStep — Queries designCustomerLink to find the linked customer. Returns null if no customer is linked (email is silently skipped).
  2. transform — Builds the email payload with customer name, design name, status, and any extra template data.
  3. sendNotificationEmailStep — Creates a notification via Medusa's notification module, which routes to the configured email provider (Resend for customer emails).

This workflow accepts a templateKey parameter, making it reusable for all design notification types.

Design Assignment Workflow

The design.assigned event uses the original sendDesignAssignedEmailWorkflow which takes a customerId directly (since it's emitted from createDesignWorkflow where the customer ID is already known).

src/workflows/email/workflows/send-design-assigned-email.ts

Event Emission Points

design.assigned — in createDesignWorkflow

The emitDesignAssignedStep fires inside the conditional when(customer_id_for_link) block, right after linkDesignToCustomerStep. This means both admin and store design creation paths emit the event from the workflow itself — no API-level event emission needed.

// src/workflows/designs/create-design.ts
when({ input, design }, ({ input }) => Boolean(input.customer_id_for_link)).then(() => {
linkDesignToCustomerStep(...)
emitDesignAssignedStep({
design_id, customer_id, design_name, design_status
})
})

design.inventory_linked — in linkDesignInventoryWorkflow

The emitDesignInventoryLinkedStep fires after inventory links are created:

// src/workflows/designs/inventory/link-inventory.ts
const linksResult = createDesignInventoryLinks(...)
emitDesignInventoryLinkedStep({ design_id, inventory_count })

design.production_started — in sendProductionRunToProductionWorkflow

Emitted alongside the existing production_run.sent_to_partner event in notifyPartnerStep:

// src/workflows/production-runs/send-production-run-to-production.ts
await eventService.emit([
{ name: "production_run.sent_to_partner", data: { ... } },
{ name: "design.production_started", data: { design_id, production_run_id } },
])

design.production_completed — in production-run-task-updated subscriber

Emitted after a production run's status is set to completed:

// src/subscribers/production-run-task-updated.ts
await productionRunService.updateProductionRuns({ id, status: "completed" })
await eventBus.emit({
name: "design.production_completed",
data: { design_id, production_run_id },
})

Status Change Notifications

The design-commerce-ready.ts subscriber (listening on design.updated) handles all status transitions. It notifies customers for the following statuses:

StatusMeaning
In_DevelopmentPartner has started work
Technical_ReviewPartner has finished, awaiting review
Sample_ProductionSample is being produced
ApprovedDesign has been approved
Commerce_ReadyDesign promoted to product (also triggers promoteDesignToProductWorkflow)

Statuses like Conceptual, Revision, On_Hold, and Rejected do not trigger customer emails — they're internal workflow states.


Email Templates

All templates are seeded via src/scripts/seed-email-templates.ts. Run the seed script after deployment to populate new templates.

Template KeySubjectVariables
design-assignedYour custom design is ready: {{design_name}}customer_name, design_name, design_url, design_status
design-status-updatedDesign update: {{design_name}} is now {{design_status}}recipient_name, design_name, previous_status, design_status, updated_by, design_url
design-inventory-linkedMaterials assigned to your design: {{design_name}}customer_name, design_name, design_status, design_url
design-production-startedProduction has started for your design: {{design_name}}customer_name, design_name, design_url
design-production-completedProduction complete for your design: {{design_name}}customer_name, design_name, design_url

All templates use the [email protected] sender address and are sent via the email channel (Resend provider).


File Reference

Workflows

FilePurpose
src/workflows/email/workflows/send-design-status-update-email.tsGeneric workflow — resolves customer from design link, sends templated email
src/workflows/email/workflows/send-design-assigned-email.tsAssignment-specific workflow (takes customerId directly)
src/workflows/designs/create-design.tsEmits design.assigned in emitDesignAssignedStep
src/workflows/designs/inventory/link-inventory.tsEmits design.inventory_linked in emitDesignInventoryLinkedStep
src/workflows/production-runs/send-production-run-to-production.tsEmits design.production_started in notifyPartnerStep

Subscribers

FileEventAction
src/subscribers/design-assigned.tsdesign.assignedSends assignment email
src/subscribers/design-commerce-ready.tsdesign.updatedSends status update email + promotes to product on Commerce_Ready
src/subscribers/design-inventory-linked.tsdesign.inventory_linkedSends inventory linked email
src/subscribers/design-production-started.tsdesign.production_startedSends production started email
src/subscribers/design-production-completed.tsdesign.production_completedSends production completed email
FileRelationship
src/links/design-customer-link.tsDesign ↔ Customer (many-to-many, used by resolveCustomerFromDesignStep)

Cart & Post-Payment Flow

The notification system integrates with the existing order flow without requiring changes to the cart or checkout process:

  1. Customer adds design to cart via POST /store/custom/designs/:id/checkout
  2. Customer completes payment (standard Medusa checkout)
  3. order.placed subscriber fires:
    • Creates design ↔ order links
    • Creates ProductionRun for each design-linked line item
  4. When the production run is dispatched to a partner → design.production_started email
  5. When all tasks complete → design.production_completed email

The order confirmation email (existing) covers the payment/receipt side. The design notifications cover the production/fulfillment side.


Manual Notification Trigger

Admins can manually re-send the design assignment email:

POST /admin/designs/:id/notify-customer

This endpoint looks up the linked customer via designCustomerLink and triggers sendDesignAssignedEmailWorkflow. Useful when the initial email fails or the customer needs a reminder.