Low Stock Alert Communication System Integration
π Overviewβ
The low stock alert system has been refactored to use the proper multi-channel communication system instead of hardcoded email logic. This provides a robust, configurable, and enterprise-grade notification system.
π― What Changedβ
Before (Old System) ββ
The email service had hardcoded logic:
// β OLD: Hardcoded in email.service.ts
@OnEvent(OnCreateLowStockAlertEvent.eventName)
async handleOnCreateLowStockAlertEvent() {
const to = "luisrangelc@rpasolution.com"; // π΄ Hardcoded email
await sgMail.send(msg); // π΄ Direct SendGrid call
console.log("Email sent"); // π΄ Console logging
}
Problems:
- π΄ Always sent to same hardcoded email
- π΄ Bypassed business communication configuration
- π΄ No rate limiting
- π΄ No multi-channel support (SMS/WhatsApp)
- π΄ Used
console.loginstead of proper logger - π΄ Ignored template system
- π΄ No proper error handling
After (New System) β β
Now uses the proper communication system:
// β
NEW: Proper handler in communications module
@OnEvent(OnCreateLowStockAlertEvent.eventName)
async handleOnCreateLowStockAlert(event) {
// 1. Get template from system
const template = await this.templatesService.findByCode('low_stock_alert_email');
// 2. Get business users who should receive alerts
const businessUsers = await this.businessUsersService.findByBusinessId(businessId);
// 3. Send via communication system (respects config, rate limits, etc.)
await this.communicationsService.send({
type: "low_stock_alert",
channel: "email", // Can be SMS/WhatsApp based on config
templateId: template.id,
recipientContact: user.email,
// ... proper configuration
});
}
β Benefitsβ
1. Dynamic Recipientsβ
- Sends to all active business users (not hardcoded)
- Each business's users get their own alerts
- Easy to add role-based filtering (e.g., only managers)
2. Business Configurationβ
- Respects
business_communication_configtable - Can enable/disable per business
- Can set as automatic or manual
- Honors time windows (don't send at 3am!)
3. Multi-Channel Supportβ
- Email (primary)
- SMS (can be enabled)
- WhatsApp (can be enabled)
- Future: Messenger, Slack, etc.
4. Rate Limitingβ
- Won't spam users with too many alerts
- Configurable: max sends per day, minimum interval
- Professional behavior
5. Professional Templatesβ
- Uses
low_stock_alert_emailtemplate from database - Brandable and customizable per business
- Consistent formatting
6. Reliabilityβ
- Queued delivery (won't lose messages if server restarts)
- Retry logic built-in
- Dead letter queue for failed messages
- Proper error handling and logging
7. Observabilityβ
- All communications logged to
communicationtable - Can track: sent, delivered, opened, clicked
- Easy to debug issues
ποΈ Architectureβ
Event Flowβ
graph TD
A[LowStockAlertsScheduler] -->|Creates Alert| B[LowStockAlert Created]
B -->|Emits Event| C[OnCreateLowStockAlertEvent]
C -->|Handled By| D[OnCreateLowStockAlertHandler]
D -->|Gets Users| E[BusinessUsersService]
D -->|Gets Template| F[CommunicationTemplatesService]
D -->|Sends| G[CommunicationsService]
G -->|Checks Config| H[BusinessCommunicationConfigService]
G -->|Queues| I[CommunicationQueueService]
I -->|Processes| J[Email/SMS/WhatsApp Adapter]
J -->|Delivers| K[Recipient]
Key Componentsβ
1. LowStockAlertsScheduler (Existing - Enhanced)β
- File:
apps/backend/src/low-stock-alerts/jobs/low-stock-alerts.scheduler.ts - Enhancements:
- β Idempotency (checks for existing alerts)
- β Bulk operations (faster processing)
- β Granular error handling
- β Type-safe constants
- β Better logging with metrics
2. OnCreateLowStockAlertHandler (New)β
- File:
apps/backend/src/communications/application/events/on-create-low-stock-alert.handler.ts - Purpose: Proper event handler for low stock alerts
- Features:
- Fetches business users dynamically
- Uses template system
- Sends via communication system
- Handles errors gracefully
3. BusinessUsersService (Enhanced)β
- File:
apps/backend/src/business-users/application/business-users.service.ts - New Method:
findByBusinessId(businessId)- Returns all active users for a business
- Includes user email and full name
- Used to determine alert recipients
4. Low Stock Alert Constants (New)β
-
File:
apps/backend/src/low-stock-alerts/domain/low-stock-alerts.constants.ts -
Purpose: Type-safe constants for status and identifiers
-
Constants:
LowStockAlertStatus = { ACTIVE, RESOLVED, DISMISSED }
SystemIdentifiers = { LOW_STOCK_CHECK, MANUAL_CREATION }
π§ Configurationβ
1. Enable/Disable for a Businessβ
Low stock alerts respect the business_communication_config table:
-- Enable email alerts for a business
UPDATE business_communication_config
SET is_enabled = true,
is_automatic = true
WHERE business_id = 'your-business-id'
AND communication_type = 'low_stock_alert'
AND channel = 'email';
2. Configure Time Windowsβ
Only send alerts during business hours:
UPDATE business_communication_config
SET send_time_window_start = '08:00:00',
send_time_window_end = '20:00:00',
timezone = 'America/Mexico_City'
WHERE business_id = 'your-business-id'
AND communication_type = 'low_stock_alert';
3. Rate Limitingβ
Prevent alert fatigue:
UPDATE business_communication_config
SET max_sends_per_recipient_per_day = 3, -- Max 3 alerts per day
min_interval_minutes = 240 -- At least 4 hours between alerts
WHERE business_id = 'your-business-id'
AND communication_type = 'low_stock_alert';
4. Add SMS/WhatsApp Supportβ
-- Enable WhatsApp alerts (requires Twilio setup)
UPDATE business_communication_config
SET is_enabled = true,
is_automatic = true
WHERE business_id = 'your-business-id'
AND communication_type = 'low_stock_alert'
AND channel = 'whatsapp';
π§ Template Variablesβ
The low_stock_alert_email template has access to:
| Variable | Type | Example | Description |
|---|---|---|---|
locationName | string | "Main Store" | Name of the location with low stock |
alertDate | string | "October 25, 2025, 10:30 AM" | When the alert was created |
itemCount | number | 15 | Number of low stock items |
items | array | [{name, sku, currentStock, minStock, category}] | Array of low stock items |
recipientName | string | "John Doe" | Name of the person receiving alert |
businessId | string | "uuid" | Business identifier |
locationId | string | "uuid" | Location identifier |
Example Template Usageβ
<h1>π΄ Low Stock Alert - {{locationName}}</h1>
<p>Dear {{recipientName}},</p>
<p>We detected {{itemCount}} items that are running low on stock at {{locationName}} as of {{alertDate}}.</p>
<table>
<thead>
<tr>
<th>Item</th>
<th>SKU</th>
<th>Current</th>
<th>Minimum</th>
<th>Category</th>
</tr>
</thead>
<tbody>
{{#each items}}
<tr>
<td>{{name}}</td>
<td>{{sku}}</td>
<td>{{currentStock}}</td>
<td>{{minStock}}</td>
<td>{{category}}</td>
</tr>
{{/each}}
</tbody>
</table>
π§ͺ Testingβ
Manual Testβ
To test the system without waiting for the scheduler:
// In your test file or temp controller
async testLowStockAlert() {
const testAlert = {
businessId: 'test-business-id',
locationId: 'test-location-id',
locationName: 'Test Location',
alertDate: new Date(),
detail: JSON.stringify({
items: [
{
itemName: 'Test Product',
itemSku: 'TEST-001',
currentStock: 5,
minStock: 10,
categoryName: 'Test Category'
}
]
}),
status: 'ACTIVE',
createdBy: 'test-user'
};
// This will trigger the event and send notifications
await this.lowStockAlertsService.addLowStockAlert(testAlert);
}
Verifyβ
- Check
communicationtable for created records - Check
communication_queuefor queued items - Check recipient's email inbox
- Check logs for success/error messages
π Monitoringβ
Query Recent Alertsβ
SELECT
c.id,
c.type,
c.channel,
c.status,
c.recipient_contact,
c.created_at,
c.sent_at,
c.delivered_at
FROM communication c
WHERE c.type = 'low_stock_alert'
AND c.created_at > NOW() - INTERVAL '24 hours'
ORDER BY c.created_at DESC;
Check Failed Deliveriesβ
SELECT *
FROM communication
WHERE type = 'low_stock_alert'
AND status IN ('failed', 'bounced')
AND created_at > NOW() - INTERVAL '7 days';
User Alert Frequencyβ
SELECT
recipient_contact,
COUNT(*) as alert_count,
MAX(sent_at) as last_sent
FROM communication
WHERE type = 'low_stock_alert'
AND created_at > NOW() - INTERVAL '24 hours'
GROUP BY recipient_contact
ORDER BY alert_count DESC;
π Future Enhancementsβ
1. Role-Based Recipientsβ
Filter recipients by role (only send to managers/admins):
const businessUsers = await this.businessUsersService.findByBusinessId(businessId);
const managers = businessUsers.filter(u =>
['admin', 'manager', 'inventory_manager'].includes(u.uniqueRoleName)
);
2. Location-Specific Recipientsβ
Send to users assigned to specific locations:
// Add location filtering
const locationUsers = await this.businessUsersService.findByLocation(locationId);
3. Alert Aggregationβ
Instead of sending one alert per item, aggregate by day:
// Send daily digest at 8am with all low stock items
const dailyDigest = await this.aggregateLowStockAlerts(businessId);
4. Priority Levelsβ
Different handling for critical vs warning levels:
if (currentStock === 0) {
priority = 'critical'; // Send immediately
} else if (currentStock < minStock * 0.5) {
priority = 'high';
} else {
priority = 'normal';
}
5. Custom Thresholdsβ
Per-user preferences for when to receive alerts:
// Only notify me if stock is below 25% of minimum
const userPrefs = await getUserAlertPreferences(userId);
π Troubleshootingβ
Not Receiving Alerts?β
-
Check if enabled for business:
SELECT * FROM business_communication_config
WHERE business_id = 'your-id'
AND communication_type = 'low_stock_alert'
AND channel = 'email'; -
Check if users exist:
SELECT bu.*, u.email, u.full_name
FROM business_user bu
JOIN "user" u ON u.id = bu.user_id
WHERE bu.business_id = 'your-id'
AND bu.is_active = true; -
Check communication queue:
SELECT * FROM communication_queue
WHERE status = 'failed'
ORDER BY created_at DESC
LIMIT 10; -
Check application logs:
# Look for OnCreateLowStockAlertHandler logs
grep "OnCreateLowStockAlertHandler" logs/app.log
Receiving Too Many Alerts?β
Adjust rate limiting in business_communication_config:
UPDATE business_communication_config
SET max_sends_per_recipient_per_day = 2,
min_interval_minutes = 360 -- 6 hours
WHERE communication_type = 'low_stock_alert';
π Related Documentationβ
- Multi-Channel Communication System
- Business Communication Configuration Guide
- Low Stock Alerts Scheduler
β Migration Checklistβ
- Created
OnCreateLowStockAlertHandlerin communications module - Added
findByBusinessId()method to BusinessUsersService - Registered handler in CommunicationsModule
- Removed hardcoded email logic from EmailService
- Added type-safe constants for alert status
- Enhanced scheduler with idempotency and bulk operations
- Documented the new system
- Test in staging environment
- Verify email delivery
- Monitor for 24 hours
- Deploy to production
Last Updated: October 25, 2025 Status: β Complete Version: 2.0