netgescon-day0/docs/SPECIFICA-SVILUPPO-MODULI.md

1162 lines
34 KiB
Markdown

# 📋 GUIDA COMPLETA SVILUPPO MODULI NETGESCON
**Versione: 2.0 - Data: 01 Agosto 2025**
---
## 🎯 **INTRODUZIONE**
NetGescon utilizza un sistema modulare avanzato che permette di sviluppare, installare e monetizzare moduli aggiuntivi. Ogni modulo è completamente autonomo e può essere distribuito come prodotto commerciale.
**✅ AGGIORNAMENTI VERSIONE 2.0:**
- Layout template unificato (`modules.layouts.base`)
- Sistema permessi automatico migliorato
- Integrazione grafica perfetta con NetGescon
- Sidebar dinamica con stati moduli
- Cache management ottimizzato
### **🏗️ ARCHITETTURA MODULARE**
```
NetGescon/
├── app/
│ ├── Services/
│ │ ├── ModuleManager.php # Gestione moduli
│ │ └── HookManager.php # Sistema eventi
│ ├── Providers/
│ │ └── ModuleServiceProvider.php # Caricamento automatico moduli
│ └── Modules/
│ └── [NomeModulo]/
│ ├── module.json # Configurazione modulo
│ ├── Controllers/ # Controller Laravel
│ ├── Routes/ # File route
│ ├── Migrations/ # Migrazioni database
│ ├── Seeders/ # Dati iniziali
│ └── Views/ # Template Blade
├── resources/views/
│ └── modules/
│ └── layouts/
│ └── base.blade.php # Template base moduli
└── docs/
├── SPECIFICA-SVILUPPO-MODULI.md
└── TEMPLATE-SVILUPPO-MODULI.md
```
---
## 🎨 **NUOVO SISTEMA LAYOUT UNIFICATO**
### **Template Base Standard**
Tutti i moduli DEVONO utilizzare il template base unificato:
```blade
@extends('modules.layouts.base')
@php
$moduleTitle = 'Nome del Modulo';
$moduleIcon = 'fas fa-calculator';
$moduleBreadcrumb = 'Moduli > Nome Modulo';
@endphp
@section('module-actions')
<div class="btn-group" role="group">
@can('modulo_create')
<a href="{{ route('modulo.create') }}" class="btn btn-module-primary">
<i class="fas fa-plus me-1"></i>
Nuovo Elemento
</a>
@endcan
<button type="button" class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown">
<i class="fas fa-cog"></i>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#"><i class="fas fa-file-export me-2"></i>Esporta</a></li>
<li><a class="dropdown-item" href="#"><i class="fas fa-cog me-2"></i>Impostazioni</a></li>
</ul>
</div>
@endsection
@section('module-content')
<!-- Il tuo contenuto qui -->
@endsection
```
### **Classi CSS Standardizzate**
Il sistema fornisce queste classi CSS preconfigurate:
```css
/* Card statistiche */
.module-stats-card /* Card per statistiche rapide */
.module-stats-number /* Numero grande nelle statistiche */
.module-stats-label /* Label sotto il numero */
/* Pulsanti */
.btn-module-primary /* Pulsante primario modulo */
/* Layout */
.module-card /* Card generica per contenuti */
.module-card-header /* Header della card */
.module-card-body /* Body della card */
.module-card-title /* Titolo della card */
.module-empty-state /* Stato vuoto con icona */
```
---
## 🔐 **NUOVO SISTEMA PERMESSI AUTOMATICO**
### **Comando di Installazione Permessi**
Ogni modulo deve avere un comando Artisan per installare i permessi:
```php
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
use Illuminate\Support\Facades\DB;
class UpdateNomeModuloPermissions extends Command
{
protected $signature = 'nomemodulo:permissions';
protected $description = 'Installa i permessi per il modulo NomeModulo';
public function handle()
{
$this->info('🔧 Installazione permessi modulo NomeModulo...');
// Definisci i permessi del modulo
$permissions = [
'nomemodulo_view' => 'Visualizzare elementi del modulo',
'nomemodulo_create' => 'Creare nuovi elementi',
'nomemodulo_edit' => 'Modificare elementi esistenti',
'nomemodulo_delete' => 'Eliminare elementi',
'nomemodulo_export' => 'Esportare dati',
'nomemodulo_settings' => 'Gestire impostazioni modulo'
];
// Crea i permessi
foreach ($permissions as $name => $description) {
$permission = Permission::firstOrCreate(
['name' => $name],
['guard_name' => 'web']
);
$this->line("✅ Permesso: {$name}");
}
// Assegna permessi ai ruoli amministrativi
$adminRoles = ['admin', 'amministratore', 'super-admin'];
foreach ($adminRoles as $roleName) {
$role = Role::where('name', $roleName)->first();
if ($role) {
foreach (array_keys($permissions) as $permissionName) {
$permission = Permission::where('name', $permissionName)->first();
if ($permission && !$role->hasPermissionTo($permission)) {
$role->givePermissionTo($permission);
}
}
$this->line("✅ Permessi assegnati al ruolo: {$roleName}");
}
}
// Aggiorna il record del modulo nel database
DB::table('modules')
->where('name', 'NomeModulo')
->update([
'permissions' => json_encode(array_keys($permissions)),
'updated_at' => now()
]);
$this->info('🎉 Permessi modulo NomeModulo installati con successo!');
return 0;
}
}
```
### **Utilizzo Permessi nei Controller**
```php
public function __construct()
{
$this->middleware('auth');
$this->middleware('permission:nomemodulo_view')->only(['index', 'show']);
$this->middleware('permission:nomemodulo_create')->only(['create', 'store']);
$this->middleware('permission:nomemodulo_edit')->only(['edit', 'update']);
$this->middleware('permission:nomemodulo_delete')->only(['destroy']);
}
```
---
## 📊 **SIDEBAR DINAMICA E STATI MODULI**
### **Integrazione nella Sidebar**
Il sistema gestisce automaticamente l'apparizione dei moduli nella sidebar. La sidebar mostra:
-**ATTIVO** - Modulo installato e funzionante
-**Prezzo** - Modulo disponibile ma non installato
- 🔒 **Disabilitato** - Modulo installato ma non attivo
### **Aggiornamento SidebarComposer**
Il `SidebarComposer` è stato aggiornato per fornire la lista `activeModules`:
```php
public function compose(View $view)
{
// ...codice esistente...
$view->with([
'stabili' => $stabili,
'stabileAttivo' => $stabileAttivo,
'anni' => $gestioni->pluck('anno_gestione')->unique(),
'annoAttivo' => $annoAttivo,
'gestione' => $gestioneAttiva,
'activeModules' => Cache::remember('netgescon.active_modules', 3600, function() {
return DB::table('modules')->where('status', 'active')->pluck('name')->toArray();
}),
]);
}
```
---
## 🚀 **PROCESSO DI INSTALLAZIONE SEMPLIFICATO**
### **1. Registrazione Database**
```php
// Via Tinker o comando
DB::table('modules')->insert([
'name' => 'NomeModulo',
'display_name' => 'Nome Visualizzato',
'description' => 'Descrizione del modulo',
'version' => '1.0.0',
'status' => 'active',
'license' => 'commercial',
'price' => 99.00,
'currency' => 'EUR',
'billing' => 'yearly',
'config' => '{}',
'dependencies' => '[]',
'permissions' => '[]',
'created_at' => now(),
'updated_at' => now()
]);
```
### **2. Installazione Permessi**
```bash
php artisan nomemodulo:permissions
```
### **3. Pulizia Cache**
```bash
php artisan cache:clear
php artisan config:clear
php artisan view:clear
```
---
## ✅ **CHECKLIST MODULO COMPLETO V2.0**
### **Files Obbligatori**
- [ ] Controller con CRUD base
- [ ] Route definitions (`Routes/web.php`)
- [ ] Migration database
- [ ] Views usando `@extends('modules.layouts.base')`
- [ ] Comando permessi (`php artisan make:command UpdateNomeModuloPermissions`)
- [ ] Middleware permessi nel controller
- [ ] Integrazione nella sidebar
### **Aspetti Tecnici**
- [ ] Utilizza template base unificato
- [ ] Permessi installati e assegnati
- [ ] Cache management corretto
- [ ] Responsive design (Bootstrap 5)
- [ ] Tooltips e UX enhancements
- [ ] Error handling robusto
- [ ] Empty states informativi
### **Testing**
- [ ] Modulo visibile in sidebar
- [ ] Permessi funzionanti (403 risolto)
- [ ] Layout grafico coerente
- [ ] Funzionalità CRUD complete
- [ ] Performance accettabili
---
## 🎯 **ESEMPIO PRATICO: MODULO CONTABILITÀ**
Il modulo Contabilità è il nostro modulo di riferimento che implementa tutte le best practices:
### **Struttura File**
```
app/Modules/Contabilita/
├── Controllers/ContabilitaController.php
├── Routes/web.php
├── Migrations/2025_01_22_170000_create_piano_conti_tables.php
└── Views/
└── index.blade.php
```
### **Features Implementate**
- ✅ Layout unificato con template base
- ✅ Statistiche rapide in card
- ✅ Tabella responsive con azioni
- ✅ Filtri di ricerca avanzati
- ✅ Sistema permessi completo
- ✅ Empty state informativo
- ✅ Pagination integrata
- ✅ Tooltips e UX enhancements
---
## 📞 **SUPPORTO E RISORSE**
### **Documentazione di Riferimento**
- `docs/SPECIFICA-SVILUPPO-MODULI.md` - Questa guida
- `docs/TEMPLATE-SVILUPPO-MODULI.md` - Template da copiare
- `resources/views/modules/layouts/base.blade.php` - Template base
### **Moduli di Esempio**
- **Contabilità** - Modulo complesso con statistiche e CRUD
- **StampeRate** - Modulo con processing e file generation
### **Comandi Utili**
```bash
# Installa permessi modulo
php artisan nomemodulo:permissions
# Controlla moduli attivi
php artisan tinker --execute="DB::table('modules')->where('status', 'active')->get(['name', 'status'])"
# Pulisci cache moduli
php artisan cache:clear
```
---
**✨ Il sistema modulare NetGescon è ora maturo, stabile e facilmente estendibile. Seguendo questa guida potrai creare moduli professionali che si integrano perfettamente con l'ecosistema esistente.**
---
## 🎯 **INTRODUZIONE**
NetGescon utilizza un sistema modulare avanzato che permette di sviluppare, installare e monetizzare moduli aggiuntivi. Ogni modulo è completamente autonomo e può essere distribuito come prodotto commerciale.
### **🏗️ ARCHITETTURA MODULARE**
```
NetGescon/
├── app/
│ ├── Services/
│ │ ├── ModuleManager.php # Gestione moduli
│ │ └── HookManager.php # Sistema eventi
│ └── Modules/
│ └── [NomeModulo]/
│ ├── module.json # Configurazione modulo
│ ├── Controllers/ # Controller Laravel
│ ├── Routes/ # File route
│ ├── Migrations/ # Migrazioni database
│ ├── Seeders/ # Dati iniziali
│ ├── Views/ # Template Blade
│ └── Assets/ # CSS/JS specifici
```
---
## 🔧 **STRUTTURA MODULO STANDARD**
### **1. Configurazione Base (module.json)**
```json
{
"name": "NomeModulo",
"display_name": "Nome Visualizzato",
"version": "1.0.0",
"description": "Descrizione del modulo",
"author": "Nome Sviluppatore",
"email": "email@sviluppatore.com",
"license": "commercial",
"price": 99.00,
"currency": "EUR",
"billing": "yearly",
"requirements": {
"laravel": ">=10.0",
"php": ">=8.1",
"netgescon": ">=1.0"
},
"dependencies": [],
"permissions": {
"modulo_view": "Visualizzare il modulo",
"modulo_create": "Creare elementi",
"modulo_edit": "Modificare elementi",
"modulo_delete": "Eliminare elementi",
"modulo_admin": "Amministrazione completa"
},
"menu_items": [
{
"title": "Dashboard Modulo",
"route": "modulo.index",
"icon": "fa-dashboard",
"permission": "modulo_view",
"order": 1
}
],
"hooks": [
"modulo.before_create",
"modulo.after_create",
"modulo.before_update",
"modulo.after_update",
"modulo.before_delete",
"modulo.after_delete"
],
"config": {
"auto_install_routes": true,
"auto_install_migrations": true,
"cache_enabled": true,
"api_enabled": true
}
}
```
### **2. Controller Base**
```php
<?php
namespace App\Modules\NomeModulo\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use App\Services\HookManager;
class NomeModuloController extends Controller
{
protected $hookManager;
public function __construct()
{
// Middleware di autenticazione
$this->middleware('auth');
// Middleware permessi specifici del modulo
$this->middleware('permission:modulo_view')->only(['index', 'show']);
$this->middleware('permission:modulo_create')->only(['create', 'store']);
$this->middleware('permission:modulo_edit')->only(['edit', 'update']);
$this->middleware('permission:modulo_delete')->only(['destroy']);
$this->hookManager = app(HookManager::class);
}
public function index(Request $request)
{
try {
// Hook pre-azione
$this->hookManager->execute('modulo.before_index', [$request]);
// Logica del controller
$data = DB::table('modulo_table')->paginate(20);
// Hook post-azione
$this->hookManager->execute('modulo.after_index', [$data]);
return view('modules.nome-modulo.index', compact('data'));
} catch (\Exception $e) {
Log::error("Errore modulo: " . $e->getMessage());
return back()->with('error', 'Errore: ' . $e->getMessage());
}
}
// Altri metodi CRUD...
}
```
### **3. Routes (web.php)**
```php
<?php
use Illuminate\Support\Facades\Route;
use App\Modules\NomeModulo\Controllers\NomeModuloController;
// Gruppo route con middleware
Route::middleware(['auth', 'verified'])->group(function () {
// Route principali
Route::prefix('nome-modulo')->name('modulo.')->group(function () {
Route::get('/', [NomeModuloController::class, 'index'])->name('index');
Route::get('/create', [NomeModuloController::class, 'create'])->name('create');
Route::post('/', [NomeModuloController::class, 'store'])->name('store');
Route::get('/{id}', [NomeModuloController::class, 'show'])->name('show');
Route::get('/{id}/edit', [NomeModuloController::class, 'edit'])->name('edit');
Route::put('/{id}', [NomeModuloController::class, 'update'])->name('update');
Route::delete('/{id}', [NomeModuloController::class, 'destroy'])->name('destroy');
});
// Route API per AJAX
Route::prefix('api/nome-modulo')->name('api.modulo.')->group(function () {
Route::get('/data', [NomeModuloController::class, 'getData'])->name('data');
Route::post('/action', [NomeModuloController::class, 'action'])->name('action');
});
});
```
### **4. Migration Standard**
```php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
// Tabella principale del modulo
Schema::create('modulo_table', function (Blueprint $table) {
$table->id();
$table->string('nome');
$table->text('descrizione')->nullable();
$table->enum('status', ['attivo', 'inattivo'])->default('attivo');
$table->json('config')->nullable();
// Audit fields standard
$table->unsignedBigInteger('created_by')->nullable();
$table->unsignedBigInteger('updated_by')->nullable();
$table->timestamps();
$table->softDeletes();
// Indici per performance
$table->index(['status', 'created_at']);
$table->index('nome');
// Foreign keys
$table->foreign('created_by')->references('id')->on('users')->onDelete('set null');
$table->foreign('updated_by')->references('id')->on('users')->onDelete('set null');
});
// Tabella log/cronologia
Schema::create('modulo_history', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('record_id');
$table->string('action');
$table->json('old_data')->nullable();
$table->json('new_data')->nullable();
$table->unsignedBigInteger('user_id')->nullable();
$table->timestamp('created_at');
$table->index(['record_id', 'created_at']);
$table->foreign('record_id')->references('id')->on('modulo_table')->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onDelete('set null');
});
}
public function down(): void
{
Schema::dropIfExists('modulo_history');
Schema::dropIfExists('modulo_table');
}
};
```
### **5. Seeder con Dati Base**
```php
<?php
namespace App\Modules\NomeModulo\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class NomeModuloSeeder extends Seeder
{
public function run(): void
{
// Configurazioni base
$configs = [
[
'chiave' => 'modulo.default_setting',
'valore' => 'valore_default',
'descrizione' => 'Impostazione di default',
'created_at' => now(),
'updated_at' => now()
]
];
foreach ($configs as $config) {
DB::table('modulo_config')->insert($config);
}
// Dati di esempio (solo in development)
if (app()->environment('local', 'development')) {
$esempi = [
[
'nome' => 'Esempio 1',
'descrizione' => 'Dato di esempio',
'status' => 'attivo',
'created_by' => 1,
'created_at' => now(),
'updated_at' => now()
]
];
foreach ($esempi as $esempio) {
DB::table('modulo_table')->insert($esempio);
}
}
echo "✅ Seeder NomeModulo completato\n";
}
}
```
---
## 🔌 **SISTEMA HOOK E EVENTI**
### **Hook Disponibili nel Sistema**
```php
// Hook di sistema core
'app.boot' // All'avvio dell'applicazione
'app.before_request' // Prima di ogni richiesta
'app.after_request' // Dopo ogni richiesta
// Hook moduli
'module.before_install' // Prima installazione modulo
'module.after_install' // Dopo installazione modulo
'module.before_uninstall' // Prima disinstallazione
'module.after_uninstall' // Dopo disinstallazione
// Hook utenti
'user.before_login' // Prima del login
'user.after_login' // Dopo il login
'user.before_logout' // Prima del logout
// Hook del tuo modulo
'modulo.before_create' // Prima della creazione
'modulo.after_create' // Dopo la creazione
'modulo.before_update' // Prima dell'aggiornamento
'modulo.after_update' // Dopo l'aggiornamento
'modulo.before_delete' // Prima dell'eliminazione
'modulo.after_delete' // Dopo l'eliminazione
```
### **Utilizzo Hook nel Modulo**
```php
// Nel controller
$this->hookManager->execute('modulo.before_create', [$data]);
// Registrazione hook listener (nel boot del modulo)
$this->hookManager->register('modulo.after_create', function($data) {
// Logica eseguita dopo la creazione
Log::info('Nuovo elemento creato: ' . $data['nome']);
});
```
---
## 💾 **DATABASE E PERFORMANCE**
### **Best Practices Database**
1. **Nomi Tabelle**: Sempre prefisso modulo (`modulo_tabella`)
2. **Indici**: Su campi più interrogati (`status`, `created_at`, ecc.)
3. **Foreign Keys**: Sempre con `onDelete('set null')` o `cascade`
4. **Soft Deletes**: Per dati importanti
5. **JSON Fields**: Per configurazioni flessibili
6. **Audit Trail**: Campi `created_by`, `updated_by`, `deleted_by`
### **Ottimizzazioni Consigliate**
```php
// Uso di scope nei Model
public function scopeAttivo($query)
{
return $query->where('status', 'attivo');
}
// Cache per query pesanti
$data = Cache::tags(['modulo_data'])->remember('modulo_list', 3600, function() {
return DB::table('modulo_table')->where('status', 'attivo')->get();
});
// Query Builder ottimizzate
$risultati = DB::table('modulo_table')
->select(['id', 'nome', 'status']) // Solo campi necessari
->where('status', 'attivo')
->orderBy('created_at', 'desc')
->limit(20)
->get();
```
---
## 🔐 **SICUREZZA E PERMESSI**
### **Sistema Permessi**
```php
// Definizione permessi nel module.json
"permissions": {
"modulo_view": "Visualizzare elementi del modulo",
"modulo_create": "Creare nuovi elementi",
"modulo_edit": "Modificare elementi esistenti",
"modulo_delete": "Eliminare elementi",
"modulo_export": "Esportare dati",
"modulo_admin": "Amministrazione completa modulo"
}
// Uso nei controller
$this->middleware('permission:modulo_view')->only(['index', 'show']);
$this->middleware('permission:modulo_create')->only(['create', 'store']);
// Controllo nei template Blade
@can('modulo_create')
<a href="{{ route('modulo.create') }}" class="btn btn-primary">Nuovo</a>
@endcan
```
### **Validazione Input**
```php
// Nel controller
public function store(Request $request)
{
$validated = $request->validate([
'nome' => 'required|string|max:255|unique:modulo_table',
'email' => 'required|email',
'importo' => 'required|numeric|min:0',
'data' => 'required|date|after:today'
]);
// Sanitizzazione aggiuntiva
$validated['nome'] = strip_tags($validated['nome']);
// Creazione record...
}
```
---
## 📦 **INSTALLAZIONE E DISTRIBUZIONE**
### **Processo di Installazione**
1. **Preparazione ZIP**:
```
NomeModulo.zip
├── module.json
├── Controllers/
├── Routes/
├── Migrations/
├── Seeders/
└── Views/
```
2. **Installazione via ModuleManager**:
```php
$moduleManager = app(ModuleManager::class);
$result = $moduleManager->installModule('NomeModulo', $zipPath);
```
3. **Registrazione Automatica**:
- Route caricate automaticamente
- Migration eseguite
- Permessi registrati
- Menu integrato
### **Command Artisan per Installazione**
```php
// app/Console/Commands/InstallModule.php
class InstallModule extends Command
{
protected $signature = 'module:install {name} {--zip=}';
public function handle()
{
$name = $this->argument('name');
$zipPath = $this->option('zip');
$moduleManager = app(ModuleManager::class);
try {
$result = $moduleManager->installModule($name, $zipPath);
$this->info("✅ Modulo {$name} installato con successo!");
} catch (\Exception $e) {
$this->error("❌ Errore installazione: " . $e->getMessage());
}
}
}
```
---
## 🎨 **FRONTEND E UX**
### **Template Blade Base**
```blade
{{-- resources/views/modules/nome-modulo/index.blade.php --}}
@extends('layouts.app')
@section('title', 'Nome Modulo')
@section('content')
<div class="container-fluid">
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h3 class="card-title">Nome Modulo</h3>
@can('modulo_create')
<a href="{{ route('modulo.create') }}" class="btn btn-primary">
<i class="fas fa-plus"></i> Nuovo
</a>
@endcan
</div>
<div class="card-body">
{{-- Filtri di ricerca --}}
<form method="GET" class="mb-3">
<div class="row">
<div class="col-md-4">
<input type="text" name="search" class="form-control"
placeholder="Cerca..." value="{{ request('search') }}">
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-outline-primary">
<i class="fas fa-search"></i>
</button>
</div>
</div>
</form>
{{-- Tabella dati --}}
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>Nome</th>
<th>Status</th>
<th>Data Creazione</th>
<th>Azioni</th>
</tr>
</thead>
<tbody>
@forelse($data as $item)
<tr>
<td>{{ $item->nome }}</td>
<td>
<span class="badge badge-{{ $item->status == 'attivo' ? 'success' : 'secondary' }}">
{{ ucfirst($item->status) }}
</span>
</td>
<td>{{ $item->created_at->format('d/m/Y H:i') }}</td>
<td>
@can('modulo_view')
<a href="{{ route('modulo.show', $item->id) }}" class="btn btn-sm btn-info">
<i class="fas fa-eye"></i>
</a>
@endcan
@can('modulo_edit')
<a href="{{ route('modulo.edit', $item->id) }}" class="btn btn-sm btn-warning">
<i class="fas fa-edit"></i>
</a>
@endcan
@can('modulo_delete')
<form method="POST" action="{{ route('modulo.destroy', $item->id) }}"
style="display: inline-block;">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-sm btn-danger"
onclick="return confirm('Sei sicuro?')">
<i class="fas fa-trash"></i>
</button>
</form>
@endcan
</td>
</tr>
@empty
<tr>
<td colspan="4" class="text-center">Nessun elemento trovato</td>
</tr>
@endforelse
</tbody>
</table>
</div>
{{-- Paginazione --}}
{{ $data->links() }}
</div>
</div>
</div>
</div>
</div>
@endsection
```
### **CSS/JS Specifici del Modulo**
```css
/* public/css/modules/nome-modulo.css */
.modulo-card {
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.modulo-stats {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 8px;
padding: 20px;
}
```
---
## 🧪 **TESTING E DEBUG**
### **Unit Test Base**
```php
<?php
namespace Tests\Modules\NomeModulo;
use Tests\TestCase;
use App\Modules\NomeModulo\Controllers\NomeModuloController;
class NomeModuloTest extends TestCase
{
public function test_index_displays_data()
{
$user = User::factory()->create();
$user->givePermissionTo('modulo_view');
$response = $this->actingAs($user)->get(route('modulo.index'));
$response->assertStatus(200);
$response->assertViewIs('modules.nome-modulo.index');
}
public function test_create_requires_permission()
{
$user = User::factory()->create();
$response = $this->actingAs($user)->get(route('modulo.create'));
$response->assertStatus(403);
}
public function test_store_validates_input()
{
$user = User::factory()->create();
$user->givePermissionTo('modulo_create');
$response = $this->actingAs($user)->post(route('modulo.store'), []);
$response->assertSessionHasErrors(['nome', 'email']);
}
}
```
### **Logging e Debug**
```php
// Nel controller
use Illuminate\Support\Facades\Log;
public function action()
{
Log::info('Modulo: Inizio azione', ['user' => auth()->id()]);
try {
// Logica
Log::debug('Modulo: Dati elaborati', ['data' => $processedData]);
} catch (\Exception $e) {
Log::error('Modulo: Errore azione', [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
'user' => auth()->id()
]);
}
}
```
---
## 💰 **MODELLO BUSINESS E PRICING**
### **Categorie di Moduli**
1. **Gratuiti** (€0):
- Moduli base/community
- Funzionalità essenziali
2. **Standard** (€49-99/anno):
- Moduli specializzati
- Funzionalità avanzate
3. **Premium** (€199-299/anno):
- Moduli complessi
- Integrazione esterna
- Support prioritario
4. **Enterprise** (€499+/anno):
- Moduli mission-critical
- Customizzazione
- SLA garantiti
### **Licenze e Distribuzione**
```json
{
"license": "commercial",
"price": 99.00,
"currency": "EUR",
"billing": "yearly",
"trial_days": 30,
"support_included": true,
"updates_included": true,
"installation_limit": 1
}
```
---
## 🚀 **DEPLOYMENT E MANUTENZIONE**
### **Checklist Pre-Release**
- [ ] Test su ambiente locale
- [ ] Validazione sicurezza
- [ ] Performance test
- [ ] Documentazione completa
- [ ] Screenshot/demo
- [ ] Pricing definito
- [ ] Support plan
### **Processo di Aggiornamento**
```php
// Migration di aggiornamento
public function up(): void
{
// Verifica versione precedente
$currentVersion = DB::table('modules')
->where('name', 'NomeModulo')
->value('version');
if (version_compare($currentVersion, '1.1.0', '<')) {
// Modifiche per v1.1.0
Schema::table('modulo_table', function (Blueprint $table) {
$table->string('nuovo_campo')->nullable();
});
}
}
```
---
## 📚 **RISORSE E SUPPORTO**
### **Documentazione Obbligatoria**
1. **README.md** - Panoramica e installazione
2. **CHANGELOG.md** - Log delle modifiche
3. **API.md** - Documentazione API se presente
4. **HELP.md** - Guida utente
### **Support e Community**
- Forum sviluppatori NetGescon
- Documentation wiki
- Code repository template
- Issue tracking system
---
## ✅ **CHECKLIST MODULO COMPLETO**
### **Files Essenziali**
- [ ] `module.json` configurato
- [ ] Controller con CRUD base
- [ ] Route definitions
- [ ] Migration database
- [ ] Seeder con dati base
- [ ] Template Blade base
- [ ] Middleware permessi
- [ ] Hook integration
- [ ] Unit tests
- [ ] Documentazione
### **Funzionalità Base**
- [ ] Autenticazione/Autorizzazione
- [ ] CRUD operations
- [ ] Ricerca e filtri
- [ ] Paginazione
- [ ] Export dati
- [ ] Logging attività
- [ ] Cache optimization
- [ ] Error handling
- [ ] Input validation
- [ ] API endpoints
### **Qualità Codice**
- [ ] PSR-4 compliance
- [ ] Commenti e documentation
- [ ] Error handling robusto
- [ ] Security best practices
- [ ] Performance optimization
- [ ] Mobile responsive UI
- [ ] Cross-browser compatibility
- [ ] Accessibility standards
---
**🎯 CONCLUSIONE**
Questa guida fornisce tutto il necessario per sviluppare moduli professionali per NetGescon. Il sistema modulare è progettato per essere:
- **Scalabile**: Supporta crescita dell'applicazione
- **Sicuro**: Permessi granulari e validazione
- **Performante**: Cache e ottimizzazioni database
- **Manutenibile**: Codice pulito e documentato
- **Commerciale**: Modello business integrato
Utilizzando questa specifica, puoi sviluppare moduli che si integrano perfettamente con NetGescon e possono essere distribuiti come prodotti commerciali.
---
**📞 CONTATTI SVILUPPO**
- Team NetGescon
- Email: dev@netgescon.com
- Repository: https://github.com/netgescon/modules