Strategia Profili Import Immutabili
Strategia Profili Import Immutabili
๐ฏ Decisione Architetturale
I profili import CSV sono IMMUTABILI - Una volta creati, non possono essere modificati, solo duplicati.
---
โ Perchรฉ questa scelta?
Problema: Data Integrity
``
Scenario problematico con profili modificabili:
1. Profilo "Juki Standard" โ Import 10.000 lavorazioni (Gen 2025) Mapping: Data, Operazione, Pezzi
2. Admin modifica mapping Mapping: Data, Operazione, Pezzi, Operatore, Durata
3. Profilo "Juki Standard" โ Import 5.000 lavorazioni (Feb 2025)
โ PROBLEMA:
- Lavorazioni Gen: senza Operatore/Durata
- Lavorazioni Feb: con Operatore/Durata
- Stessa struttura โ Dati inconsistenti!
`
Soluzione: Immutabilitร
`
โ Profilo "Juki Standard v1" โ Import Gen (frozen) โ Duplica โ "Juki Standard v1 (copia)" โ Modifica mapping โ Rinomina โ "Juki Standard v2" โ Import Feb โ Usa v2</p><p>Risultato: โ Ogni import ha il suo profilo specifico โ Integritร dati garantita โ Tracciabilitร completa
---
๐ง Implementazione
1. Route Duplica
File:
routes/i40.php</p><p></code>`<code>php
Route::post('/{importProfile}/duplicate', [ImportProfilesController::class, 'duplicate'])
->name('duplicate');
</code>`<code></p><p><h3><strong>2. Metodo Controller</strong></h3></p><p><strong>File</strong>: </code>app/Http/Controllers/Admin/I40/ImportProfilesController.php<code></p><p></code>`<code>php
public function duplicate(ImportProfile $importProfile)
{
// Replica profilo
$new = $importProfile->replicate();
// Nome univoco
$baseName = $importProfile->name;
$counter = 2;
$newName = "{$baseName} (copia)";
while (ImportProfile::where('name', $newName)->exists()) {
$newName = "{$baseName} (copia {$counter})";
$counter++;
}
$new->name = $newName;
$new->created_by = auth()->id();
$new->save();
// Duplica file CSV
if ($importProfile->sample_file_path) {
$newPath = 'I40/import-profiles/' . uniqid('profile_') . '.csv';
Storage::disk('public')->copy($importProfile->sample_file_path, $newPath);
$new->sample_file_path = $newPath;
$new->save();
}
return redirect()->with('success', "Profilo duplicato: '{$new->name}'");
}
</code>`<code></p><p><h3><strong>3. UI - Pulsante Duplica</strong></h3></p><p><strong>Nella tabella</strong>:
</code>`<code>html
<button onclick="duplicateProfile(id, name)">
<i class="bi bi-files"></i> Duplica
</button>
</code>`<code></p><p><strong>Nel modal dettaglio</strong>:
</code>`<code>html
<div class="modal-footer">
<button onclick="duplicateFromModal()">Duplica Profilo</button>
</div>
</code>`<code></p><p>---</p><p><h2>๐ซ Cosa NON ร Implementato</h2></p><p><ul><li>โ <strong>Update/Modifica</strong>: Rimosso completamente</li>
<li>โ <strong>Versioning</strong>: Non necessario con immutabilitร </li>
<li>โ <strong>Soft Delete</strong>: Eliminazione fisica (per ora)</li></p><p>---</p><p><h2>๐ Workflow Utente</h2></p><p><h3><strong>Creare Nuovo Profilo</strong></h3>
1. Click "Nuovo Profilo"
2. Upload CSV
3. Sistema analizza e propone mapping
4. Salva profilo
5. โ
Profilo frozen (immutabile)</p><p><h3><strong>Correggere/Aggiornare Profilo</strong></h3>
1. Visualizza profilo esistente
2. Click "Duplica" (tabella o modal)
3. Modifica nome duplicato (es. "Juki Standard v2")
4. โ
Nuovo profilo modificabile</p><p><h3><strong>Eliminare Profilo</strong></h3>
1. Click cestino
2. Conferma eliminazione
3. โ
Profilo e file CSV eliminati</p><p>---</p><p><h2>โ
Vantaggi</h2></p><p>1. <strong>Integritร Dati</strong>: Garantita al 100%
2. <strong>Semplicitร </strong>: Zero complessitร architetturale
3. <strong>Tracciabilitร </strong>: Ogni import ha profilo specifico
4. <strong>Sicurezza</strong>: Nessun rischio corruzione storico
5. <strong>UX Chiara</strong>: "Frozen โ Duplica โ Modifica"</p><p>---</p><p><h2>๐จ UX Flow Completo</h2></p><p>โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ Lista Profili โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ โข Juki Standard v1 โ โ [๐๏ธ Visualizza] [๐ Duplica] [๐๏ธ] โ โ โ โ โข Juki Standard v2 โ โ [๐๏ธ Visualizza] [๐ Duplica] [๐๏ธ] โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ</p><p>Click "Visualizza" โ Modal con: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ Juki Standard v1 โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ Info | Mapping | File CSV โ โ โ โ [Chiudi] [๐ Duplica Profilo] โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
---
๐ฎ Evoluzioni Future (opzionali)
Se in futuro serve piรน flessibilitร :
Opzione A: Aggiungi flag
is_locked
`sql
ALTER TABLE import_profiles ADD COLUMN is_locked BOOLEAN DEFAULT 0;-- Blocca profilo dopo primo import
UPDATE import_profiles SET is_locked = 1 WHERE id = X;
`Opzione B: Conta import associati
`php
public function canBeDeleted(): bool {
return $this->imports()->count() === 0;
}
`Opzione C: Soft Delete con restore
`php
use SoftDeletes;// Elimina logicamente, ripristinabile
``---
๐ Pattern Riutilizzabile
Questo pattern "Immutabile + Duplica" funziona per:
Quando serve integritร storica, usa immutabilitร !
---
Documento creato: 17 Ottobre 2025 Strategia: Immutabilitร senza versioning
Analisi Codice
Blocco 1
Scenario problematico con profili modificabili:
1. Profilo "Juki Standard" โ Import 10.000 lavorazioni (Gen 2025)
Mapping: Data, Operazione, Pezzi
2. Admin modifica mapping
Mapping: Data, Operazione, Pezzi, Operatore, Durata
3. Profilo "Juki Standard" โ Import 5.000 lavorazioni (Feb 2025)
โ PROBLEMA:
- Lavorazioni Gen: senza Operatore/Durata
- Lavorazioni Feb: con Operatore/Durata
- Stessa struttura โ Dati inconsistenti!
Blocco 2
โ
Profilo "Juki Standard v1" โ Import Gen (frozen)
โ
Duplica โ "Juki Standard v1 (copia)" โ Modifica mapping
โ
Rinomina โ "Juki Standard v2"
โ
Import Feb โ Usa v2
Risultato:
โ
Ogni import ha il suo profilo specifico
โ
Integritร dati garantita
โ
Tracciabilitร completa
Blocco 3 php
Route::post('/{importProfile}/duplicate', [ImportProfilesController::class, 'duplicate'])
->name('duplicate');
Blocco 4 php
public function duplicate(ImportProfile $importProfile)
{
// Replica profilo
$new = $importProfile->replicate();
// Nome univoco
$baseName = $importProfile->name;
$counter = 2;
$newName = "{$baseName} (copia)";
while (ImportProfile::where('name', $newName)->exists()) {
$newName = "{$baseName} (copia {$counter})";
$counter++;
}
$new->name = $newName;
$new->created_by = auth()->id();
$new->save();
// Duplica file CSV
if ($importProfile->sample_file_path) {
$newPath = 'I40/import-profiles/' . uniqid('profile_') . '.csv';
Storage::disk('public')->copy($importProfile->sample_file_path, $newPath);
$new->sample_file_path = $newPath;
$new->save();
}
return redirect()->with('success', "Profilo duplicato: '{$new->name}'");
}
Blocco 5 html
<button onclick="duplicateProfile(id, name)">
<i class="bi bi-files"></i> Duplica
</button>
Blocco 6 html
<div class="modal-footer">
<button onclick="duplicateFromModal()">Duplica Profilo</button>
</div>
Blocco 7
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Lista Profili โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โข Juki Standard v1 โ
โ [๐๏ธ Visualizza] [๐ Duplica] [๐๏ธ] โ
โ โ
โ โข Juki Standard v2 โ
โ [๐๏ธ Visualizza] [๐ Duplica] [๐๏ธ] โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Click "Visualizza" โ Modal con:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Juki Standard v1 โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Info | Mapping | File CSV โ
โ โ
โ [Chiudi] [๐ Duplica Profilo] โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Blocco 8 sql
ALTER TABLE import_profiles ADD COLUMN is_locked BOOLEAN DEFAULT 0;
-- Blocca profilo dopo primo import
UPDATE import_profiles SET is_locked = 1 WHERE id = X;
Blocco 9 php
public function canBeDeleted(): bool {
return $this->imports()->count() === 0;
}
Blocco 10 php
use SoftDeletes;
// Elimina logicamente, ripristinabile