stock-monitoring
v0.0.6
Published
Monitor product inventory levels and send email notifications for low stock, out of stock, and slow-moving products.
Maintainers
Readme
stock-monitoring
Medusa v2 plugin that monitors inventory levels (low, out-of-stock, and slow-moving) and sends admin notification alerts.
Plugin Overview
stock-monitoring adds stock alert monitoring to Medusa by:
- Evaluating inventory quantities per variant and per warehouse/location level.
- Detecting three alert types:
low_stockout_of_stockslow_moving
- Running a scheduled daily stock check job.
- Sending notification emails to configured admin recipients via Medusa notification module.
- Exposing an admin API for listing/filtering alerts.
- Providing an admin route page for alert visualization and filtering.
This plugin is built for Medusa v2 (uses Medusa module/workflow/job/admin-sdk APIs).
Installation & Setup
1) Install package
npm install stock-monitoring
# or
yarn add stock-monitoring2) Register in medusa-config.ts
import { defineConfig } from "@medusajs/framework/utils"
export default defineConfig({
modules: {
stock_monitoring: {
resolve: "stock-monitoring",
options: {
low_stock_threshold: 10,
slow_moving_days_threshold: 90,
low_stock_threshold_per_warehouse: {
// "sloc_...": 5
},
admin_notification_emails: ["[email protected]"],
},
},
},
plugins: [
{
resolve: "stock-monitoring",
options: {
low_stock_threshold: 10,
slow_moving_days_threshold: 90,
low_stock_threshold_per_warehouse: {},
admin_notification_emails: ["[email protected]"],
},
},
],
})3) Migrations
No plugin-specific database models/migrations are defined in this codebase.
You can still run standard app migrations as usual:
npx medusa db:migrateConfiguration (config.ts / plugin options)
Configuration is defined by StockMonitoringPluginOptions (src/types/stock-monitoring.ts) and validated in src/modules/stock-monitoring/service.ts.
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
| low_stock_threshold | number | Optional | 10 | Global threshold used for low-stock alerts. |
| slow_moving_days_threshold | number | Optional | 90 | Days-since-update threshold for slow-moving alerts. |
| low_stock_threshold_per_warehouse | Record<string, number> | Optional | {} | Per-location threshold override keyed by location_id. |
| admin_notification_emails | string[] | Optional | [] | Recipients for stock alert notifications. If empty, job skips sending notifications. |
Validation behavior:
- Thresholds must be integers and
>= 0. - Email list must be an array of strings; empty/whitespace entries are ignored.
Complete example config block
{
modules: {
stock_monitoring: {
resolve: "stock-monitoring",
options: {
low_stock_threshold: 12,
slow_moving_days_threshold: 120,
low_stock_threshold_per_warehouse: {
sloc_warehouse_a: 5,
sloc_warehouse_b: 20,
},
admin_notification_emails: [
"[email protected]",
"[email protected]",
],
},
},
},
plugins: [
{
resolve: "stock-monitoring",
options: {
low_stock_threshold: 12,
slow_moving_days_threshold: 120,
low_stock_threshold_per_warehouse: {
sloc_warehouse_a: 5,
sloc_warehouse_b: 20,
},
admin_notification_emails: [
"[email protected]",
"[email protected]",
],
},
},
],
}Environment Variables
No runtime process.env.* usage is present in this plugin’s src code.
| Variable | Used in src runtime code? | Notes |
|---|---|---|
| None | No | All plugin behavior is configured through Medusa module/plugin options. |
REST APIs / Routes
Admin APIs
GET /admin/stock-monitoring/alerts
- Auth requirement: Admin JWT (admin namespace route)
- Query params:
| Param | Type | Required | Default | Notes |
|---|---|---|---|---|
| limit | number string | No | 50 | Clamped to 1..200. |
| offset | number string | No | 0 | Min 0. |
| alert_type | enum | No | — | low_stock, out_of_stock, slow_moving. |
| product_id | string | No | — | Exact product id filter. |
| variant_id | string | No | — | Exact variant id filter. |
| search | string | No | — | Case-insensitive title search (product or variant). |
- Response schema:
| Field | Type |
|---|---|
| alerts | StockAlertInput[] |
| count | number |
| limit | number |
| offset | number |
StockAlertInput includes:
variant_idproduct_idproduct_titlevariant_titlecurrent_quantityalert_typeoptional
thresholdoptional
days_unchangedoptional
location_idoptional
location_nameDescription: Computes current alert list from product + inventory queries, applies filters, returns paginated results.
Health routes
GET /admin/plugin->200GET /store/plugin->200
Important endpoint examples
# List alerts (first page)
curl "http://localhost:9000/admin/stock-monitoring/alerts?limit=50&offset=0" \
-H "Authorization: Bearer <ADMIN_JWT>"# Filter by out-of-stock alerts
curl "http://localhost:9000/admin/stock-monitoring/alerts?alert_type=out_of_stock" \
-H "Authorization: Bearer <ADMIN_JWT>"# Search by title
curl "http://localhost:9000/admin/stock-monitoring/alerts?search=laptop" \
-H "Authorization: Bearer <ADMIN_JWT>"Services
StockMonitoringModuleService
Located at src/modules/stock-monitoring/service.ts.
What it manages:
- Option resolution/validation.
- Exposes threshold and notification recipient getters used by jobs/routes.
Key methods:
getLowStockThreshold(): numbergetSlowMovingDaysThreshold(): numbergetLowStockThresholdForWarehouse(locationId: string): numbergetAdminNotificationEmails(): string[]
Workflow step dependencies (notification sending)
send-stock-notification-step resolves:
Modules.NOTIFICATIONservice for sending email notifications.ContainerRegistrationKeys.LOGGERfor structured logs.
Workflows & Steps (Medusa v2)
Workflow: send-stock-alert
File: src/workflows/send-stock-alert-workflow.ts
- Input:
alerts: StockAlertInput[]adminEmails: string[]
- Steps:
send-stock-notification
- Output:
sent: booleanalertsSent: number
Step: send-stock-notification
File: src/workflows/steps/send-stock-notification-step.ts
Behavior:
- Skips if no alerts or no admin emails.
- Builds email payload per recipient with alert summary text.
- Uses notification service:
- prefers
createNotifications(payloads) - falls back to
create(payload)one by one
- prefers
- Includes retry with exponential backoff:
- max retries: 3
- delays: 1s, 2s, 4s
Subscribers / Event Hooks
No subscribers are implemented in this plugin (src/subscribers contains README only).
Jobs
Job: check-stock-levels
File: src/jobs/check-stock-levels.ts
Schedule: 0 0 * * * (daily at midnight)
Behavior summary:
- Resolves thresholds/emails from
stock_monitoringservice. - Loads products/variants and inventory items.
- Resolves per-location inventory levels via:
- inventory module service (
listInventoryLevels) if available, - batch graph query fallback,
- per-item graph query fallback.
- inventory module service (
- Generates:
out_of_stockalerts first (quantity <= 0)low_stockalerts using warehouse-specific threshold (or global fallback)slow_movingalerts based on days since location-level update.
- Executes
send-stock-alertworkflow when alerts exist.
Admin UI / Widgets
This plugin adds an admin route (not a widget zone injection):
Admin Route: stock-monitoring-alerts
- File:
src/admin/routes/stock-monitoring-alerts/page.tsx - Route config label:
Stock Alerts - UI renders:
- alerts table
- search input
- alert-type filter dropdown
- pagination/load-more controls
- refresh action
- action button to navigate to product detail (
/products/:id)
- Data source:
GET /admin/stock-monitoring/alerts
Models & Entities
No custom model/entity definitions are implemented in this plugin source.
Data sources used are Medusa core entities queried via graph/services:
productproduct.variantsinventory_iteminventory levels/location relations(via inventory service or graph fields)
Use Cases & Examples
Daily low-stock operations monitoring
- Configure thresholds and recipient list, then rely on daily
check-stock-levelsjob notifications.
- Configure thresholds and recipient list, then rely on daily
Warehouse-specific threshold enforcement
- Use
low_stock_threshold_per_warehouseto flag low stock differently across locations.
- Use
Out-of-stock escalation
- Detect immediate zero-quantity variants and trigger recipient notifications.
Slow-moving inventory review
- Use
slow_moving_days_thresholdto surface variants whose inventory hasn’t changed for long periods.
- Use
Admin-side alert triage
- Use
/admin/stock-monitoring/alertsand admin route filters/search to prioritize replenishment actions.
- Use
Troubleshooting
No alert emails are sent
- Cause:
admin_notification_emailsis empty/missing. - Fix: set non-empty recipient emails in plugin/module options.
Plugin startup fails with threshold validation errors
- Cause: thresholds are non-numeric, non-integer, or negative.
- Fix: set integer values
>= 0for:low_stock_thresholdslow_moving_days_thresholdlow_stock_threshold_per_warehouse[*]
Alerts show unexpected warehouse data
- Cause: location level resolution falls back based on available query/service data.
- Fix: verify inventory levels, location IDs, and location names are properly configured in inventory module data.
No alerts found even though stock is low
- Cause: threshold/warehouse filter mismatch or inventory-level retrieval issues.
- Fix: verify effective threshold (global vs per-warehouse), inventory quantities, and location-level links for variants.
Notification send failures
- Cause: notification module unavailable or provider-level send failures.
- Fix: ensure
Modules.NOTIFICATIONis configured and a notification provider is active; inspect logs for retry attempts/errors.
Admin alerts endpoint errors
- Cause: graph query/runtime data issues.
- Fix: inspect server logs, verify inventory/product graph entities and module health.
