39 KiB
Executable File
39 KiB
Executable File
🛠️ 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:
# 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:
# 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:
# 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:
<!-- In layouts/admin.blade.php -->
@if(app()->environment('local'))
<!-- Development mode -->
@vite(['resources/css/app.css', 'resources/js/app.js'])
@else
<!-- Production mode with cache busting -->
<link rel="stylesheet" href="{{ asset('css/netgescon-admin.css') }}?v={{ filemtime(public_path('css/netgescon-admin.css')) }}">
<script src="{{ asset('js/netgescon-admin.js') }}?v={{ filemtime(public_path('js/netgescon-admin.js')) }}"></script>
@endif
⚡ JavaScript Non Funzionante
🔍 Sintomi:
- Sidebar non si apre/chiude
- Form non validano
- AJAX requests falliscono
- Animazioni non funzionano
🚑 Debug 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:
# 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:
// 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:
// 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 = '<i class="fas fa-arrow-right"></i> 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:
// 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:
// 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:
/* 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:
#!/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:
#!/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):
#!/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
#!/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
// 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
// /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
# 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
// 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
- Self-Service - Questa guida e procedure automatiche
- Developer - GitHub Copilot documentation
- System Admin - Server e infrastructure issues
- 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