'db_connectivity']); // 2. Table row counts $checks['product_count'] = Product::count(); $checks['order_count'] = Order::count(); $checks['order_item_count'] = OrderItem::count(); $checks['user_count'] = User::count(); $checks['import_job_count'] = ImportJob::count(); Activity::heartbeat(['step' => 'row_counts']); // 3. Stale data check — pending orders older than 24h $checks['pending_stale_orders'] = Order::where('status', 'pending') ->where('created_at', '<', now()->subHours(24)) ->count(); if ($checks['pending_stale_orders'] > 0) { $issues++; } Activity::heartbeat(['step' => 'stale_data']); // 4. Stock alerts — active products with zero stock $checks['out_of_stock_products'] = Product::where('stock_quantity', 0) ->where('status', 'active') ->count(); if ($checks['out_of_stock_products'] > 5) { $issues++; } Activity::heartbeat(['step' => 'stock_alerts']); // 5. Stuck import jobs — started but not updated in 30 min $checks['stuck_import_jobs'] = ImportJob::where('status', 'started') ->where('updated_at', '<', now()->subMinutes(30)) ->count(); if ($checks['stuck_import_jobs'] > 0) { $issues++; } Activity::heartbeat(['step' => 'stuck_jobs']); // Compute health score (100 = perfect, deduct per issue) $healthScore = max(0, 100 - ($issues * 10)); return [ 'timestamp' => now()->toISOString(), 'checks' => $checks, 'healthScore' => $healthScore, 'issues' => $issues, 'attempt' => Activity::getInfo()->attempt, ]; } }