✅ Completato: - Database modernizzato con chiavi id standard Laravel - Relazioni corrette Amministratore→Stabili→Movimenti - UI universale responsive con sidebar permission-based - Codici alfanumerici 8 caratteri implementati - Seeders con dati di test funzionanti - Documentazione tecnica completa (INSTALL_LINUX, TECHNICAL_SPECS, UPDATE_SYSTEM) 🔧 Miglioramenti: - Helper userSetting() funzionante - Sistema multi-database preparato - .gitignore aggiornato per sicurezza - Migration cleanup e ottimizzazione 📚 Documentazione: - Guida installazione Linux completa - Specifiche tecniche dettagliate - Sistema aggiornamenti progettato - Progress log aggiornato
864 lines
25 KiB
Markdown
864 lines
25 KiB
Markdown
# NetGesCon - Sistema Aggiornamenti Automatici
|
|
|
|
## 🎯 Panoramica Sistema
|
|
|
|
Il sistema di aggiornamenti automatici NetGesCon permette:
|
|
- **Registrazione utenti** con codici 8 caratteri univoci
|
|
- **Download automatico** aggiornamenti via API
|
|
- **Backup pre-aggiornamento** automatico
|
|
- **Rollback** in caso di errori
|
|
- **Gestione versioni** (stable/development)
|
|
- **Sistema licenze** basato su livello servizio
|
|
|
|
## 🏗️ Architettura Sistema
|
|
|
|
```
|
|
NetGesCon Master Server (update.netgescon.com)
|
|
├── API Registrazione Utenti
|
|
├── API Download Aggiornamenti
|
|
├── Database Utenti/Licenze
|
|
├── Repository Versioni
|
|
└── Sistema Notifiche
|
|
|
|
NetGesCon Client (Installazione Locale)
|
|
├── Update Service
|
|
├── Backup Manager
|
|
├── Version Manager
|
|
└── License Validator
|
|
```
|
|
|
|
## 📊 Database Schema
|
|
|
|
### Tabella: `registered_users`
|
|
```sql
|
|
CREATE TABLE registered_users (
|
|
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
|
codice_utente VARCHAR(8) UNIQUE NOT NULL, -- es: "USR12345"
|
|
email VARCHAR(255) UNIQUE NOT NULL,
|
|
nome VARCHAR(100) NOT NULL,
|
|
cognome VARCHAR(100) NOT NULL,
|
|
azienda VARCHAR(200),
|
|
telefono VARCHAR(20),
|
|
|
|
-- Licenza e Servizi
|
|
livello_servizio ENUM('basic', 'professional', 'enterprise') DEFAULT 'basic',
|
|
data_scadenza DATE,
|
|
max_amministratori INT DEFAULT 5,
|
|
max_stabili INT DEFAULT 50,
|
|
features_abilitate JSON, -- {"multi_db": true, "audit": false, "api": true}
|
|
|
|
-- Sicurezza
|
|
api_key VARCHAR(64) UNIQUE,
|
|
api_secret VARCHAR(128),
|
|
ultimo_accesso TIMESTAMP NULL,
|
|
ip_autorizzati TEXT, -- JSON array IP
|
|
|
|
-- Sistema
|
|
stato ENUM('attivo', 'sospeso', 'scaduto') DEFAULT 'attivo',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
deleted_at TIMESTAMP NULL
|
|
);
|
|
```
|
|
|
|
### Tabella: `system_versions`
|
|
```sql
|
|
CREATE TABLE system_versions (
|
|
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
|
versione VARCHAR(20) NOT NULL, -- "2.1.0"
|
|
tipo_release ENUM('stable', 'development', 'hotfix') DEFAULT 'stable',
|
|
|
|
-- Files
|
|
download_url VARCHAR(500),
|
|
checksum_sha256 VARCHAR(64),
|
|
dimensione_mb DECIMAL(8,2),
|
|
|
|
-- Compatibilità
|
|
versione_php_min VARCHAR(10), -- "8.2"
|
|
versione_laravel_min VARCHAR(10), -- "10.0"
|
|
versione_mysql_min VARCHAR(10), -- "8.0"
|
|
|
|
-- Descrizione
|
|
titolo VARCHAR(200),
|
|
descrizione TEXT,
|
|
changelog TEXT,
|
|
breaking_changes TEXT,
|
|
|
|
-- Controllo
|
|
richiede_backup BOOLEAN DEFAULT true,
|
|
richiede_downtime BOOLEAN DEFAULT false,
|
|
compatibile_rollback BOOLEAN DEFAULT true,
|
|
|
|
-- Metadata
|
|
data_rilascio TIMESTAMP,
|
|
stato ENUM('draft', 'testing', 'published', 'deprecated') DEFAULT 'draft',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
);
|
|
```
|
|
|
|
### Tabella: `update_logs`
|
|
```sql
|
|
CREATE TABLE update_logs (
|
|
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
|
codice_utente VARCHAR(8),
|
|
versione_da VARCHAR(20),
|
|
versione_a VARCHAR(20),
|
|
|
|
-- Processo
|
|
stato ENUM('started', 'downloading', 'backing_up', 'installing', 'completed', 'failed', 'rolled_back'),
|
|
percentuale_completamento TINYINT DEFAULT 0,
|
|
|
|
-- Dettagli
|
|
log_output TEXT,
|
|
errore_dettaglio TEXT,
|
|
backup_path VARCHAR(500),
|
|
tempo_inizio TIMESTAMP,
|
|
tempo_fine TIMESTAMP,
|
|
|
|
-- Sistema
|
|
ip_client VARCHAR(45),
|
|
user_agent TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
);
|
|
```
|
|
|
|
## 🔌 API Endpoints
|
|
|
|
### 1. Registrazione Utente
|
|
```http
|
|
POST /api/v1/register
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"email": "admin@condominio.it",
|
|
"nome": "Mario",
|
|
"cognome": "Rossi",
|
|
"azienda": "Amministrazioni Rossi SRL",
|
|
"telefono": "+39 123 456 7890",
|
|
"livello_servizio": "professional"
|
|
}
|
|
|
|
Response:
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"codice_utente": "USR12345",
|
|
"api_key": "a1b2c3d4e5f6...",
|
|
"api_secret": "secret_hash...",
|
|
"scadenza": "2026-07-07",
|
|
"features": {
|
|
"multi_db": true,
|
|
"audit": true,
|
|
"api": true
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### 2. Verifica Licenza
|
|
```http
|
|
GET /api/v1/license/verify
|
|
Authorization: Bearer {api_key}
|
|
X-API-Secret: {api_secret}
|
|
|
|
Response:
|
|
{
|
|
"valid": true,
|
|
"scadenza": "2026-07-07",
|
|
"giorni_rimanenti": 365,
|
|
"livello": "professional",
|
|
"limiti": {
|
|
"amministratori": 20,
|
|
"stabili": 200
|
|
},
|
|
"features": ["multi_db", "audit", "api"]
|
|
}
|
|
```
|
|
|
|
### 3. Check Aggiornamenti
|
|
```http
|
|
GET /api/v1/updates/check
|
|
Authorization: Bearer {api_key}
|
|
X-Client-Version: 2.0.5
|
|
X-Release-Channel: stable
|
|
|
|
Response:
|
|
{
|
|
"update_available": true,
|
|
"latest_version": "2.1.0",
|
|
"download_url": "https://update.netgescon.com/releases/2.1.0/netgescon-2.1.0.zip",
|
|
"checksum": "sha256:a1b2c3...",
|
|
"size_mb": 45.2,
|
|
"changelog": "- Fix bug contabilità\n- Nuova UI dashboard...",
|
|
"breaking_changes": false,
|
|
"requires_backup": true
|
|
}
|
|
```
|
|
|
|
### 4. Download Aggiornamento
|
|
```http
|
|
GET /api/v1/updates/download/{version}
|
|
Authorization: Bearer {api_key}
|
|
X-API-Secret: {api_secret}
|
|
|
|
Response: [Binary ZIP file with update]
|
|
```
|
|
|
|
## 💻 Client Update Service
|
|
|
|
### Comando Artisan: `update:check`
|
|
```php
|
|
<?php
|
|
// app/Console/Commands/UpdateCheckCommand.php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use Illuminate\Console\Command;
|
|
use App\Services\UpdateService;
|
|
|
|
class UpdateCheckCommand extends Command
|
|
{
|
|
protected $signature = 'update:check
|
|
{--force : Force check anche se già controllato di recente}
|
|
{--channel=stable : Channel release (stable|development)}';
|
|
|
|
protected $description = 'Controlla aggiornamenti disponibili';
|
|
|
|
public function handle(UpdateService $updateService)
|
|
{
|
|
$this->info('🔍 Controllo aggiornamenti NetGesCon...');
|
|
|
|
$channel = $this->option('channel');
|
|
$force = $this->option('force');
|
|
|
|
$result = $updateService->checkUpdates($channel, $force);
|
|
|
|
if ($result['update_available']) {
|
|
$this->info("✅ Aggiornamento disponibile:");
|
|
$this->table(['Campo', 'Valore'], [
|
|
['Versione attuale', $result['current_version']],
|
|
['Nuova versione', $result['latest_version']],
|
|
['Tipo release', $result['release_type']],
|
|
['Dimensione', $result['size_mb'] . ' MB'],
|
|
['Richiede backup', $result['requires_backup'] ? 'Sì' : 'No']
|
|
]);
|
|
|
|
if ($this->confirm('Vuoi procedere con il download?')) {
|
|
$this->call('update:download', ['version' => $result['latest_version']]);
|
|
}
|
|
} else {
|
|
$this->info('✅ Sistema aggiornato alla versione più recente');
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Comando Artisan: `update:install`
|
|
```php
|
|
<?php
|
|
|
|
class UpdateInstallCommand extends Command
|
|
{
|
|
protected $signature = 'update:install
|
|
{version : Versione da installare}
|
|
{--skip-backup : Salta backup pre-installazione}
|
|
{--rollback-on-error : Auto-rollback in caso di errore}';
|
|
|
|
public function handle(UpdateService $updateService, BackupService $backupService)
|
|
{
|
|
$version = $this->argument('version');
|
|
$skipBackup = $this->option('skip-backup');
|
|
$autoRollback = $this->option('rollback-on-error');
|
|
|
|
$this->info("🚀 Installazione NetGesCon v{$version}");
|
|
|
|
// 1. Validazione pre-installazione
|
|
$this->info('📋 Validazione sistema...');
|
|
if (!$updateService->validateSystem($version)) {
|
|
$this->error('❌ Sistema non compatibile con questa versione');
|
|
return 1;
|
|
}
|
|
|
|
// 2. Backup automatico
|
|
if (!$skipBackup) {
|
|
$this->info('💾 Creazione backup pre-aggiornamento...');
|
|
$backupPath = $backupService->createPreUpdateBackup($version);
|
|
$this->info("Backup salvato: {$backupPath}");
|
|
}
|
|
|
|
// 3. Download se necessario
|
|
if (!$updateService->isVersionDownloaded($version)) {
|
|
$this->info('⬇️ Download aggiornamento...');
|
|
$updateService->downloadVersion($version, function($progress) {
|
|
$this->output->write("\r📦 Download: {$progress}%");
|
|
});
|
|
$this->newLine();
|
|
}
|
|
|
|
// 4. Installazione
|
|
$this->info('⚙️ Installazione in corso...');
|
|
|
|
try {
|
|
$updateService->installVersion($version, function($step, $progress) {
|
|
$this->output->write("\r🔧 {$step}: {$progress}%");
|
|
});
|
|
|
|
$this->newLine();
|
|
$this->info('✅ Aggiornamento completato con successo!');
|
|
$this->info("NetGesCon aggiornato alla versione {$version}");
|
|
|
|
} catch (\Exception $e) {
|
|
$this->error("❌ Errore durante l'installazione: " . $e->getMessage());
|
|
|
|
if ($autoRollback && !$skipBackup) {
|
|
$this->warn('🔄 Avvio rollback automatico...');
|
|
if ($backupService->restore($backupPath)) {
|
|
$this->info('✅ Rollback completato');
|
|
} else {
|
|
$this->error('❌ Errore durante il rollback');
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
```
|
|
|
|
## 🔧 UpdateService Implementation
|
|
|
|
```php
|
|
<?php
|
|
// app/Services/UpdateService.php
|
|
|
|
namespace App\Services;
|
|
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Facades\File;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class UpdateService
|
|
{
|
|
private $apiBaseUrl;
|
|
private $apiKey;
|
|
private $apiSecret;
|
|
private $currentVersion;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->apiBaseUrl = config('netgescon.update.api_url');
|
|
$this->apiKey = config('netgescon.update.api_key');
|
|
$this->apiSecret = config('netgescon.update.api_secret');
|
|
$this->currentVersion = config('netgescon.version');
|
|
}
|
|
|
|
public function checkUpdates(string $channel = 'stable', bool $force = false): array
|
|
{
|
|
// Cache del controllo (evita troppe chiamate API)
|
|
$cacheKey = "updates_check_{$channel}";
|
|
|
|
if (!$force && cache()->has($cacheKey)) {
|
|
return cache($cacheKey);
|
|
}
|
|
|
|
try {
|
|
$response = Http::withHeaders([
|
|
'Authorization' => "Bearer {$this->apiKey}",
|
|
'X-Client-Version' => $this->currentVersion,
|
|
'X-Release-Channel' => $channel
|
|
])->get("{$this->apiBaseUrl}/api/v1/updates/check");
|
|
|
|
if ($response->successful()) {
|
|
$data = $response->json();
|
|
|
|
// Cache per 1 ora
|
|
cache([$cacheKey => $data], 3600);
|
|
|
|
return $data;
|
|
}
|
|
|
|
throw new \Exception('API non raggiungibile: ' . $response->status());
|
|
|
|
} catch (\Exception $e) {
|
|
Log::error("Errore controllo aggiornamenti: " . $e->getMessage());
|
|
|
|
return [
|
|
'update_available' => false,
|
|
'current_version' => $this->currentVersion,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
public function downloadVersion(string $version, $progressCallback = null): string
|
|
{
|
|
$downloadPath = storage_path("app/updates/{$version}");
|
|
$zipPath = "{$downloadPath}/netgescon-{$version}.zip";
|
|
|
|
if (!File::exists($downloadPath)) {
|
|
File::makeDirectory($downloadPath, 0755, true);
|
|
}
|
|
|
|
$response = Http::withHeaders([
|
|
'Authorization' => "Bearer {$this->apiKey}",
|
|
'X-API-Secret' => $this->apiSecret
|
|
])->withOptions([
|
|
'sink' => $zipPath,
|
|
'progress' => function($downloadTotal, $downloadedBytes) use ($progressCallback) {
|
|
if ($downloadTotal > 0 && $progressCallback) {
|
|
$progress = round(($downloadedBytes / $downloadTotal) * 100);
|
|
$progressCallback($progress);
|
|
}
|
|
}
|
|
])->get("{$this->apiBaseUrl}/api/v1/updates/download/{$version}");
|
|
|
|
if (!$response->successful()) {
|
|
throw new \Exception("Errore download versione {$version}");
|
|
}
|
|
|
|
// Verifica checksum
|
|
$this->verifyChecksum($zipPath, $version);
|
|
|
|
return $zipPath;
|
|
}
|
|
|
|
public function installVersion(string $version, $progressCallback = null): void
|
|
{
|
|
$zipPath = storage_path("app/updates/{$version}/netgescon-{$version}.zip");
|
|
$extractPath = storage_path("app/updates/{$version}/extracted");
|
|
|
|
if (!File::exists($zipPath)) {
|
|
throw new \Exception("File aggiornamento non trovato: {$zipPath}");
|
|
}
|
|
|
|
// 1. Estrazione
|
|
$progressCallback && $progressCallback('Estrazione files', 10);
|
|
$this->extractUpdate($zipPath, $extractPath);
|
|
|
|
// 2. Backup configurazioni attuali
|
|
$progressCallback && $progressCallback('Backup configurazioni', 20);
|
|
$this->backupConfigurations();
|
|
|
|
// 3. Manutenzione mode
|
|
$progressCallback && $progressCallback('Attivazione modalità manutenzione', 30);
|
|
\Artisan::call('down');
|
|
|
|
try {
|
|
// 4. Aggiornamento files
|
|
$progressCallback && $progressCallback('Aggiornamento files applicazione', 40);
|
|
$this->updateApplicationFiles($extractPath);
|
|
|
|
// 5. Composer install
|
|
$progressCallback && $progressCallback('Installazione dipendenze', 60);
|
|
$this->runComposerInstall();
|
|
|
|
// 6. Database migrations
|
|
$progressCallback && $progressCallback('Aggiornamento database', 75);
|
|
\Artisan::call('migrate', ['--force' => true]);
|
|
|
|
// 7. Cache refresh
|
|
$progressCallback && $progressCallback('Aggiornamento cache', 85);
|
|
$this->refreshCache();
|
|
|
|
// 8. NPM build
|
|
$progressCallback && $progressCallback('Build assets', 95);
|
|
$this->buildAssets();
|
|
|
|
} finally {
|
|
// 9. Disattivazione manutenzione
|
|
$progressCallback && $progressCallback('Riattivazione applicazione', 100);
|
|
\Artisan::call('up');
|
|
}
|
|
|
|
// 10. Aggiornamento versione
|
|
$this->updateVersionFile($version);
|
|
|
|
// 11. Cleanup
|
|
$this->cleanupUpdateFiles($version);
|
|
}
|
|
|
|
private function extractUpdate(string $zipPath, string $extractPath): void
|
|
{
|
|
$zip = new \ZipArchive();
|
|
|
|
if ($zip->open($zipPath) === TRUE) {
|
|
$zip->extractTo($extractPath);
|
|
$zip->close();
|
|
} else {
|
|
throw new \Exception("Impossibile estrarre {$zipPath}");
|
|
}
|
|
}
|
|
|
|
private function updateApplicationFiles(string $extractPath): void
|
|
{
|
|
// Lista files da NON sovrascrivere
|
|
$preserveFiles = [
|
|
'.env',
|
|
'storage/app/*',
|
|
'storage/logs/*',
|
|
'storage/framework/cache/*',
|
|
'storage/framework/sessions/*',
|
|
'storage/framework/views/*'
|
|
];
|
|
|
|
// Copia files (eccetto quelli da preservare)
|
|
File::copyDirectory($extractPath, base_path(), function($path) use ($preserveFiles) {
|
|
foreach ($preserveFiles as $preserve) {
|
|
if (fnmatch($preserve, $path)) {
|
|
return false; // Non copiare
|
|
}
|
|
}
|
|
return true; // Copia
|
|
});
|
|
}
|
|
|
|
private function verifyChecksum(string $filePath, string $version): void
|
|
{
|
|
// Ottieni checksum atteso dall'API
|
|
$response = Http::withHeaders([
|
|
'Authorization' => "Bearer {$this->apiKey}"
|
|
])->get("{$this->apiBaseUrl}/api/v1/updates/checksum/{$version}");
|
|
|
|
$expectedChecksum = $response->json()['checksum'];
|
|
$actualChecksum = hash_file('sha256', $filePath);
|
|
|
|
if ($expectedChecksum !== $actualChecksum) {
|
|
throw new \Exception("Checksum non valido per versione {$version}");
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## ⚙️ Configurazione Client
|
|
|
|
### Config: `config/netgescon.php`
|
|
```php
|
|
<?php
|
|
|
|
return [
|
|
'version' => env('NETGESCON_VERSION', '2.0.0'),
|
|
|
|
'update' => [
|
|
'api_url' => env('NETGESCON_UPDATE_API_URL', 'https://update.netgescon.com'),
|
|
'api_key' => env('NETGESCON_UPDATE_API_KEY'),
|
|
'api_secret' => env('NETGESCON_UPDATE_API_SECRET'),
|
|
'check_interval' => env('NETGESCON_UPDATE_CHECK_INTERVAL', 24), // ore
|
|
'auto_backup' => env('NETGESCON_UPDATE_AUTO_BACKUP', true),
|
|
'release_channel' => env('NETGESCON_RELEASE_CHANNEL', 'stable'), // stable|development
|
|
],
|
|
|
|
'license' => [
|
|
'codice_utente' => env('NETGESCON_LICENSE_CODE'),
|
|
'livello_servizio' => env('NETGESCON_LICENSE_LEVEL', 'basic'),
|
|
'scadenza' => env('NETGESCON_LICENSE_EXPIRES'),
|
|
],
|
|
];
|
|
```
|
|
|
|
### Environment Variables (`.env`)
|
|
```env
|
|
# NetGesCon Update System
|
|
NETGESCON_VERSION=2.0.0
|
|
NETGESCON_UPDATE_API_URL=https://update.netgescon.com
|
|
NETGESCON_UPDATE_API_KEY=your_api_key_here
|
|
NETGESCON_UPDATE_API_SECRET=your_api_secret_here
|
|
NETGESCON_UPDATE_CHECK_INTERVAL=24
|
|
NETGESCON_UPDATE_AUTO_BACKUP=true
|
|
NETGESCON_RELEASE_CHANNEL=stable
|
|
|
|
# License
|
|
NETGESCON_LICENSE_CODE=USR12345
|
|
NETGESCON_LICENSE_LEVEL=professional
|
|
NETGESCON_LICENSE_EXPIRES=2026-07-07
|
|
```
|
|
|
|
## 🕒 Scheduling Automatico
|
|
|
|
### `app/Console/Kernel.php`
|
|
```php
|
|
protected function schedule(Schedule $schedule)
|
|
{
|
|
// Check aggiornamenti automatico (ogni 6 ore)
|
|
$schedule->command('update:check --channel=stable')
|
|
->everySixHours()
|
|
->runInBackground()
|
|
->sendOutputTo(storage_path('logs/update-check.log'));
|
|
|
|
// Verifica licenza (ogni giorno)
|
|
$schedule->command('license:verify')
|
|
->daily()
|
|
->at('02:00');
|
|
|
|
// Cleanup update files (ogni settimana)
|
|
$schedule->command('update:cleanup')
|
|
->weekly()
|
|
->sundays()
|
|
->at('03:00');
|
|
}
|
|
```
|
|
|
|
## 🔔 Sistema Notifiche
|
|
|
|
### Notifica Aggiornamento Disponibile
|
|
```php
|
|
<?php
|
|
// app/Notifications/UpdateAvailableNotification.php
|
|
|
|
namespace App\Notifications;
|
|
|
|
use Illuminate\Notifications\Notification;
|
|
use Illuminate\Notifications\Messages\MailMessage;
|
|
|
|
class UpdateAvailableNotification extends Notification
|
|
{
|
|
private $updateInfo;
|
|
|
|
public function __construct(array $updateInfo)
|
|
{
|
|
$this->updateInfo = $updateInfo;
|
|
}
|
|
|
|
public function via($notifiable)
|
|
{
|
|
return ['mail', 'database'];
|
|
}
|
|
|
|
public function toMail($notifiable)
|
|
{
|
|
return (new MailMessage)
|
|
->subject('NetGesCon: Aggiornamento Disponibile')
|
|
->greeting('Ciao ' . $notifiable->name)
|
|
->line("È disponibile una nuova versione di NetGesCon: {$this->updateInfo['latest_version']}")
|
|
->line("Versione attuale: {$this->updateInfo['current_version']}")
|
|
->line("Novità principali:")
|
|
->line($this->updateInfo['changelog'])
|
|
->action('Aggiorna Ora', url('/admin/updates'))
|
|
->line('Ti consigliamo di aggiornare per avere le ultime funzionalità e correzioni.');
|
|
}
|
|
}
|
|
```
|
|
|
|
## 📱 Frontend Update Manager
|
|
|
|
### Update Status Component (Vue.js)
|
|
```vue
|
|
<template>
|
|
<div class="update-manager">
|
|
<div v-if="updateAvailable" class="update-banner">
|
|
<div class="update-info">
|
|
<h4>🎉 Aggiornamento Disponibile!</h4>
|
|
<p>NetGesCon v{{ latestVersion }} è pronto per l'installazione</p>
|
|
<small>Versione attuale: v{{ currentVersion }}</small>
|
|
</div>
|
|
|
|
<div class="update-actions">
|
|
<button @click="viewChangelog" class="btn btn-outline">
|
|
📋 Novità
|
|
</button>
|
|
<button @click="startUpdate" class="btn btn-primary" :disabled="isUpdating">
|
|
⬆️ Aggiorna Ora
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Progress Modal -->
|
|
<div v-if="isUpdating" class="update-modal">
|
|
<div class="modal-content">
|
|
<h3>⚙️ Aggiornamento in corso...</h3>
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" :style="{width: progress + '%'}"></div>
|
|
</div>
|
|
<p>{{ currentStep }} ({{ progress }}%)</p>
|
|
<div class="update-log">
|
|
<pre v-for="line in updateLog" :key="line">{{ line }}</pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
data() {
|
|
return {
|
|
updateAvailable: false,
|
|
currentVersion: '2.0.0',
|
|
latestVersion: null,
|
|
isUpdating: false,
|
|
progress: 0,
|
|
currentStep: '',
|
|
updateLog: []
|
|
}
|
|
},
|
|
|
|
mounted() {
|
|
this.checkForUpdates();
|
|
// Check ogni ora
|
|
setInterval(this.checkForUpdates, 3600000);
|
|
},
|
|
|
|
methods: {
|
|
async checkForUpdates() {
|
|
try {
|
|
const response = await axios.get('/api/updates/check');
|
|
this.updateAvailable = response.data.update_available;
|
|
this.latestVersion = response.data.latest_version;
|
|
} catch (error) {
|
|
console.error('Errore controllo aggiornamenti:', error);
|
|
}
|
|
},
|
|
|
|
async startUpdate() {
|
|
if (!confirm('Sicuro di voler procedere con l\'aggiornamento?')) {
|
|
return;
|
|
}
|
|
|
|
this.isUpdating = true;
|
|
this.progress = 0;
|
|
this.updateLog = [];
|
|
|
|
try {
|
|
// Avvia aggiornamento via WebSocket o polling
|
|
await this.performUpdate();
|
|
} catch (error) {
|
|
alert('Errore durante l\'aggiornamento: ' + error.message);
|
|
} finally {
|
|
this.isUpdating = false;
|
|
}
|
|
},
|
|
|
|
async performUpdate() {
|
|
// Implementa WebSocket o polling per progress real-time
|
|
const response = await axios.post('/api/updates/install', {
|
|
version: this.latestVersion
|
|
});
|
|
|
|
// Simula progress updates
|
|
const steps = [
|
|
'Download aggiornamento...',
|
|
'Backup sistema...',
|
|
'Installazione files...',
|
|
'Aggiornamento database...',
|
|
'Completamento...'
|
|
];
|
|
|
|
for (let i = 0; i < steps.length; i++) {
|
|
this.currentStep = steps[i];
|
|
this.progress = ((i + 1) / steps.length) * 100;
|
|
this.updateLog.push(`[${new Date().toLocaleTimeString()}] ${steps[i]}`);
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
}
|
|
|
|
// Ricarica pagina per nuova versione
|
|
setTimeout(() => {
|
|
window.location.reload();
|
|
}, 2000);
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
```
|
|
|
|
## 🔒 Sicurezza e Validazione
|
|
|
|
### Validazione Checksum
|
|
```php
|
|
private function validateDownload(string $filePath, string $expectedChecksum): bool
|
|
{
|
|
$actualChecksum = hash_file('sha256', $filePath);
|
|
return hash_equals($expectedChecksum, $actualChecksum);
|
|
}
|
|
```
|
|
|
|
### Signature Verification (GPG)
|
|
```php
|
|
private function verifySignature(string $filePath, string $signaturePath): bool
|
|
{
|
|
$publicKey = file_get_contents(resource_path('keys/netgescon-public.key'));
|
|
|
|
// Implementa verifica GPG signature
|
|
// ...
|
|
|
|
return $isValid;
|
|
}
|
|
```
|
|
|
|
### Rate Limiting API
|
|
```php
|
|
// routes/api.php
|
|
Route::middleware(['throttle:10,1'])->group(function () {
|
|
Route::get('/updates/check', [UpdateController::class, 'check']);
|
|
Route::post('/updates/download', [UpdateController::class, 'download']);
|
|
});
|
|
```
|
|
|
|
## 📊 Monitoring e Analytics
|
|
|
|
### Log Update Events
|
|
```php
|
|
class UpdateEventLogger
|
|
{
|
|
public static function logUpdateStart(string $version): void
|
|
{
|
|
Log::info('Update started', [
|
|
'version_from' => config('netgescon.version'),
|
|
'version_to' => $version,
|
|
'timestamp' => now(),
|
|
'user_ip' => request()->ip()
|
|
]);
|
|
}
|
|
|
|
public static function logUpdateComplete(string $version, int $duration): void
|
|
{
|
|
Log::info('Update completed', [
|
|
'version' => $version,
|
|
'duration_seconds' => $duration,
|
|
'timestamp' => now()
|
|
]);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Metriche Sistema
|
|
- Tempo medio aggiornamento
|
|
- Tasso successo/fallimento
|
|
- Versioni più utilizzate
|
|
- Problemi comuni durante update
|
|
|
|
---
|
|
|
|
## 🎯 Roadmap Implementazione
|
|
|
|
### Fase 1: Foundation (Week 1-2)
|
|
- ✅ Database schema design
|
|
- ✅ API endpoints base
|
|
- ⏳ UpdateService implementation
|
|
- ⏳ Basic Artisan commands
|
|
|
|
### Fase 2: Core Features (Week 3-4)
|
|
- ⏳ Download e installazione automatica
|
|
- ⏳ Sistema backup/rollback
|
|
- ⏳ Frontend update manager
|
|
- ⏳ Notifiche sistema
|
|
|
|
### Fase 3: Advanced (Week 5-6)
|
|
- ⏳ Gestione licenze
|
|
- ⏳ Release channels
|
|
- ⏳ Security features
|
|
- ⏳ Monitoring e analytics
|
|
|
|
### Fase 4: Testing & Deployment (Week 7-8)
|
|
- ⏳ Testing completo
|
|
- ⏳ Documentation
|
|
- ⏳ Production deployment
|
|
- ⏳ User onboarding
|
|
|
|
---
|
|
|
|
*Ultima modifica: 7 Luglio 2025*
|