🚨 Phase 6: Alerts & Notifications

Automated Monitoring & Alert Systems

Duration: 2-3 weeks | Complexity: Intermediate

📋 Phase Overview

This phase implements comprehensive alert and notification systems to proactively manage farm operations. You'll create weather-based alerts, task scheduling systems, equipment maintenance notifications, inventory alerts, and multi-channel communication (email, SMS, in-app notifications).

End Goal: Automated monitoring system that keeps you informed of critical events and upcoming tasks.

⚠️ Prerequisites

  • Phase 5 Completed: Analytics and reporting functional
  • Email Configuration: SMTP settings configured
  • Weather Service: OpenWeather API integration working
  • Task Scheduler: Laravel's task scheduling setup
1

Install Notification Dependencies

Install packages for email, SMS, and push notifications.

Install Notification Services:

# Install Laravel Notifications (included by default) # Install SMS service (Twilio) composer require twilio/sdk # Install push notification service composer require laravel-notification-channels/webpush # Install email queue processing composer require laravel/horizon

Configure Notification Channels:

# Configure mail settings in .env MAIL_MAILER=smtp MAIL_HOST=your-smtp-host MAIL_PORT=587 MAIL_USERNAME=your-email MAIL_PASSWORD=your-password # Add Twilio settings TWILIO_SID=your-twilio-sid TWILIO_TOKEN=your-twilio-token TWILIO_FROM=your-twilio-number
2

Weather Alert System

Create comprehensive weather monitoring and alert system for frost warnings and extreme weather.

Weather Alert Service:

# Create weather alert service php artisan make:command CheckWeatherAlerts # Create notification classes php artisan make:notification FrostWarning php artisan make:notification ExtremeWeatherAlert php artisan make:notification HarvestWeatherAlert

Weather Alert Implementation:

fetchCurrentWeather(); $forecast = $weatherService->get5DayForecast(); if (!$weather || !$forecast) { $this->error('Failed to fetch weather data'); return 1; } $this->checkFrostWarnings($weather, $forecast); $this->checkExtremeWeather($weather, $forecast); $this->checkHarvestConditions($weather, $forecast); return 0; } private function checkFrostWarnings($current, $forecast) { $frostTemp = config('weather.frost_warning_temp', 36); $freezeTemp = config('weather.freeze_warning_temp', 32); // Check current conditions if ($current['main']['temp'] <= $freezeTemp) { $this->sendAlert(new FrostWarning('freeze', $current['main']['temp'], 'current')); } elseif ($current['main']['temp'] <= $frostTemp) { $this->sendAlert(new FrostWarning('frost', $current['main']['temp'], 'current')); } // Check forecast for next 48 hours foreach ($forecast['list'] as $item) { $temp = $item['main']['temp_min']; $datetime = \Carbon\Carbon::createFromTimestamp($item['dt']); if ($datetime->diffInHours(now()) <= 48) { if ($temp <= $freezeTemp) { $this->sendAlert(new FrostWarning('freeze', $temp, $datetime)); } elseif ($temp <= $frostTemp) { $this->sendAlert(new FrostWarning('frost', $temp, $datetime)); } } } } private function checkExtremeWeather($current, $forecast) { // Check for high winds if (($current['wind']['speed'] ?? 0) > 25) { // 25+ mph $this->sendAlert(new ExtremeWeatherAlert('high_wind', $current['wind']['speed'])); } // Check for heavy rain if (($current['rain']['1h'] ?? 0) > 0.5) { // >0.5 inches per hour $this->sendAlert(new ExtremeWeatherAlert('heavy_rain', $current['rain']['1h'])); } // Check for extreme temperatures if ($current['main']['temp'] > 95) { $this->sendAlert(new ExtremeWeatherAlert('extreme_heat', $current['main']['temp'])); } } private function sendAlert($notification) { $users = User::whereHas('preferences', function($query) { $query->where('weather_alerts', true); })->get(); foreach ($users as $user) { $user->notify($notification); } } }

Frost Warning Notification:

type = $type; $this->temperature = $temperature; $this->when = $when; } public function via($notifiable) { return ['mail', 'database']; } public function toMail($notifiable) { $subject = $this->type === 'freeze' ? '🧊 FREEZE WARNING' : '❄️ Frost Warning'; return (new MailMessage) ->subject($subject . ' - Blackberry Farm Alert') ->line("Weather alert for your blackberry farm!") ->line("Temperature: {$this->temperature}°F") ->line("Time: " . ($this->when === 'current' ? 'Now' : $this->when->format('M j, Y g:i A'))) ->line('Recommended Actions:') ->line('• Cover sensitive plants') ->line('• Run irrigation if available') ->line('• Check plant protection measures') ->action('View Weather Dashboard', route('weather.dashboard')); } public function toArray($notifiable) { return [ 'type' => 'weather_alert', 'alert_type' => $this->type, 'temperature' => $this->temperature, 'when' => $this->when, 'message' => "{$this->type} warning: {$this->temperature}°F" ]; } }
3

Task Scheduling & Reminders

Create automated task scheduling with smart reminders based on plant lifecycle and seasonal needs.

Task Reminder System:

# Create task reminder command php artisan make:command SendTaskReminders # Create task notification php artisan make:notification TaskReminder php artisan make:notification OverdueTaskAlert

Task Management Features:

class TaskReminderService { public function generateSeasonalTasks() { $currentMonth = now()->month; $tasks = []; switch ($currentMonth) { case 3: // March $tasks = [ ['task' => 'Apply pre-emergent fertilizer', 'priority' => 'high'], ['task' => 'Prune winter-damaged canes', 'priority' => 'high'], ['task' => 'Check irrigation system', 'priority' => 'medium'] ]; break; case 6: // June $tasks = [ ['task' => 'Summer harvest preparation', 'priority' => 'high'], ['task' => 'Pest monitoring and treatment', 'priority' => 'medium'], ['task' => 'Weed control', 'priority' => 'medium'] ]; break; case 9: // September $tasks = [ ['task' => 'Fall fertilizer application', 'priority' => 'high'], ['task' => 'Air layering opportunity', 'priority' => 'high'], ['task' => 'Soil testing', 'priority' => 'medium'] ]; break; } return $tasks; } public function checkPlantSpecificTasks() { $tasks = []; // Check plants needing measurement $plantsNeedingMeasurement = Plant::whereDoesntHave('measurements', function($query) { $query->where('measurement_date', '>=', now()->subDays(30)); })->get(); foreach ($plantsNeedingMeasurement as $plant) { $tasks[] = [ 'plant_id' => $plant->plant_id, 'task' => 'Record growth measurements', 'priority' => 'medium', 'due_date' => now()->addDays(7) ]; } // Check air layers ready for separation $readyAirLayers = AirLayer::readyForSeparation()->get(); foreach ($readyAirLayers as $layer) { $tasks[] = [ 'air_layer_id' => $layer->layer_id, 'task' => 'Separate air layer from parent plant', 'priority' => 'high', 'due_date' => now()->addDays(3) ]; } return $tasks; } }
4

Equipment Maintenance Alerts

Create automated equipment maintenance scheduling and alerts.

Equipment Maintenance System:

# Create maintenance alert command php artisan make:command CheckEquipmentMaintenance # Create maintenance notifications php artisan make:notification MaintenanceDue php artisan make:notification MaintenanceOverdue

Maintenance Alert Logic:

class EquipmentMaintenanceService { public function checkMaintenanceSchedules() { $equipment = Equipment::where('active', true)->get(); $alerts = []; foreach ($equipment as $item) { $maintenance = $this->calculateNextMaintenance($item); if ($maintenance['status'] === 'overdue') { $alerts[] = [ 'type' => 'overdue', 'equipment' => $item, 'days_overdue' => $maintenance['days_overdue'], 'priority' => 'critical' ]; } elseif ($maintenance['status'] === 'due_soon') { $alerts[] = [ 'type' => 'due_soon', 'equipment' => $item, 'days_until_due' => $maintenance['days_until_due'], 'priority' => 'high' ]; } } return $alerts; } private function calculateNextMaintenance($equipment) { $lastMaintenance = $equipment->last_maintenance_date ?: $equipment->purchase_date; // Define maintenance intervals by equipment type $intervals = [ 'irrigation' => 90, // days 'tractor' => 60, 'sprayer' => 30, 'harvesting' => 45 ]; $interval = $intervals[$equipment->equipment_category] ?? 90; $nextDue = $lastMaintenance->addDays($interval); $daysUntilDue = now()->diffInDays($nextDue, false); if ($daysUntilDue < 0) { return [ 'status' => 'overdue', 'days_overdue' => abs($daysUntilDue), 'next_due' => $nextDue ]; } elseif ($daysUntilDue <= 7) { return [ 'status' => 'due_soon', 'days_until_due' => $daysUntilDue, 'next_due' => $nextDue ]; } return [ 'status' => 'ok', 'days_until_due' => $daysUntilDue, 'next_due' => $nextDue ]; } }
5

Inventory Level Alerts

Create automated inventory monitoring with low stock and expiration alerts.

Inventory Alert System:

class InventoryAlertService { public function checkInventoryLevels() { $alerts = []; // Check product inventory levels $products = ValueAddProduct::all(); foreach ($products as $product) { $inventory = $product->getCurrentInventory(); $minimumStock = $this->getMinimumStockLevel($product); if ($inventory <= 0) { $alerts[] = [ 'type' => 'out_of_stock', 'product' => $product, 'current_stock' => $inventory, 'priority' => 'critical' ]; } elseif ($inventory <= $minimumStock) { $alerts[] = [ 'type' => 'low_stock', 'product' => $product, 'current_stock' => $inventory, 'minimum_stock' => $minimumStock, 'priority' => 'high' ]; } } // Check for expiring products $expiringBatches = ProductionBatch::expiringWithin(7)->get(); foreach ($expiringBatches as $batch) { $alerts[] = [ 'type' => 'expiring_soon', 'batch' => $batch, 'days_until_expiration' => $batch->days_until_expiration, 'priority' => $batch->days_until_expiration <= 3 ? 'critical' : 'high' ]; } return $alerts; } private function getMinimumStockLevel($product) { // Calculate minimum stock based on sales history $avgMonthlySales = Sale::where('product_id', $product->product_id) ->where('sale_date', '>=', now()->subMonths(6)) ->avg(\DB::raw('quantity')); return max(ceil($avgMonthlySales * 0.5), 5); // 2-week safety stock, minimum 5 units } }
6

Multi-Channel Notification System

Implement email, SMS, and in-app notifications with user preferences.

User Notification Preferences:

# Create user preferences migration php artisan make:migration add_notification_preferences_to_users_table # Migration content: Schema::table('users', function (Blueprint $table) { $table->json('notification_preferences')->nullable(); $table->string('phone')->nullable(); $table->boolean('sms_enabled')->default(false); });

Notification Preference Management:

class NotificationPreference extends Model { protected $fillable = [ 'user_id', 'weather_alerts', 'task_reminders', 'equipment_maintenance', 'inventory_alerts', 'harvest_reminders', 'email_enabled', 'sms_enabled', 'push_enabled', 'alert_frequency' ]; protected $casts = [ 'weather_alerts' => 'boolean', 'task_reminders' => 'boolean', 'equipment_maintenance' => 'boolean', 'inventory_alerts' => 'boolean', 'harvest_reminders' => 'boolean', 'email_enabled' => 'boolean', 'sms_enabled' => 'boolean', 'push_enabled' => 'boolean' ]; } // Universal notification sending method class NotificationService { public function sendAlert($user, $notification) { $preferences = $user->notificationPreferences; $channels = []; if ($preferences->email_enabled) { $channels[] = 'mail'; } if ($preferences->sms_enabled && $user->phone) { $channels[] = 'sms'; } if ($preferences->push_enabled) { $channels[] = 'database'; } // Respect quiet hours (10 PM to 6 AM) $currentHour = now()->hour; if ($currentHour >= 22 || $currentHour <= 6) { // Only send critical alerts during quiet hours if ($notification->priority !== 'critical') { return; } } $user->notify($notification); } }
7

Alert Dashboard & Management

Create dashboard for managing alerts and notification history.

Alert Dashboard Features:

// Alert Dashboard Controller class AlertDashboardController extends Controller { public function index() { $activeAlerts = Alert::where('status', 'active') ->orderByDesc('created_at') ->get(); $recentNotifications = auth()->user() ->notifications() ->latest() ->limit(10) ->get(); $alertStats = [ 'critical' => Alert::where('priority', 'critical')->where('status', 'active')->count(), 'high' => Alert::where('priority', 'high')->where('status', 'active')->count(), 'medium' => Alert::where('priority', 'medium')->where('status', 'active')->count(), 'resolved_today' => Alert::where('resolved_at', '>=', now()->startOfDay())->count() ]; return view('alerts.dashboard', compact('activeAlerts', 'recentNotifications', 'alertStats')); } public function acknowledge(Alert $alert) { $alert->update([ 'acknowledged_at' => now(), 'acknowledged_by' => auth()->id() ]); return response()->json(['status' => 'acknowledged']); } public function resolve(Alert $alert) { $alert->update([ 'status' => 'resolved', 'resolved_at' => now(), 'resolved_by' => auth()->id() ]); return redirect()->back()->with('success', 'Alert resolved successfully'); } } // Scheduled task to clean up old notifications class CleanupNotifications extends Command { protected $signature = 'notifications:cleanup'; public function handle() { // Delete notifications older than 30 days \DB::table('notifications') ->where('created_at', '<', now()->subDays(30)) ->delete(); // Archive resolved alerts older than 90 days Alert::where('status', 'resolved') ->where('resolved_at', '<', now()->subDays(90)) ->delete(); $this->info('Notification cleanup completed'); } }
8

Schedule All Alert Commands

Configure Laravel's task scheduler to run all alert checks automatically.

Task Scheduler Configuration (app/Console/Kernel.php):

protected function schedule(Schedule $schedule) { // Weather alerts - check every 30 minutes $schedule->command('weather:check-alerts')->everyThirtyMinutes(); // Task reminders - daily at 7 AM $schedule->command('tasks:send-reminders')->dailyAt('07:00'); // Equipment maintenance - weekly on Mondays $schedule->command('equipment:check-maintenance')->weeklyOn(1, '09:00'); // Inventory alerts - daily at 6 AM $schedule->command('inventory:check-levels')->dailyAt('06:00'); // Harvest window alerts - during harvest season, twice daily $schedule->command('harvest:check-windows') ->twiceDaily(8, 16) ->when(function () { $month = now()->month; return in_array($month, [6, 7, 8, 9, 10]); // Harvest months }); // Cleanup old notifications - weekly $schedule->command('notifications:cleanup')->weekly(); // Generate daily farm report - daily at 5 AM $schedule->command('reports:daily-summary')->dailyAt('05:00'); }

✅ Phase 6 Completion Checklist

  • Weather alert system with frost/freeze warnings
  • Automated task scheduling and reminders
  • Equipment maintenance alert system
  • Inventory level monitoring and alerts
  • Multi-channel notifications (email, SMS, in-app)
  • User notification preferences management
  • Alert dashboard with acknowledgment system
  • Scheduled task automation via cron
  • Notification history and cleanup
  • Priority-based alert filtering

🎯 Next Steps: Phase 7 Preparation

With Phase 6 complete, you're ready for Phase 7: Mobile App Development. The next phase will involve:

  • Laravel API development for mobile
  • Mobile app framework selection
  • Native QR code scanning
  • Offline data collection capabilities
  • Data synchronization features
💾

Create Phase 6 Backup

# Create database backup mysqldump -u wwwhom8_main -p wwwhom8_blackberries > phase6_backup.sql # Create git commit git add . git commit -m "Phase 6: Alerts & Notifications completed - weather alerts, task scheduling, equipment maintenance" # Create git tag git tag -a v6.0-phase6 -m "Phase 6: Alerts & Notifications completed"