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(&#039;/{importProfile}/duplicate&#039;, [ImportProfilesController::class, &#039;duplicate&#039;])
    -&gt;name(&#039;duplicate&#039;);
</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-&gt;replicate();
    
    // Nome univoco
    $baseName = $importProfile-&gt;name;
    $counter = 2;
    $newName = &quot;{$baseName} (copia)&quot;;
    
    while (ImportProfile::where(&#039;name&#039;, $newName)-&gt;exists()) {
        $newName = &quot;{$baseName} (copia {$counter})&quot;;
        $counter++;
    }
    
    $new-&gt;name = $newName;
    $new-&gt;created_by = auth()-&gt;id();
    $new-&gt;save();
    
    // Duplica file CSV
    if ($importProfile-&gt;sample_file_path) {
        $newPath = &#039;I40/import-profiles/&#039; . uniqid(&#039;profile_&#039;) . &#039;.csv&#039;;
        Storage::disk(&#039;public&#039;)-&gt;copy($importProfile-&gt;sample_file_path, $newPath);
        $new-&gt;sample_file_path = $newPath;
        $new-&gt;save();
    }
    
    return redirect()-&gt;with(&#039;success&#039;, &quot;Profilo duplicato: &#039;{$new-&gt;name}&#039;&quot;);
}
</code>`<code></p><p><h3><strong>3. UI - Pulsante Duplica</strong></h3></p><p><strong>Nella tabella</strong>:
</code>`<code>html
&lt;button onclick=&quot;duplicateProfile(id, name)&quot;&gt;
    &lt;i class=&quot;bi bi-files&quot;&gt;&lt;/i&gt; Duplica
&lt;/button&gt;
</code>`<code></p><p><strong>Nel modal dettaglio</strong>:
</code>`<code>html
&lt;div class=&quot;modal-footer&quot;&gt;
    &lt;button onclick=&quot;duplicateFromModal()&quot;&gt;Duplica Profilo&lt;/button&gt;
&lt;/div&gt;
</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 &quot;Nuovo Profilo&quot;
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 &quot;Duplica&quot; (tabella o modal)
3. Modifica nome duplicato (es. &quot;Juki Standard v2&quot;)
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>: &quot;Frozen โ†’ Duplica โ†’ Modifica&quot;</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 &quot;Visualizza&quot; โ†’ 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:

  • โœ… Template CSV import
  • โœ… Configurazioni macchine
  • โœ… Workflow produzione
  • โœ… Regole business critiche
  • 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