# πŸ› οΈ TROUBLESHOOTING - Guida Completa NetGescon > **Guida alla risoluzione problemi dell'interfaccia universale** > **πŸ“… Creato:** 21/07/2025 > **πŸ”„ Ultimo aggiornamento:** 21/07/2025 > **🎯 PrioritΓ :** ⚑ CRITICO --- ## πŸ“‹ **OVERVIEW TROUBLESHOOTING** Questa guida fornisce **SOLUZIONI IMMEDIATE** per: - 🚨 **Problemi Critici** - Sistema non funzionante - ⚠️ **Problemi Comuni** - Errori frequenti dell'interfaccia - πŸ”§ **Procedure di Recovery** - Ripristino rapido del sistema - πŸ§ͺ **Test e Validazione** - Verifiche post-risoluzione - πŸ“Š **Monitoring e Prevenzione** - Evitare problemi futuri ### 🎯 **Filosofia del Troubleshooting** - **Diagnosi Rapida** - Identificazione immediata del problema - **Soluzioni Incrementali** - Dal piΓΉ semplice al piΓΉ complesso - **Backup Safety** - Sempre conservare stati funzionanti - **Documentazione Completa** - Tracciare ogni intervento --- ## 🚨 **PROBLEMI CRITICI** ### πŸ’₯ **Interfaccia Completamente Rotta** #### πŸ” **Sintomi:** - Schermata bianca/nera - JavaScript errors nel console - CSS non caricato - Layout completamente distorto #### πŸš‘ **Soluzione Immediata:** ```bash # 1. Backup immediato dello stato attuale cp -r /var/www/netgescon /var/www/netgescon_backup_$(date +%Y%m%d_%H%M%S) # 2. Ripristino da backup funzionante cp -r /var/www/netgescon_backup_working/* /var/www/netgescon/ # 3. Clear cache Laravel cd /var/www/netgescon php artisan cache:clear php artisan config:clear php artisan view:clear php artisan route:clear # 4. Rebuild assets npm run build # 5. Fix permissions sudo chown -R www-data:www-data /var/www/netgescon sudo chmod -R 755 /var/www/netgescon ``` #### πŸ§ͺ **Verifica:** ```bash # Test basic functionality curl -I http://localhost:8000 php artisan route:list | grep admin npm run dev --dry-run ``` --- ### 🎨 **CSS Non Caricato / Stili Mancanti** #### πŸ” **Sintomi:** - Layout senza stili - Elementi sovrapposti - Colori di default del browser - Font non applicati #### πŸš‘ **Soluzione Immediata:** ```bash # 1. Check if CSS files exist ls -la /var/www/netgescon/public/css/ ls -la /var/www/netgescon/public/build/ # 2. Rebuild CSS cd /var/www/netgescon npm run build # 3. Check for compilation errors npm run dev # 4. Force browser cache clear # Add timestamp to CSS includes ``` #### πŸ› οΈ **Soluzione Completa:** ```blade @if(app()->environment('local')) @vite(['resources/css/app.css', 'resources/js/app.js']) @else @endif ``` --- ### ⚑ **JavaScript Non Funzionante** #### πŸ” **Sintomi:** - Sidebar non si apre/chiude - Form non validano - AJAX requests falliscono - Animazioni non funzionano #### πŸš‘ **Debug JavaScript:** ```javascript // Add to console for immediate debugging console.log('NetGescon Debug Info:'); console.log('App initialized:', window.NetGesconApp?.initialized); console.log('jQuery loaded:', typeof $ !== 'undefined'); console.log('Bootstrap loaded:', typeof bootstrap !== 'undefined'); console.log('Config:', window.NetGesconConfig?.all()); console.log('Permissions:', window.PermissionManager?.permissions); // Check for JavaScript errors window.addEventListener('error', (e) => { console.error('JavaScript Error:', e.error); // Send to monitoring if available if (window.Sentry) { window.Sentry.captureException(e.error); } }); ``` #### πŸ› οΈ **Fix JavaScript Issues:** ```bash # 1. Check JavaScript compilation cd /var/www/netgescon npm run build # 2. Check for syntax errors npm run lint # 3. Test individual components node -e "console.log('Node.js working')" # 4. Rebuild node_modules if needed rm -rf node_modules package-lock.json npm install npm run build ``` --- ## ⚠️ **PROBLEMI COMUNI** ### πŸ“± **Sidebar Non Funziona** #### πŸ” **Sintomi:** - Sidebar non si apre su mobile - Toggle button non risponde - Overlay non appare #### πŸš‘ **Fix Rapido:** ```javascript // Emergency sidebar fix function fixSidebar() { const sidebar = document.getElementById('sidebar'); const toggle = document.getElementById('mobile-nav-toggle'); const overlay = document.getElementById('sidebar-overlay'); if (!sidebar || !toggle) { console.error('Sidebar elements missing'); return; } // Create overlay if missing if (!overlay) { const newOverlay = document.createElement('div'); newOverlay.id = 'sidebar-overlay'; newOverlay.className = 'sidebar-overlay'; document.body.appendChild(newOverlay); } // Fix event listeners toggle.addEventListener('click', () => { sidebar.classList.toggle('show'); document.getElementById('sidebar-overlay').classList.toggle('show'); }); document.getElementById('sidebar-overlay').addEventListener('click', () => { sidebar.classList.remove('show'); document.getElementById('sidebar-overlay').classList.remove('show'); }); } // Run fix fixSidebar(); ``` --- ### πŸ“Š **Tabelle Non Responsive** #### πŸ” **Sintomi:** - Tabelle escono dal container - Scroll orizzontale problematico - Mobile view non funziona #### πŸš‘ **Fix Tabelle:** ```javascript // Emergency table fix function fixTables() { const tables = document.querySelectorAll('.table-responsive-mobile'); tables.forEach(container => { const table = container.querySelector('table'); if (!table) return; // Add horizontal scroll indicator if (!container.querySelector('.scroll-indicator')) { const indicator = document.createElement('div'); indicator.className = 'scroll-indicator'; indicator.innerHTML = ' Scorri per vedere piΓΉ colonne'; indicator.style.cssText = ` position: absolute; top: 50%; right: 10px; background: rgba(0,0,0,0.7); color: white; padding: 5px 10px; border-radius: 15px; font-size: 12px; pointer-events: none; z-index: 10; `; container.style.position = 'relative'; container.appendChild(indicator); // Hide on scroll container.addEventListener('scroll', () => { const isScrolledToEnd = container.scrollLeft >= (container.scrollWidth - container.clientWidth - 10); indicator.style.opacity = isScrolledToEnd ? '0' : '1'; }); } // Mobile stack view for very small screens if (window.innerWidth <= 576 && !container.querySelector('.mobile-table-stack')) { createMobileTableStack(container, table); } }); } function createMobileTableStack(container, table) { const mobileStack = document.createElement('div'); mobileStack.className = 'mobile-table-stack'; mobileStack.style.display = window.innerWidth <= 576 ? 'block' : 'none'; const headers = Array.from(table.querySelectorAll('thead th')).map(th => th.textContent.trim()); const rows = table.querySelectorAll('tbody tr'); rows.forEach(row => { const cells = row.querySelectorAll('td'); const mobileItem = document.createElement('div'); mobileItem.className = 'mobile-table-item'; mobileItem.style.cssText = ` background: white; border: 1px solid #e2e8f0; border-radius: 8px; padding: 1rem; margin-bottom: 1rem; `; cells.forEach((cell, index) => { const itemRow = document.createElement('div'); itemRow.style.cssText = ` display: flex; justify-content: space-between; padding: 0.25rem 0; border-bottom: 1px solid #f1f5f9; `; const label = document.createElement('div'); label.style.cssText = ` font-weight: 500; color: #64748b; font-size: 0.875rem; `; label.textContent = headers[index] || `Campo ${index + 1}`; const value = document.createElement('div'); value.style.cssText = ` color: #0f172a; text-align: right; `; value.innerHTML = cell.innerHTML; itemRow.appendChild(label); itemRow.appendChild(value); mobileItem.appendChild(itemRow); }); mobileStack.appendChild(mobileItem); }); container.appendChild(mobileStack); // Hide original table on mobile table.style.display = window.innerWidth <= 576 ? 'none' : 'table'; } // Run fix fixTables(); ``` --- ### πŸ” **Permessi Non Funzionano** #### πŸ” **Sintomi:** - Elementi visibili che non dovrebbero esserlo - Azioni bloccate quando dovrebbero essere permesse - Errori 403 inaspettati #### πŸš‘ **Debug Permessi:** ```javascript // Permission debugging tool function debugPermissions() { console.log('=== PERMISSION DEBUG ==='); // Check user data const user = window.PermissionManager?.user; console.log('User:', user); console.log('Role:', user?.role); // Check permissions const permissions = window.PermissionManager?.permissions; console.log('Permissions:', permissions); // Test common permissions const testResources = ['stabili', 'condomini', 'unita', 'reports', 'users']; const testActions = ['read', 'create', 'update', 'delete']; testResources.forEach(resource => { console.log(`\n--- ${resource.toUpperCase()} ---`); testActions.forEach(action => { const hasPermission = window.PermissionManager?.can(resource, action); console.log(`${action}: ${hasPermission ? 'βœ…' : '❌'}`); }); }); // Check problematic elements const permissionElements = document.querySelectorAll('[data-permission], [data-role]'); console.log(`\nFound ${permissionElements.length} permission-controlled elements`); permissionElements.forEach((el, index) => { const permission = el.dataset.permission; const role = el.dataset.role; const action = el.dataset.action || 'read'; const visible = el.style.display !== 'none' && !el.hasAttribute('aria-hidden'); console.log(`Element ${index + 1}:`, { tag: el.tagName, permission, role, action, visible, shouldBeVisible: permission ? window.PermissionManager?.can(permission, action) : true }); }); } // Run debug debugPermissions(); ``` #### πŸ› οΈ **Fix Permessi:** ```php // Add to routes/web.php for emergency permission reset Route::get('/debug/permissions/{user}', function($userId) { if (!auth()->user()->hasRole('super_admin')) { abort(403); } $user = User::findOrFail($userId); return response()->json([ 'user' => $user, 'role' => $user->getRole(), 'permissions' => $user->permissions, 'default_level' => $user->getDefaultPermissionLevel(), 'test_permissions' => [ 'stabili' => [ 'read' => $user->getPermissionLevel('stabili'), 'create' => $user->getPermissionLevel('stabili'), 'update' => $user->getPermissionLevel('stabili'), 'delete' => $user->getPermissionLevel('stabili'), ] ] ]); })->middleware(['auth', 'role:super_admin']); ``` --- ### πŸ“± **Problemi Mobile** #### πŸ” **Sintomi:** - Layout rotto su mobile - Touch non funziona - Font troppo piccoli - Elementi non accessibili #### πŸš‘ **Fix Mobile:** ```css /* Emergency mobile fixes */ @media (max-width: 767px) { /* Ensure minimum touch targets */ .btn, .nav-link, .form-input, .form-select { min-height: 44px !important; min-width: 44px !important; } /* Fix font sizes to prevent zoom */ input, select, textarea { font-size: 16px !important; } /* Fix overlapping elements */ .netgescon-content { padding: 1rem !important; margin-top: 60px !important; } /* Fix sidebar on mobile */ .netgescon-sidebar { position: fixed !important; top: 60px !important; left: -280px !important; width: 280px !important; height: calc(100vh - 60px) !important; z-index: 999 !important; transition: left 0.3s ease !important; } .netgescon-sidebar.show { left: 0 !important; } /* Fix tables */ .table-responsive-mobile { overflow-x: auto !important; -webkit-overflow-scrolling: touch !important; } /* Fix cards */ .netgescon-card { margin-bottom: 1rem !important; padding: 1rem !important; } /* Fix buttons */ .btn-group { flex-direction: column !important; width: 100% !important; } .btn-group .btn { width: 100% !important; margin-bottom: 0.5rem !important; } } ``` --- ## πŸ”§ **PROCEDURE DI RECOVERY** ### πŸ’Ύ **Backup e Restore** #### πŸ“ **Backup Completo:** ```bash #!/bin/bash # create-backup.sh DATE=$(date +%Y%m%d_%H%M%S) BACKUP_DIR="/var/backups/netgescon" SOURCE_DIR="/var/www/netgescon" # Create backup directory mkdir -p $BACKUP_DIR # Backup files echo "Backing up files..." tar -czf "$BACKUP_DIR/netgescon_files_$DATE.tar.gz" -C "$SOURCE_DIR" . # Backup database echo "Backing up database..." mysqldump -u root -p netgescon > "$BACKUP_DIR/netgescon_db_$DATE.sql" # Backup config files echo "Backing up configs..." cp /etc/nginx/sites-available/netgescon "$BACKUP_DIR/nginx_config_$DATE" cp /etc/php/8.2/fpm/pool.d/netgescon.conf "$BACKUP_DIR/php_config_$DATE" # Create restore script cat > "$BACKUP_DIR/restore_$DATE.sh" << EOF #!/bin/bash echo "Restoring NetGescon from backup $DATE..." # Stop services sudo systemctl stop nginx php8.2-fpm # Restore files sudo rm -rf /var/www/netgescon/* sudo tar -xzf "$BACKUP_DIR/netgescon_files_$DATE.tar.gz" -C /var/www/netgescon/ # Restore database mysql -u root -p netgescon < "$BACKUP_DIR/netgescon_db_$DATE.sql" # Fix permissions sudo chown -R www-data:www-data /var/www/netgescon sudo chmod -R 755 /var/www/netgescon sudo chmod -R 775 /var/www/netgescon/storage sudo chmod -R 775 /var/www/netgescon/bootstrap/cache # Restart services sudo systemctl start php8.2-fpm nginx echo "Restore completed!" EOF chmod +x "$BACKUP_DIR/restore_$DATE.sh" echo "Backup completed: $BACKUP_DIR" echo "To restore: sudo bash $BACKUP_DIR/restore_$DATE.sh" ``` #### πŸ”„ **Restore da Backup:** ```bash #!/bin/bash # quick-restore.sh # Find latest backup LATEST_BACKUP=$(ls -t /var/backups/netgescon/netgescon_files_*.tar.gz | head -1) LATEST_DB=$(ls -t /var/backups/netgescon/netgescon_db_*.sql | head -1) if [ -z "$LATEST_BACKUP" ]; then echo "❌ No backup found!" exit 1 fi echo "πŸ”„ Restoring from: $LATEST_BACKUP" # Backup current state first cp -r /var/www/netgescon "/var/www/netgescon_before_restore_$(date +%Y%m%d_%H%M%S)" # Stop services sudo systemctl stop nginx php8.2-fpm # Restore files sudo rm -rf /var/www/netgescon/* sudo tar -xzf "$LATEST_BACKUP" -C /var/www/netgescon/ # Restore database if available if [ -n "$LATEST_DB" ]; then echo "πŸ—„οΈ Restoring database..." mysql -u root -p netgescon < "$LATEST_DB" fi # Clear all caches cd /var/www/netgescon php artisan cache:clear php artisan config:clear php artisan view:clear php artisan route:clear # Fix permissions sudo chown -R www-data:www-data /var/www/netgescon sudo chmod -R 755 /var/www/netgescon sudo chmod -R 775 /var/www/netgescon/storage sudo chmod -R 775 /var/www/netgescon/bootstrap/cache # Restart services sudo systemctl start php8.2-fpm nginx echo "βœ… Restore completed!" echo "πŸ§ͺ Test the application: http://localhost:8000" ``` --- ### πŸ”§ **Reset Completo Sistema** #### 🚨 **Reset Interfaccia (EMERGENCY):** ```bash #!/bin/bash # emergency-reset.sh echo "🚨 EMERGENCY RESET - This will reset the interface to default state" read -p "Are you sure? (type 'RESET' to confirm): " confirm if [ "$confirm" != "RESET" ]; then echo "❌ Reset cancelled" exit 1 fi # 1. Backup current state BACKUP_DIR="/tmp/emergency_backup_$(date +%Y%m%d_%H%M%S)" cp -r /var/www/netgescon "$BACKUP_DIR" echo "πŸ“ Current state backed up to: $BACKUP_DIR" # 2. Reset to clean Laravel installation cd /var/www/netgescon # Clear all caches php artisan cache:clear php artisan config:clear php artisan view:clear php artisan route:clear php artisan storage:link # Reset config files cp .env.example .env php artisan key:generate # 3. Reset database (if needed) read -p "Reset database too? (y/N): " reset_db if [ "$reset_db" = "y" ] || [ "$reset_db" = "Y" ]; then php artisan migrate:fresh --seed fi # 4. Rebuild assets npm install npm run build # 5. Fix permissions sudo chown -R www-data:www-data /var/www/netgescon sudo chmod -R 755 /var/www/netgescon sudo chmod -R 775 /var/www/netgescon/storage sudo chmod -R 775 /var/www/netgescon/bootstrap/cache # 6. Restart services sudo systemctl restart nginx php8.2-fpm echo "βœ… Emergency reset completed!" echo "πŸ”§ Configure your .env file and test the application" echo "πŸ“ Previous state backed up to: $BACKUP_DIR" ``` --- ## πŸ§ͺ **TEST E VALIDAZIONE** ### βœ… **Test Rapidi Post-Fix** ```bash #!/bin/bash # quick-tests.sh echo "πŸ§ͺ Running Quick Validation Tests..." # 1. Test web server echo "πŸ“‘ Testing web server..." HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8000) if [ "$HTTP_CODE" = "200" ]; then echo "βœ… Web server responding" else echo "❌ Web server not responding (HTTP $HTTP_CODE)" fi # 2. Test database connection echo "πŸ—„οΈ Testing database..." cd /var/www/netgescon if php artisan tinker --execute="DB::connection()->getPdo(); echo 'DB Connected';" 2>/dev/null | grep -q "DB Connected"; then echo "βœ… Database connection working" else echo "❌ Database connection failed" fi # 3. Test assets echo "🎨 Testing assets..." if [ -f "public/css/netgescon-admin.css" ] && [ -f "public/js/netgescon-admin.js" ]; then echo "βœ… Assets compiled" else echo "❌ Assets missing" fi # 4. Test permissions echo "πŸ” Testing file permissions..." if [ -w "storage/logs" ] && [ -w "bootstrap/cache" ]; then echo "βœ… File permissions correct" else echo "❌ File permissions incorrect" fi # 5. Test critical routes echo "πŸ›£οΈ Testing critical routes..." ROUTES=$(php artisan route:list --compact | grep -E "(admin|login|dashboard)" | wc -l) if [ "$ROUTES" -gt "0" ]; then echo "βœ… Routes registered ($ROUTES found)" else echo "❌ No routes found" fi echo "🏁 Quick tests completed!" ``` ### πŸ” **Test Completi Interfaccia** ```javascript // Complete interface test suite class InterfaceTests { constructor() { this.results = []; this.runTests(); } async runTests() { console.log('πŸ§ͺ Running Complete Interface Tests...'); const tests = [ () => this.testPageLoad(), () => this.testCSS(), () => this.testJavaScript(), () => this.testSidebar(), () => this.testResponsive(), () => this.testForms(), () => this.testTables(), () => this.testPermissions(), () => this.testAccessibility(), () => this.testPerformance() ]; for (const test of tests) { try { const result = await test(); this.results.push(result); this.logResult(result); } catch (error) { const result = { name: test.name, passed: false, error: error.message }; this.results.push(result); this.logResult(result); } } this.generateReport(); } testPageLoad() { const start = performance.now(); const loaded = document.readyState === 'complete'; const loadTime = performance.now() - start; return { name: 'Page Load', passed: loaded && loadTime < 3000, details: { loaded, loadTime: `${loadTime.toFixed(2)}ms` } }; } testCSS() { const stylesheets = document.querySelectorAll('link[rel="stylesheet"]'); const hasNetGesconCSS = Array.from(stylesheets).some(link => link.href.includes('netgescon-admin.css') ); // Test if critical styles are applied const body = document.body; const computedStyle = getComputedStyle(body); const hasStyles = computedStyle.fontFamily !== 'serif'; // Default would be serif return { name: 'CSS Loading', passed: hasNetGesconCSS && hasStyles, details: { stylesheets: stylesheets.length, hasNetGesconCSS, hasStyles, fontFamily: computedStyle.fontFamily } }; } testJavaScript() { const hasNetGesconApp = typeof window.NetGesconApp !== 'undefined'; const hasPermissionManager = typeof window.PermissionManager !== 'undefined'; const hasBootstrap = typeof window.bootstrap !== 'undefined'; return { name: 'JavaScript Loading', passed: hasNetGesconApp && hasPermissionManager && hasBootstrap, details: { hasNetGesconApp, hasPermissionManager, hasBootstrap } }; } testSidebar() { const sidebar = document.getElementById('sidebar'); const toggle = document.getElementById('mobile-nav-toggle'); if (!sidebar) { return { name: 'Sidebar', passed: false, details: { missing: 'sidebar element' } }; } // Test toggle functionality const originalClass = sidebar.className; sidebar.classList.add('show'); const canToggle = sidebar.classList.contains('show'); sidebar.className = originalClass; return { name: 'Sidebar', passed: canToggle && (window.innerWidth >= 768 || toggle), details: { hasSidebar: !!sidebar, hasToggle: !!toggle, canToggle } }; } testResponsive() { const viewport = window.innerWidth; const isMobile = viewport < 768; const isTablet = viewport >= 768 && viewport < 1024; const isDesktop = viewport >= 1024; // Test grid systems const grids = document.querySelectorAll('.grid, .netgescon-grid, .stats-grid'); const hasGrids = grids.length > 0; return { name: 'Responsive', passed: hasGrids, details: { viewport, isMobile, isTablet, isDesktop, grids: grids.length } }; } testForms() { const forms = document.querySelectorAll('form'); const inputs = document.querySelectorAll('input, select, textarea'); // Test form validation classes const hasValidationClasses = Array.from(inputs).some(input => input.classList.contains('form-input') || input.classList.contains('form-control') ); return { name: 'Forms', passed: forms.length > 0 && hasValidationClasses, details: { forms: forms.length, inputs: inputs.length, hasValidationClasses } }; } testTables() { const tables = document.querySelectorAll('table'); const responsiveTables = document.querySelectorAll('.table-responsive, .table-responsive-mobile'); return { name: 'Tables', passed: tables.length === 0 || responsiveTables.length > 0, details: { tables: tables.length, responsiveTables: responsiveTables.length } }; } testPermissions() { const permissionElements = document.querySelectorAll('[data-permission], [data-role]'); const hasPermissionManager = typeof window.PermissionManager !== 'undefined'; return { name: 'Permissions', passed: hasPermissionManager, details: { permissionElements: permissionElements.length, hasPermissionManager } }; } testAccessibility() { // Test for basic accessibility features const images = document.querySelectorAll('img'); const imagesWithAlt = Array.from(images).filter(img => img.hasAttribute('alt')); const buttons = document.querySelectorAll('button'); const buttonsWithAriaLabel = Array.from(buttons).filter(btn => btn.hasAttribute('aria-label') || btn.textContent.trim() ); const altRatio = images.length ? imagesWithAlt.length / images.length : 1; const buttonRatio = buttons.length ? buttonsWithAriaLabel.length / buttons.length : 1; return { name: 'Accessibility', passed: altRatio >= 0.8 && buttonRatio >= 0.8, details: { altRatio: `${(altRatio * 100).toFixed(1)}%`, buttonRatio: `${(buttonRatio * 100).toFixed(1)}%` } }; } testPerformance() { const navigation = performance.getEntriesByType('navigation')[0]; const loadTime = navigation ? navigation.loadEventEnd - navigation.fetchStart : 0; const resources = performance.getEntriesByType('resource'); const slowResources = resources.filter(r => r.duration > 1000); return { name: 'Performance', passed: loadTime < 5000 && slowResources.length < 3, details: { loadTime: `${loadTime.toFixed(2)}ms`, totalResources: resources.length, slowResources: slowResources.length } }; } logResult(result) { const status = result.passed ? 'βœ…' : '❌'; console.log(`${status} ${result.name}:`, result.details); if (result.error) { console.error(` Error: ${result.error}`); } } generateReport() { const passed = this.results.filter(r => r.passed).length; const total = this.results.length; const passRate = (passed / total * 100).toFixed(1); console.log('\nπŸ“Š Test Summary:'); console.log(`Pass Rate: ${passRate}% (${passed}/${total})`); const failed = this.results.filter(r => !r.passed); if (failed.length > 0) { console.log('\n❌ Failed Tests:'); failed.forEach(test => { console.log(` - ${test.name}: ${test.error || 'Failed validation'}`); }); } // Store results for later analysis window.InterfaceTestResults = { timestamp: new Date().toISOString(), passRate, results: this.results }; } } // Run tests automatically in debug mode if (window.location.search.includes('test=interface')) { document.addEventListener('DOMContentLoaded', () => { setTimeout(() => new InterfaceTests(), 2000); }); } ``` --- ## πŸ“Š **MONITORING E PREVENZIONE** ### πŸ“ˆ **Sistema di Monitoring** ```javascript // /public/js/monitoring/health-check.js class HealthMonitor { constructor() { this.checks = new Map(); this.alerts = []; this.interval = 30000; // 30 seconds this.init(); } init() { this.setupChecks(); this.startMonitoring(); this.setupErrorReporting(); } setupChecks() { // Add health checks this.addCheck('javascript', () => this.checkJavaScript()); this.addCheck('css', () => this.checkCSS()); this.addCheck('api', () => this.checkAPI()); this.addCheck('permissions', () => this.checkPermissions()); this.addCheck('performance', () => this.checkPerformance()); } addCheck(name, checkFn) { this.checks.set(name, { name, check: checkFn, lastRun: null, lastResult: null, consecutiveFailures: 0 }); } async startMonitoring() { setInterval(async () => { await this.runAllChecks(); }, this.interval); // Run initial checks await this.runAllChecks(); } async runAllChecks() { for (const [name, checkData] of this.checks) { try { const result = await checkData.check(); this.handleCheckResult(name, result); } catch (error) { this.handleCheckResult(name, { healthy: false, error: error.message }); } } } handleCheckResult(name, result) { const checkData = this.checks.get(name); checkData.lastRun = Date.now(); checkData.lastResult = result; if (result.healthy) { checkData.consecutiveFailures = 0; } else { checkData.consecutiveFailures++; // Alert after 3 consecutive failures if (checkData.consecutiveFailures >= 3) { this.createAlert(name, result); } } } createAlert(checkName, result) { const alert = { id: Date.now(), timestamp: new Date().toISOString(), check: checkName, message: result.error || `Health check ${checkName} failed`, severity: result.severity || 'warning', data: result }; this.alerts.push(alert); this.notifyAlert(alert); // Keep only last 100 alerts if (this.alerts.length > 100) { this.alerts = this.alerts.slice(-100); } } notifyAlert(alert) { console.warn(`🚨 Health Alert [${alert.check}]:`, alert.message); // Send to external monitoring if available if (window.Sentry) { window.Sentry.captureMessage(alert.message, alert.severity); } // Show user notification for critical alerts if (alert.severity === 'critical' && window.NetGesconNotifications) { NetGesconNotifications.error( `Sistema: ${alert.message}`, { duration: 10000 } ); } } // Health check functions checkJavaScript() { const errors = []; // Check core objects if (typeof window.NetGesconApp === 'undefined') { errors.push('NetGesconApp not loaded'); } if (typeof window.PermissionManager === 'undefined') { errors.push('PermissionManager not loaded'); } if (typeof window.bootstrap === 'undefined') { errors.push('Bootstrap not loaded'); } return { healthy: errors.length === 0, errors, severity: errors.length > 0 ? 'critical' : 'info' }; } checkCSS() { const stylesheets = document.querySelectorAll('link[rel="stylesheet"]'); const netgesconCSS = Array.from(stylesheets).find(link => link.href.includes('netgescon-admin.css') ); if (!netgesconCSS) { return { healthy: false, error: 'NetGescon CSS not found', severity: 'critical' }; } // Check if styles are actually applied const testElement = document.createElement('div'); testElement.className = 'netgescon-card'; testElement.style.position = 'absolute'; testElement.style.visibility = 'hidden'; document.body.appendChild(testElement); const styles = getComputedStyle(testElement); const hasStyles = styles.borderRadius && styles.borderRadius !== '0px'; document.body.removeChild(testElement); return { healthy: hasStyles, error: hasStyles ? null : 'CSS styles not applied', severity: hasStyles ? 'info' : 'warning' }; } async checkAPI() { try { const response = await fetch('/api/health'); return { healthy: response.ok, status: response.status, severity: response.ok ? 'info' : 'critical' }; } catch (error) { return { healthy: false, error: 'API not reachable', severity: 'critical' }; } } checkPermissions() { const hasManager = typeof window.PermissionManager !== 'undefined'; const hasPermissions = window.PermissionManager?.permissions; return { healthy: hasManager && hasPermissions, error: !hasManager ? 'Permission manager not loaded' : !hasPermissions ? 'Permissions not loaded' : null, severity: 'warning' }; } checkPerformance() { const navigation = performance.getEntriesByType('navigation')[0]; if (!navigation) { return { healthy: true, error: 'Performance data not available' }; } const loadTime = navigation.loadEventEnd - navigation.fetchStart; const healthy = loadTime < 5000; // 5 seconds threshold return { healthy, loadTime, error: healthy ? null : `Page load time too slow: ${loadTime}ms`, severity: healthy ? 'info' : 'warning' }; } setupErrorReporting() { // Global error handler window.addEventListener('error', (e) => { this.createAlert('javascript_error', { healthy: false, error: `${e.error?.message || e.message} at ${e.filename}:${e.lineno}`, severity: 'warning', stack: e.error?.stack }); }); // Unhandled promise rejection handler window.addEventListener('unhandledrejection', (e) => { this.createAlert('promise_rejection', { healthy: false, error: `Unhandled promise rejection: ${e.reason}`, severity: 'warning' }); }); } // Public methods for debugging getHealthStatus() { const status = {}; for (const [name, checkData] of this.checks) { status[name] = { healthy: checkData.lastResult?.healthy, lastRun: checkData.lastRun ? new Date(checkData.lastRun).toISOString() : null, consecutiveFailures: checkData.consecutiveFailures, error: checkData.lastResult?.error }; } return status; } getAlerts(severity = null) { return severity ? this.alerts.filter(a => a.severity === severity) : this.alerts; } forceCheck(checkName) { const checkData = this.checks.get(checkName); if (checkData) { return checkData.check(); } throw new Error(`Check '${checkName}' not found`); } } // Initialize health monitor document.addEventListener('DOMContentLoaded', () => { if (NetGesconConfig?.get('app.debug') || window.location.search.includes('monitor=true')) { window.HealthMonitor = new HealthMonitor(); console.log('πŸ₯ Health Monitor started'); } }); ``` --- ## πŸ“š **QUICK REFERENCE** ### 🚨 **Emergency Commands** ```bash # Complete system restart sudo systemctl restart nginx php8.2-fpm mysql # Clear all Laravel caches php artisan cache:clear && php artisan config:clear && php artisan view:clear && php artisan route:clear # Rebuild assets npm run build # Fix permissions sudo chown -R www-data:www-data /var/www/netgescon sudo chmod -R 755 /var/www/netgescon sudo chmod -R 775 /var/www/netgescon/storage /var/www/netgescon/bootstrap/cache # Emergency backup cp -r /var/www/netgescon "/var/backups/netgescon_emergency_$(date +%Y%m%d_%H%M%S)" ``` ### πŸ” **Debug URLs** ``` # Interface tests http://localhost:8000/?test=interface # Health monitoring http://localhost:8000/?monitor=true # Permission debug http://localhost:8000/debug/permissions/{user_id} # Laravel debug info http://localhost:8000/?debug=true ``` ### πŸ“ž **Emergency JavaScript** ```javascript // Emergency fixes you can run in browser console // Fix sidebar document.getElementById('mobile-nav-toggle')?.addEventListener('click', () => { document.getElementById('sidebar')?.classList.toggle('show'); }); // Force permission refresh window.PermissionManager?.refreshPermissions(); // Clear local storage localStorage.clear(); // Reload CSS document.querySelectorAll('link[rel="stylesheet"]').forEach(link => { link.href = link.href + '?v=' + Date.now(); }); // Emergency user info console.log('User:', window.NetGesconApp?.user); console.log('Permissions:', window.PermissionManager?.permissions); console.log('Config:', window.NetGesconConfig?.all()); ``` --- ## πŸ“ž **CONTATTI DI EMERGENZA** ### πŸ› οΈ **Escalation Path** 1. **Self-Service** - Questa guida e procedure automatiche 2. **Developer** - GitHub Copilot documentation 3. **System Admin** - Server e infrastructure issues 4. **Database Admin** - Data corruption o performance issues ### πŸ“‹ **Incident Report Template** ``` INCIDENT REPORT - NetGescon Interface ===================================== Timestamp: [DATE TIME] Severity: [CRITICAL/HIGH/MEDIUM/LOW] Affected Users: [NUMBER/ALL/SPECIFIC] PROBLEM DESCRIPTION: - What happened? - When did it start? - What is the impact? SYMPTOMS: - Browser errors? - UI not loading? - Functionality broken? ENVIRONMENT: - URL: [URL] - Browser: [BROWSER VERSION] - Screen size: [RESOLUTION] - User role: [ROLE] ATTEMPTED FIXES: - [ ] Cleared browser cache - [ ] Tried different browser - [ ] Checked console errors - [ ] Ran quick tests - [ ] Applied emergency fixes RESOLUTION: [What fixed the issue] PREVENTION: [How to prevent this in future] ``` --- *πŸ“ Documento mantenuto da: GitHub Copilot AI Assistant* *πŸ”— Componente: Troubleshooting Guide NetGescon Interface v2.1.0* *πŸ“ž Per supporto immediato: Consulta questa guida β†’ Test automatici β†’ Escalation*