Notizie
Vue 3 Composition API CRM-1

Vue 3 e Composition API per una App CRM: Vantaggi e Esempi

Stai sviluppando un’app CRM complessa con Vue 3 e ti ritrovi con componenti sempre più grandi, difficile da leggere e con logiche di business sparse tra data, methods e computed? La gestione dello stato reattivo per celle, filtri complessi o integrazioni in tempo reale può trasformare il tuo codice in un groviglio difficile da mantenere, soprattutto quando il progetto cresce e il team si espande. La Composition API di Vue 3 nasce proprio per risolvere questa sfida, permettendoti di organizzare la logica per funzionalità e non per opzioni del componente. Per un’app enterprise come un CRM, dove ogni modulo (gestione contatti, pipeline vendite, reporting) ha la sua logica complessa, questo approccio non è solo una preferenza sintattica: è un fattore critico per scalabilità, riutilizzo del codice e manutenibilità a lungo termine. In questa guida pratica, vedremo come la Composition API, con i suoi ref, reactive e composables, ti aiuta a costruire moduli CRM più puliti, testabili e facili da estendere. Ti mostreremo esempi concreti dal mondo reale (come un componente di filtro avanzato o un hook per sincronizzazione dati) e, come bonus, potrai scaricare subito la nostra checklist gratuita per valutare se e come migrare i tuoi componenti esistenti alla Composition API senza stress.

Introduzione: Perché il Frontend di una App CRM Moderna Richiede un Cambio di Paradigma

Le applicazioni CRM moderne non sono più semplici liste di contatti. Oggi un CRM gestisce flussi di lavoro complessi, dashboard in tempo reale, integrazioni con decine di servizi esterni e moduli configurabili dall’utente. Quando la complessità cresce, il vecchio paradigma dell’Options API di Vue 2 inizia a mostrare i suoi limiti. La logica di business, prima suddivisa in blocchi opachi (data, methods, computed), si frantuma in tutto il file del componente, rendendo la manutenzione un’impresa. Il riutilizzo del codice diventa un groviglio di mixin poco trasparenti. Per team che costruiscono o modernizzano un CRM enterprise, serve un approccio che metta la logica di business al centro, non la struttura del framework. Vue 3, con la sua Composition API e la sintassi <script setup>, offre proprio questo: la possibilità di organizzare il codice per funzionalità (logica di autenticazione, gestione stato form, fetch dati) invece che per opzioni. Il risultato è codice più leggibile, componenti più piccoli e riutilizzabili, e una manutenzione significativamente più semplice man mano che il CRM evolve. In questo articolo vediamo come sfruttare la Composition API per costruire frontend CRM scalabili, con esempi pratici di gestione stati complessi e logiche di form.

Ti sta piacendo questo articolo?

Iscriviti per ricevere aggiornamenti esclusivi!

Le sfide specifiche delle applicazioni CRM: stato complesso, logica di business intensiva e manutenzione nel tempo

Le applicazioni CRM presentano sfide uniche che mettono a dura prova le architetture frontend tradizionali.

Stato complesso e reattività fine-grained
Un CRM gestisce decine di entità interconnesse: contatti, aziende,Opportunità di vendita, attività, note. Lo stato non è mai banale. Ad esempio, modificare il telefono di un contatto potrebbe dover aggiornare automaticamente le statistiche dell’azienda collegata. Con l’Options API, la logica di sincronizzazione viene frammentata tra data, watch e methods, rendendo difficile tracciare il flusso completo.

Logica di business intensiva e riutilizzo
Le regole di business sono il cuore del CRM: calcolo del punteggio lead (lead scoring), validazione di campi in base al tipo di cliente, automazioni basate su trigger. Queste logiche sono spesso necessarie in più componenti (una dashboard, una modale di dettaglio, un report). Mixins o copy-paste creano dipendenze invisibili e duplicazione.

Manutenzione nel tempo e scalabilità del team
Un CRM evolve per anni. Nuovi campi, flussi, integrazioni si aggiungono senza sosta. Componenti che iniziano semplici diventano mostruosi file da 500+ linee nell’Options API. Per un nuovo sviluppatore, comprendere una funzionalità che coinvolge 4 differenti blocchi data e 3 methods sparsi è un’impresa. La manutenzione diventa rischiosa e lenta.

Vue 3 e Composition API: una soluzione progettata per la scalabilità

Per applicazioni CRM in crescita, la scalabilità del codice è cruciale. Il Composition API di Vue 3 affronta direttamente questa sfida.

Rispetto all’Options API, che può generare “esplosione di opzioni” nei componenti complessi, il Composition API permette di raggruppare la logica per funzionalità. Puoi tenere insieme, in un’unica funzione (composable), tutto il codice relativo a una specifica feature del CRM, come la gestione di un contatto o il flusso di vendita.

Questo significa componenti più leggibili, manutenzione semplificata e la possibilità di riutilizzare logiche complesse (es. validazione form, calcolo metriche) in più parti dell’applicazione senza duplicazione.

Il risultato è una codebase più organizzata e pronta a evolversi con le crescenti esigenze del business.

Vue 3 Composition API: Fondamenti Teorici e Vantaggi per l’Architettura CRM

Vue 3 Composition API: Fondamenti Teorici e Vantaggi per l’Architettura CRM

La Composition API, introdotta in Vue 3, rappresenta un cambio di paradigma nella scrittura di componenti. Abbandona la struttura basata su opzioni (data, methods, computed) per adottare un approccio funzionale, dove la logica è organizzata per funzionalità anziché per tipo di codice. Questo è possibile grazie a funzioni come ref(), reactive() e computed(), che permettono di gestire lo stato reattivo in modo esplicito.

Per un’applicazione CRM, caratterizzata da elevata complessità logica e da numerosi stati interconnessi (contatti, aziende, deal, attività), i vantaggi della Composition API sono sostanziali:

  • Organizzazione del codice per dominio: Invece di avere tutti i dati nel blocco data() e i metodi sparsi, puoi raggruppare il codice relativo a una specifica funzionalità. Ad esempio, la gestione dei contatti (creazione, modifica, storico) può vivere in un unico file Composabile (useContactManager.js), rendendo il componente principale più pulito e navigabile.
  • Riutilizzo della logica (Composables): Pattern come validazione form, recupero dati da API, gestione filtri complessi possono essere estratti in funzioni riutilizzabili. In un CRM, la stessa logica di validazione email o di formattazione telefono serve in più sezioni; con i Composables eviti duplicazione e garantisci coerenza.
  • TypeScript-first: La Composition API è progettata per TypeScript. La tipizzazione esplicita degli stati reattivi (ref<Contact>) e dei valori restituiti dai Composables riduce errori runtime e migliora l’autocompletamento IDE, cruciale quando si maneggiano oggetti complessi come un’Opportunità di vendita con decine di proprietà.
  • Scalabilità e manutenibilità: I componenti CRM tendono a diventare molto grandi. Con l’Options API, il codice relativo a una singola funzionalità è frammentato tra data, methods, computed, watch. La Composition API mantiene tutto ciò che riguarda una feature in un unico blocco, semplificando lettura, debug e refactoring.
  • Integrazione con tool di stato globale: La Composition API si integra perfettamente con Pinia (store ufficiale Vue 3). Puoi creare store in stile Composition, condividendo logica tra components e store, ideale per stato dell’app CRM condiviso (es. lista deal filtrabile).

Esempio concreto in un CRM: Supponi di dover gestire la pipeline dei deal. Un Composabile useDealPipeline() potrebbe esporre:

  • Stato reattivo per la lista deal (deals),
  • Funzioni per cambiare stage (moveDealToStage),
  • Valori calcolati come la probabilità di chiusura media (averageWinRate),
  • Watcher che notificano il team quando un deal cambia stage.

Tutto questo, racchiuso in un modulo autonomo, testabile e riutilizzabile in diverse viste del CRM (dashboard, vista kanban, report).

In sintesi, la Composition API fornisce gli strumenti per costruire architetture CRM modulari, dove ogni blocco di logica è isolato e composabile. Questo si traduce in codice più pulito, minore technical debt e team più produttivi nella gestione di progetti frontend complessi.

Dal ‘Options API’ alla ‘Composition API’: un cambio di mentalità per organizzare la logica

Il passaggio da Options API a Composition API rappresenta un cambio di paradigma nell’organizzazione del codice. Con l’Options API, la logica di un componente viene raggruppata per opzioni (data, methods, computed), un approccio lineare ma che può generare frammentazione in componenti complessi come quelli di un CRM. La Composition API, invece, permette di raggruppare il codice in base alla funzionalità logica. Ad esempio, tutta la gestione dei clienti—ricerca, filtri, operazioni—può essere incapsulata in un unico composable (es. useCustomerManager). Questo migliora drasticamente leggibilità, manutenzione e riutilizzo, specialmente in progetti enterprise dove la scalabilità del codice è critica.

I pilastri della Composition API: `setup()`, `ref`, `reactive`, `computed` e `watch`

Nel Composition API, il cuore è la funzione setup(), che prepara lo stato prima del rendering. I pilastri operativi sono:

  • ref: crea una reattività per valori primitivi (es. const ticketCount = ref(0)). Si accede al valore tramite .value.
  • reactive: rende reattivo un oggetto intero (es. reactive({ cliente: '', status: 'pending' })). Le modifiche alle proprietà sono tracciate automaticamente.
  • computed: definisce proprietà calcolate in base allo stato reattivo (es. const isAttivo = computed(() => cliente.status === 'active')). Si aggiorna automaticamente.
  • watch: osserva cambiamenti in uno stato reattivo per eseguire effetti collaterali (es. inviare un alert quando lo status di un cliente cambia).

In una app CRM, questi strumenti permettono di gestire complessità logiche (come flussi di follow-up o calcoli su team) in modo modulare e manutenibile.

Composability e riutilizzo: il cuore della manutenibilità in progetti di grandi dimensioni

Composability e riutilizzo: il cuore della manutenibilità in progetti di grandi dimensioni

Nei CRM complessi, la logica di business (come la validazione di un contatto, il calcolo del punteggio di un lead o la sincronizzazione con un calendario) è spesso distribuita in più componenti. L’Options API costringe a duplicare questa logica o a usare mixin, generando dipendenze opache e codice frammentato.

Con la Composition API, ogni logica distintiva (es. “ricerca avanzata”, “gestione note”, “audit trail”) viene incapsulata in una funzione useX() (il composable). Questo modulo puro, testabile e riutilizzabile, può essere importato in qualsiasi componente del CRM, dai form alla dashboard.

Esempio pratico per un CRM: Un composable useContactValidation() conterrebbe tutte le regole per email, P.IVA e campi obbligatori. Questo stesso file viene utilizzato dal form di creazione, da quello di modifica e dall’importazione bulk, garantendo coerenza e riducendo il codice da mantenere.

  • Vantaggio: Modifiche centralizzate. Aggiorni la regola in un solo file e si riflette ovunque.
  • Risultato: Codebase più pulita, debuggabile e scalabile.

Questa architettura modulare è fondamentale per progetti enterprise come un CRM, dove l’evoluzione delle funzionalità è continua.

Implementazione Pratica: Costruire Feature CRM Tipiche con la Composition API

Implementazione Pratica: Costruire Feature CRM Tipiche con la Composition API

L’adozione della Composition API in un’app CRM non è un semplice cambio di sintassi, ma un miglioramento strutturale che impatta direttamente sulla manutenibilità e scalabilità delle funzionalità core. Invece di avere metodi e dati sparsi tra data(), methods e computed, la logica di business di ciascuna feature viene incapsulata in funzioni riutilizzabili (composables). Questo approccio è particolarmente vantaggioso per un CRM, dove componenti come liste contatti, form complessi e dashboard condividono spesso logiche di stato, validazione e fetch dati.

1. Gestione dello Stato di un Contatto: il Composable useContact

Immagina di dover gestire la creazione e modifica di un contatto in più sezioni dell’interfaccia: un form modale, una vista dettagliata e una lista card. Con l’Options API, la logica di validazione e salvataggio sarebbe duplicata o astratta in mixin complessi. Con la Composition API, crei un singolo composable che racchiude tutto lo stato e il comportamento.

// composables/useContact.js
import { ref, reactive, computed } from 'vue'

export function useContact(initialData = null) {
  const contact = reactive({
    id: null,
    name: '',
    email: '',
    company: '',
    status: 'lead' // lead, customer, inactive
  })

  const errors = reactive({})

  const isValid = computed(() => {
    return contact.name && contact.email && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(contact.email)
  })

  const setContactData = (data) => {
    Object.assign(contact, data)
  }

  const validate = () => {
    errors.name = !contact.name ? 'Il nome è obbligatorio' : ''
    errors.email = !contact.email ? 'L\'email è obbligatoria' : ''
    errors.email = errors.email || (!isValid.value ? 'Email non valida' : '')
    return Object.keys(errors).every(key => !errors[key])
  }

  const saveContact = async (apiService) => {
    if (!validate()) return false
    try {
      const response = contact.id
        ? await apiService.update(contact.id, contact)
        : await apiService.create(contact)
      return response
    } catch (error) {
      console.error('Salvataggio fallito:', error)
      return false
    }
  }

  // Inizializza se ci sono dati passati
  if (initialData) setContactData(initialData)

  return {
    contact,
    errors,
    isValid,
    setContactData,
    validate,
    saveContact
  }
}

Come usarlo in un componente:

<script setup>
import { useContact } from '@/composables/useContact'
import { useCRMAPI } from '@/composables/useCRMAPI'

const { contact, errors, isValid, saveContact } = useContact()
const { createContact, updateContact } = useCRMAPI()

const onSubmit = async () => {
  const success = await saveContact({ create: createContact, update: updateContact })
  if (success) alert('Contatto salvato!')
}
</script>

Vantaggi pratici per il CRM: La logica di validazione e persistenza è definita una volta e disponibile in ogni componente che usa useContact. Se modifichi la regola di validazione dell’email, il cambiamento si propaga automaticamente a tutto il CRM.

2. Tracciamento Attività e Interazioni: il Composable useActivityLog

Un CRM traccia ogni interazione (email, chiamata, meeting) con un contatto. Questo flusso è complesso: stato di caricamento, recupero cronologia, aggiunta nuova attività, gestione errori. Incapsuliamo questa complessità.

// composables/useActivityLog.js
import { ref, onMounted } from 'vue'

export function useActivityLog(contactId) {
  const activities = ref([])
  const loading = ref(false)
  const error = ref(null)

  const fetchActivities = async (apiService) => {
    loading.value = true
    error.value = null
    try {
      activities.value = await apiService.getActivities(contactId)
    } catch (err) {
      error.value = 'Impossibile caricare le attività'
    } finally {
      loading.value = false
    }
  }

  const addActivity = async (activityData, apiService) => {
    try {
      const newActivity = await apiService.createActivity(contactId, activityData)
      activities.value.unshift(newActivity) // Aggiunge all'inizio della lista
      return newActivity
    } catch (err) {
      throw err // Gestito dal componente chiamante
    }
  }

  onMounted(() => {
    // Assumiamo che apiService sia iniettato o importato globalmente
    // In un'app reale, potresti iniettarlo via provide/inject
    fetchActivities(/* apiService */)
  })

  return {
    activities,
    loading,
    error,
    fetchActivities,
    addActivity
  }
}

Integrazione in un componente Timeline:

<template>
  <div v-if="loading">Caricamento...</div>
  <div v-else-if="error">{{ error }}</div>
  <ul v-else>
    <li v-for="act in activities" :key="act.id">
      {{ act.type }}: {{ act.description }} ({{ formatDate(act.date) }})
    </li>
  </ul>
</template>

<script setup>
import { useActivityLog } from '@/composables/useActivityLog'
defineProps({ contactId: String })
const { activities, loading, error } = useActivityLog(props.contactId)
</script>

3. Dashboard con Dati Aggregati: Composable useDashboardStats

La dashboard del CRM mostra metriche come “Contatti totali”, “Attività this week”, “Pipeline value”. Queste metriche provengono da endpoint diversi e hanno stati di caricamento indipendenti. Un composable coordina il tutto.

// composables/useDashboardStats.js
import { ref, onMounted } from 'vue'

export function useDashboardStats() {
  const stats = ref({
    totalContacts: 0,
    newContactsThisWeek: 0,
    pipelineValue: 0
  })
  const loading = ref(true)

  const fetchAllStats = async (apiService) => {
    try {
      const [contacts, pipeline] = await Promise.all([
        apiService.getContactsCount(),
        apiService.getPipelineValue()
      ])
      stats.value = {
        totalContacts: contacts.total,
        newContactsThisWeek: contacts.newThisWeek,
        pipelineValue: pipeline.value
      }
    } catch (e) {
      console.error('Errore stats')
    } finally {
      loading.value = false
    }
  }

  onMounted(() => {
    fetchAllStats(/* apiService */)
  })

  return { stats, loading }
}

Uso nel componente Dashboard:

<template>
  <div v-if="loading">Caricamento metriche...</div>
  <div v-else class="stats-grid">
    <div>Contatti Totali: {{ stats.totalContacts }}</div>
    <div>Nuovi questa settimana: {{ stats.newContactsThisWeek }}</div>
    <div>Pipeline: €{{ stats.pipelineValue }}</div>
  </div>
</template>
<script setup>
import { useDashboardStats } from '@/composables/useDashboardStats'
const { stats, loading } = useDashboardStats()
</script>

4. Tabella Riassuntiva: Opzioni API vs Composition API in un CRM

Feature CRM Approccio Options API Approccio Composition API Vantaggio pratico
Form Contatto Logica di validazione in methods, stato in data. Duplicazione se usato in modale e pagina. Composable useContact unico. Importato dove serve. Modifica regola validazione? Cambia in un solo file.
Lista Contatti con Filtri data per lista e filtri, computed per lista filtrata, methods per fetch. Codice frammentato. Composable useContactList(filters) che gestisce tutto lo stato e il fetching. Logica di filtro e fetch è isolata e testabile.
Timeline Attività Stato activities, loading, error nel componente. Se serve in altro widget, copia-incolla. Composable useActivityLog(contactId). Importabile in timeline, scheda contatto, report. Riutilizzo immediato senza duplicazione.

Checklist Operativa per lo Sviluppatore CRM

  • Identifica le unità logiche: Per ogni feature (contatto, attività, deal), mappa stato, azioni, derived state.
  • Crea un composable per unità: Usa reactive per oggetti complessi (contatto), ref per valori primitivi (loading flag).
  • Esponi solo ciò che serve: Il composable deve ritornare un oggetto con proprietà specifiche (es. { contact, errors, saveContact }). Non esporre lo stato interno non necessario.
  • Gestisci le dipendenze esterne: Passa i servizi API (es. apiService.createContact) come argomenti al composable o iniettali con provide/inject per evitare dipendenze rigide.
  • Testa il composable isolatamente: Poiché sono funzioni pure, puoi testare la logica di business senza dover montare un componente Vue.

Implementare feature CRM con la Composition API significa costruire mattoni di logica riutilizzabile. Iniziare con i composable per le entità principali (contatto, azienda, attività) crea una base solida. I componenti UI diventano poi “contenitori sottili” che collegano il template a questi mattoni. Il risultato è un codice più leggibile, facile da testare e da estendere quando il CRM cresce con nuove funzionalità.

Caso Studio 1: Gestione Avanzata dello Stato Globalizzato (Contatti, Aziende, Deal)

Nei CRM moderni, gestire lo stato condiviso tra diverse entità come contatti, aziende e deal può rapidamente diventare complesso usando solo l’Options API. La logica di caricamento, filtraggio e sincronizzazione risulta frammentata tra data, methods e computed, rendendo difficile il riutilizzo.

Con la Composition API, invece, puoi creare un composable dedicato allo stato CRM. Ad esempio, un file useCRMStore.js può incapsolare tutta la logica per le tre entità in un unico luogo logico, usando reactive per lo stato e funzioni per le azioni. Questo approccio raggruppa per funzionalità (es. “gestione contatti”) invece che per tipo di opzione.

Esempio Pratico: Composable per lo Stato CRM

Immagina di dover sincronizzare i contatti con le aziende di appartenenza.Con la Composition API, puoi scrivere:

// useCRM.js
import { reactive, computed } from 'vue'

export function useCRM() {
  const state = reactive({
    contacts: [],
    companies: [],
    deals: []
  })

  const contactsByCompany = computed(() => {
    return state.companies.map(company => ({
      ...company,
      contacts: state.contacts.filter(c => c.companyId === company.id)
    }))
  })

  function addContact(contact) {
    state.contacts.push(contact)
  }
  // ... altre funzioni per aziende e deal

  return { state, contactsByCompany, addContact }
}

Ogni componente Vue che importa useCRM() ha accesso immediato a uno stato coerente e reattivo, senza duplicazione di logica. Questo è cruciale per interfacce complesse come dashboard o viste ibride che mescolano dati di entità diverse.

Punto chiave:Usa un composable per domain logic (es. “CRM”) e non per singoli componenti. Estrai ulteriormente se la logica cresce (es. useContacts(), useDeals())

Il risultato è un codice più leggibile, testabile e facile da estendere. Se domani aggiungi una nuova entità “Task”, basta estendere il composable principale senza toccare i componenti esistenti che ne fanno uso.

Caso Studio 2: Dashboard con Widget Dinamici e Filtri Complessi

Caso Studio 2: Dashboard con Widget Dinamici e Filtri Complessi

Immagina una dashboard CRM dove un responsabile vendite deve visualizzare, in tempo reale, metriche diverse (opportunità per fase, ticket aperti, forecast) che cambiano in base a filtri complessi: data, team di vendita, tipo cliente. Con l’Options API, la logica per ogni widget (stato, recupero dati, filtri) si frammenta tra data, methods, computed e watch. Aggiungere un nuovo filtro richiede di modificare più sezioni del componente, aumentando il rischio di errori e rendendo il codice difficile da leggere.

Con la Composition API e <script setup>, puoi raggruppare tutta la logica di un widget specifico in un unico composable. Ad esempio, crei un useSalesPipeline() che gestisce lo stato dei filtri, il calcolo delle metriche e l’interazione con l’API. La dashboard principale importa e utilizza diversi composable (usePipelineWidget, useSupportTickets), ognuno autosufficiente. Ogni volta che un filtro globale (es. seleziona team) cambia, basta un watch centrale che passi il nuovo valore a tutti i composable, i quali aggiornano autonomamente i propri stati e computed.

Esempio concreto: Un widget “Opportunità per Fase” ora contiene, nello stesso blocco di codice, lo stato (ref), la logica di filtraggio per fase/team, il computed per l’aggregazione e il watch per reagire ai cambiamenti del filtro globale. Questo rende il componente principale molto più snello e ogni widget facilmente testabile e riutilizzabile in altre pagine.

  • Logica raggruppata per feature, non per tipo di opzione.
  • Riusabilità immediata: lo stesso composable useSalesPipeline alimenta sia la dashboard che una vista dettagliata.
  • Manutenzione semplificata: modifiche a un widget avvengono in un unico file, senza cercare in methods e computed sparsi.

Il risultato è una dashboard più performante (reazioni ottimizzate), più facile da scalare (aggiungere widget è questione di creare un nuovo composable) e comprensibile anche per nuovi sviluppatori che possono capire la logica di un widget senza saltare tra decine di opzioni.

Caso Studio 3: Form Dinamici e Wizard Complessi per Inserimento Dati

Caso Studio 3: Form Dinamici e Wizard Complessi per Inserimento Dati

Nei CRM, i form non sono mai statici. Un processo di onboarding cliente, la raccolta di una richiesta di supporto o la configurazione di un prodotto richiedono spesso wizard multi-schermata con campi che appaiono o scompaiono in base alle selezioni precedenti. Con l’Options API, gestire questa logica condizionale portava a metodi e computed properties dispersi in diverse sezioni del componente, rendendo difficile seguire il flusso.

La Composition API risolve questo problema grazie al raggruppamento logico per funzionalità. È possibile creare un unico composable, ad esempio useDynamicFormWizard, che incapsula tutto lo stato del wizard: lo step corrente, i dati parziali raccolti, le regole di validazione per ciascuno step e le condizioni per abilitare i campi successivi.

Esempio pratico: in un wizard di “Nuova Opportunità Commerciale”, il passo 1 chiede se il cliente è un’azienda o un privato. Questa scelta (tipoCliente) determina dinamicamente i campi visibili nel passo 2 (P.IVA per azienda, Codice Fiscale per privato). Con un composable, puoi definire una computed property come campiStep2 che restituisce l’array di campi corretto basandosi sullo stato reattivo tipoCliente. La logica di “se… allora…” rimane tutta in unico luogo leggibile.

Vantaggi operativi:

  • Riusabilità: lo stesso composable useDynamicFormWizard può essere utilizzato per form di onboarding tecnico, di assessment o di richiesta preventivo, passando semplicemente una configurazione diversa.
  • Maintenibilità: se la logica di validazione per un campo complesso cambia, modifichi un’unica funzione nel composable, senza cercare tra methods e watch sparsi.
  • Testabilità: è possibile testare la logica del wizard (transizioni tra step, validazione) in isolation, senza dover montare il componente Vue completo.
  • Gestione dello stato transitorio: il composable può gestire il salvataggio temporaneo dei dati in localStorage se l’utente abbandona il wizard a metà, una funzionalità critica per l’esperienza utente.

Per progetti CRM con molti moduli data-driven, astrarre la logica dei form in composables dedicati non è un optional, ma una pratica che riduce drasticamente il debito tecnico e accelera lo sviluppo di nuove interfacce.

Confronto Diretto: Stesso Problema CRM, Due Approcci (Options vs Composition API)

Esempio Pratico: Gestione Lista Contatti in un CRM

Immagina un componente che gestisce una lista contatti con funzionalità di ricerca, selezione multipla e calcolo di statistiche. Con l’Options API, il codice viene frammentato in sezioni distinte (data, methods, computed, watch), anche se le funzionalità sono logicamente legate. Quando il componente cresce, diventa difficile seguire il flusso: ad esempio, la logica di filtraggio (che dipende dal termine di ricerca) e quella di selezione (che gestisce gli ID dei contatti selezionati) sono separate.

Con la Composition API, invece, raggruppi la logica per dominio funzionale. Puoi creare un composable dedicato (es. useContactList) che incapsula tutto lo stato reattivo (searchTerm, selectedIds), le funzioni di filtraggio/selezione, e le proprietà calcolate (es. filteredContacts). Il componente principale risulta molto più pulito e focused sul rendering.

Confronto Diretto: Differenze Chiave

  • Organizzazione del codice: Options API → separazione per opzioni (spesso forbice tra logica correlata). Composition API → raggruppamento per logica di business.
    Nel CRM, la gestione di un’offerta può coinvolgere stato, calcolo importi, e validazione: col Composition API stanno insieme.
  • Riutilizzo: Options API → mixin (con conflitti di nomi e dipendenze opache). Composition API → composables (funzioni pure, stato isolato, import/esportazione esplicita).
    Esempio: la logica di “formattazione valuta” o “validazione email” si scrive una volta e si usa in ogni modulo del CRM.
  • TypeScript: Options API → inferenza limitata, necessita di annotazioni manuali. Composition API → tipizzazione nativa e precisa grazie a <script setup>.
    Critico in un CRM con modelli dati complessi (Clienti, Contratti, Prodotti).
  • Scalabilità: Options API → “option explosion” nei componenti grandi (centinaia di righe frammentate). Composition API → estrazione facile in composables per mantenere componenti piccoli e focalizzati.

In sintesi, per un’app CRM con business logic articolata, la Composition API offre manutenibilità superiore. L’Options API rimane valido per componenti isolati e semplici, ma quando le funzionalità si intrecciano (come spesso accade in un sistema di gestione clienti), il raggruppamento per logica del Composition API riduce il debito tecnico e accelera lo sviluppo di nuove feature.

Esempio Pratico: ‘Lista Contatti con Ricerca e Ordinamento’ in Options API

Esempio Pratico: ‘Lista Contatti con Ricerca e Ordinamento’ in Options API

Immagina un componente <ContactList> per un CRM. Utilizzando l’Options API, la logica viene suddivisa rigidamente:

  • data(): contiene l’array contacts originale, il termine di searchQuery, e i campi per l’ordinamento (sortField, sortDirection).
  • computed: definisce filteredContacts (filtraggio per nome/email) e sortedContacts (ordinamento in base a sortField). Ogni proprietà calcolata dipende da più fonti reattive.
  • methods: ospita setSort(field) che muta sortField e sortDirection.

Problema pratico: Se la logica di filtro o ordinamento diventa complessa (es. ricerche per più campi, ordinamento per più livelli), le proprietà computed si espandono. Aggiungere una nuova funzionalità, come il salvataggio di un layout di ordinamento preferito, costringe a spargere codice tra data, methods e magari watch, rendendo il componente difficile da leggere e testare.

Checklist operativa Options API:

  • Tutte le variabili di stato nel data().
  • Ogni derived state (filtri, ordinamenti) come computed.
  • Le azioni utente (click su intestazione tabella) nei methods.
  • Attenzione: la logica per una singola feature (es. “ordinamento avanzato”) è frammentata.

La stessa funzionalità riscritta in Composition API: analisi del codice, leggibilità e testabilità

La stessa funzionalità riscritta in Composition API: analisi del codice, leggibilità e testabilità

Prendiamo un modulo CRM comune: la gestione e il filtraggio dei contatti. Con l’Options API, la logica per caricare i dati, filtrare per stato (“attivo”, “inattivo”) e gestire gli errori è distribuita in blocchi separati (data, methods, computed, watch). Per comprendere il flusso completo, si deve scorrere avanti e indietro nel file.

Riscrivendo la stessa funzionalità con la Composition API, tutta la logica concernente lo stato dei contatti viene raggruppata in un unico blocco coerente all’interno di una funzione setup() o, meglio ancora, in un composable riutilizzabile (es: useContactFilter()). Questo non solo migliora la leggibilità immediata, ma ha un impatto diretto sulla testabilità.

Ogni funzione pura estratta in un composable (getActiveContacts(), validateEmail()) può essere testata in isolamento, senza dover istanziare un componente Vue. La separazione chiara tra logica di business e template rende i test unitari più semplici, robusti e focalizzati.

  • Esempio pratico: In un CRM, la logica per “cercare contatti per nome e filtrare per regione” può risiedere in un unico composable useContactSearch(). Il componente UI diventa un semplice “consumer” di questa logica, dichiarativo e sottile.

Il risultato è un codice più manutenibile, dove l’aggiunta di un nuovo filtro o la modifica di una regola di validazione avviene in un luogo logico e prevedibile, senza intaccare la struttura del componente.

Best Practices e Pattern Avanzati per Applicazioni CRM Enterprise

Best Practices e Pattern Avanzati per Applicazioni CRM Enterprise

Le applicazioni CRM a livello enterprise gestiscono flussi complessi di dati clienti, automazioni di vendita e integrazioni con sistemi terzi. La Composition API di Vue 3 non è solo una sintassi alternativa, ma un paradigma che abilita pattern architetturali scalabili per questi contesti critici. Ecco le best practice consolidate.

1. Composable per Domini Logici, non per Tipi di Dato

In un CRM, evita di raggruppare i composables per tipo tecnico (es. useApi, useStore). Strutturali invece per dominio funzionale: useContactManagement, useDealPipeline, useActivityTracking. Ogni composable incapsula tutta la logica, lo stato reattivo e le dipendenze (API, store) per quella specifica funzionalità aziendale.

// Esempio: /src/features/deals/composables/useDealPipeline.js
import { ref, computed } from 'vue'
import { dealApi } from '@/services/dealApi'
import { useUser } from '../users/useUser'

export function useDealPipeline(dealId) {
  const { currentUser } = useUser()
  const deal = ref(null)
  const stages = ref([])
  const isLoading = ref(false)

  const isEditable = computed(() => 
    currentUser.value?.permissions?.canEditDeals
  )

  async function loadDeal() {
    isLoading.value = true
    deal.value = await dealApi.fetch(dealId)
    stages.value = await dealApi.getStages()
    isLoading.value = false
  }

  async function moveDeal(stageId) {
    await dealApi.updateStage(deal.value.id, stageId)
    await loadDeal() // Refresh coerente
  }

  return { deal, stages, isLoading, loadDeal, moveDeal, isEditable }
}

Questo pattern mantiene la logica di business del “deal pipeline” isolata, testabile e facilmente riutilizzabile in componenti come DealKanban.vue e DealDetails.vue.

2. TypeScript-First Architecture

Per un CRM enterprise, TypeScript non è opzionale. Definisci interfacce rigorose per every domain entity: Contact, Company, Interaction. I composables devono essere generics o fortemente tipizzati.

interface Contact {
  id: string
  name: string
  email: string
  companyId: string | null
  lifecycleStage: 'lead' | 'customer' | 'churned'
  customFields: Record<string, any> // Estensibile
}

// Composable tipizzato
export function useContact(contactId: string) {
  const contact = ref<Contact | null>(null)
  // ... logica
  return { contact }
}

Usa anche tipi per le risposte API e per gli eventi custom emessi. Questo catching degli errori in fase di sviluppo e migliora l’autocomplete in IDE complessi.

3. Stato Globale Stratificato con Pinia + Composable

Non riversare tutto in Pinia. Usa una strategia ibrida:

  • Pinia stores: per stato autenticazione, preferenze utente, configurazione tenant (multi-tenancy).
  • Composables locali: per stato transazionale di form complessi (es. useContactForm con validazione).
  • Composables di caching: per dati condivisi tra route (useContactCache), evitando chiamate API ripetute.

Esempio di composable di caching:

const contactCache = new Map<string, Contact>()

export function useContactCache() {
  function get(id: string): Contact | undefined {
    return contactCache.get(id)
  }
  
  function set(contact: Contact) {
    contactCache.set(contact.id, contact)
  }
  
  return { get, set }
}

4. Gestione Centralizzata degli Errori e Logging Strutturato

Le applicazioni CRM devono tracciare errori in modo auditabile. Crea un composable useErrorHandler che:

  • Cattura errori da API, validazioni, ecc.
  • Logga con contesto (componente, azione, userId).
  • Mostra UI coerente (toast, modale) basata sul tipo errore.
  • Per errori critici, invia a un servizio di monitoring (es. Sentry).
export function useErrorHandler() {
  const error = ref(null)
  
  function handleError(err, context = {}) {
    error.value = { message: err.message, context }
    logger.error('CRM Error', { err, context })
    // Potrebbe triggerare un evento a livello app
  }
  
  return { error, handleError }
}

5. Virtualizzazione e Ottimizzazione Liste Grandi

I CRM visualizzano liste di contatti/opportunità anche con migliaia di record. Combina la Composition API con librerie di virtualizzazione (es. vue-virtual-scroller). Incapsula la logica di virtualizzazione in un composable:

export function useVirtualizedList(items, itemHeight = 50) {
  const scrollContainer = ref(null)
  const visibleRange = ref({ start: 0, end: 0 })
  
  function onScroll() {
    const scrollTop = scrollContainer.value?.scrollTop || 0
    const containerHeight = scrollContainer.value?.clientHeight || 0
    visibleRange.value = calculateVisibleRange(
      scrollTop, 
      containerHeight, 
      itemHeight, 
      items.length
    )
  }
  
  const visibleItems = computed(() => 
    items.slice(visibleRange.value.start, visibleRange.value.end)
  )
  
  return { scrollContainer, visibleItems, onScroll }
}

Considerazioni Finali

Per un CRM enterprise, la Composition API abilita una separazione netta tra UI e logica di business, fondamentale per team distribuiti e per la lunga manutenzione. Investire in composables ben strutturati, tipizzati e testati paga in riduzione del debito tecnico e agilità nell’aggiungere nuove funzionalità (es. integrazione AI per lead scoring) senza rifattorizzazioni massive.

Organizzazione del codice: dove posizionare i composables? (cartella `/composables`, naming conventions)

Organizzazione del codice: dove posizionare i composables?

In un’applicazione complessa come un CRM, una struttura ordinata è fondamentale per la manutenibilità. La convenzione consolidata è creare una cartella /composables alla radice del progetto (o dentro /src).

Ogni file deve contenere una singola responsabilità logica e usare la naming convention con prefisso use (es. useCustomerFilter.js, useDealPipeline.js).

Per progetti molto grandi, suddividi in sottocartelle funzionali: /composables/customers/, /composables/deals/, /composables/auth/. Mantieni always la separazione tra logica di business e utility generiche (/composables/utils/).

  • Regola d’oro: Un composable deve essere auto-contenuto e riutilizzabile in qualsiasi componente.
  • Esempio: /composables/customers/useCustomerForm.js gestisce la logica del form inserimento/modifica cliente.

Gestione degli side-effect (`watch`, `watchEffect`) in un contesto di dati reload frequenti

In un’app CRM con aggiornamenti frequenti dei dati, la gestione degli side-effect con watch e watchEffect richiede particolare attenzione per evitare cali di performance e comportamenti imprevedibili.

watch consente di monitorare sorgenti specifiche, risultando più controllabile quando i reload coinvolgono dati noti (es. aggiornamento di un contatto). Sfrutta opzioni come flush: 'post' per eseguire la callback dopo il rendering del DOM, o immediate: true per un’inizializzazione immediata. In contesti di refresh continuo, applica tecniche di debouncing alla callback per ridurre le esecuzioni.

watchEffect, invece, traccia automaticamente tutte le dipendenze reattive usate nel suo corpo: la sua reattività implicita è potente ma può innescare调用 più del necessario con dati volatile. Valuta se sostituirlo con computed quando il risultato è puramente derivato, oppure limita l’ambito con un watch mirato.

Infine, assicurati di cancellare i watcher attivi nel hook onUnmounted per prevenire memory leak, soprattutto in componenti con ciclo di vita breve.

TypeScript: tipizzazione completa di composables per un’integra |azione solida con il backend

TypeScript: tipizzazione completa di composables per un’integrazione solida con il backend

Abbinare TypeScript ai composables del Composition API trasforma l’integrazione con le API del backend da rischio a vantaggio competitivo. Ogni funzione riutilizzabile (useCustomerAPI, useDealPipeline) viene definita con interfacce TypeScript per richieste, risposte ed errori.

Questo significa che, prima ancora di eseguire il codice, l’IDE segnala mismatch tra i dati inviati e lo schema del CRM, o tra le proprietà attese e quelle effettivamente restituite. La tipizzazione statica diventa una forma di documentazione vivente per il team e un controllo automatico sulla coerenza dei dati.

  • Esempio pratico: Un composable useAuth definisce l’interfaccia LoginPayload (email: string, password: string) e AuthResponse (token: string, user: User). Se inadvertitamente si prova a inviare un campo username al posto di email, TypeScript blocca l’errore in tempo di sviluppo.
  • Vantaggio operativo: La refactoring di logiche complesse (es. sincronizzazione lead) diventa più sicura, poiché i tipi garantiscono che ogni cambiamento nella struttura dati venga propagato in tutti i composables che ne fanno uso.

Il risultato finale è un’applicazione CRM in cui il “contratto” con il backend è verificato automaticamente, riducendo i bug in produzione e accelerando le modifiche.

Migrazione da Legacy Vue 2/Options API a Vue 3 Composition: Una Roadmap per il CRM

Migrazione da Legacy Vue 2/Options API a Vue 3 Composition: Una Roadmap per il CRM

Migrare un’app CRM legacy da Vue 2 Options API a Vue 3 Composition API è un investimento strategico per la manutenibilità a lungo termine. Il processo non richiede una riscrittura completa, ma un refactoring graduale e controllato, ideale per gestire la complessità logica tipica di un CRM (gestione contatti, pipeline,的报告).

Inizia con una valutazione dell’codebase: identifica i componenti con la logica più complessa e quelli che beneficerebbero maggiormente dalla co-localizzazione del codice (es. form di inserimento contatto con validazione, filtri dynamic dashboard). Utilizza la Vue 3 Migration Build per introdurre Vue 3 nel progetto mantenendo temporaneamente la compatibilità con la sintassi Options API. Questo strumento evidenzia i breaking change e permette un upgrade incrementale.

La roadmap pratica segue questi step:

  • Analisi e Priorizzazione: Mappa i componenti per complessità logica. Inizia con quelli più grandi o condivisi.
  • Strumentazione: Aggiorna Vue CLI o Vite, installa la build di migrazione. Configura ESLint con la ruleset per Composition API.
  • Refactoring Componente per Componente: Per ogni componente selezionato, converti la logica in una o più <script setup>. Estrai la logica di business riutilizzabile (es. gestione stato form, chiamate API specifiche per il CRM) in composables (es. useContactForm(), useDealPipeline()).
  • Gestione Transizione: I componenti convertiti possono coesistere con quelli legacy. Non migrare subito le dipendenze globali (Vuex/Pinia) se non pianifichi anche l’upgrade dello store.
  • Test e Validazione: Esegui test di regressione completi (unit e E2E) dopo ogni batch di componenti migrati. Verifica che le interazioni complesse del CRM (es. salvataggio con popolamento automatico campi) funzionino invariabilmente.

Per un CRM, il vero valore emerge quando la logica di dominio specifica (come le regole di assegnazione lead o il calcolo del punteggio) viene incapsulata in composables testabili e riutilizzabili, semplificando futuri aggiornamenti e riducendo il debito tecnico.

Approccio incrementale: coesistenza di Options e Composition API nello stesso progetto

In un progetto Vue 3 esistente, non è necessario riscrivere tutto in Composition API. Vue supporta nativamente la coesistenza di entrambi gli stili nello stesso codebase. Puoi quindi adottare un approccio incrementale e low-risk.

La strategia più comune è:

  • Mantenere i componenti legacy scritti con Options API.
  • Scrivere tutti i nuovi componenti (o quelli con logica complessa da rifattorizzare) utilizzando <script setup> e Composition API.
  • Convertire gradualmente i componenti esistenti, iniziando da quelli più grandi o riutilizzabili.

Per un’app CRM, ad esempio, potresti mantenere i form legacy con Options API e creare nuovi dashboard analitici complessi con Composition API, estraendo la logica di filtraggio e fetching dati in composable riutilizzabili. Questo permette al team di apprendere il nuovo paradigma senza blocchi di sviluppo.

Identificare i ‘moduli’ critici del CRM da migrare per primi (es. gestione anagrafica)

Per una migrazione efficiente a Vue 3 con Composition API, individua i moduli del CRM con il più alto impatto operativo e complessità logica. I candidati ideali per partire sono quelli ad alta interazione utente e riutilizzo di logica, come la gestione anagrafica clienti/fornitori.

Questo modulo tipicamente include form complessi, validazioni in tempo reale, gestione dello stato (selezioni, filtri) e integrazione con altri dati (storico contatti, ordini). Con il Composition API, puoi incapsolare questa logica in composables riutilizzabili (es. useAnagraficaValidation, useRelatedData), migliorando leggibilità e manutenibilità rispetto a un unico componente Options API frammentato.

Prioritizza anche moduli che beneficiano della TypeScript integration nativa del Composition API, garantendo maggiore sicurezza nelle operazioni sui dati sensibili dell’anagrafica.

Conclusioni: La Composition API Come Abilitatore per CRM Complessi e in Evoluzione

Per un CRM, l’evoluzione è costante: nuove funzionalità, integrazioni e cambiamenti nei flussi di lavoro sono la norma. La Composition API si rivela l’abilitatore perfetto per questa complessità dinamica. Attraverso i composables, puoi incapsulare la logica di business specifica del CRM—come il calcolo del valore lifetime di un cliente, la gestione degli stati della pipeline o l’integrazione con servizi di email marketing—in blocchi modulari, riutilizzabili e testabili. Questo significa che quando devi aggiungere una nuova automazione o modificare una regola di assegnazione dei lead, intervieni su un modulo isolato senza rischiare di compromettere il resto dell’applicazione.

La struttura per logica, anziché per opzioni, permette al tuo team di sviluppare e far evolvere funzionalità complesse (come dashboard di reporting o gestione appuntamenti) mantenendo il codice leggibile e facile da navigare, anche in componenti di grandi dimensioni. L’integrazione nativa con TypeScript, infine, fornisce la sicurezza necessaria per gestire schemi dati articolati—dai contatti alle opportunità commerciali—riducendo gli errori in fase di sviluppo.

In sintesi, la Composition API non è solo una scelta tecnica, ma una strategia per gestire la complessità e il cambiamento. Fornisce la flessibilità per costruire un CRM solido oggi e adattarlo rapidamente alle esigenze di domani, garantendo una base di codice che cresce in modo ordinato e sostenibile.

Riepilogo dei benefici tangibili per team e prodotto (riduzione bug, velocità di onboarding)

Nei team che sviluppano app CRM, il Composition API contribuisce a ridurre i bug grazie a una migliore gestione dello stato reattivo e all’integrazione nativa con TypeScript, che cattura errori in fase di sviluppo. L’organizzazione del codice per logica di business (es. “gestione opportunità commerciali”) invece che per opzioni tecniche, rende il progetto più leggibile. Questo accorcia i tempi di onboarding dei nuovi sviluppatori, che possono concentrarsi su una funzionalità specifica senza dover navigare tra blocchi di codice frammentati. I composables riutilizzabili standardizzano operazioni critiche, limitando duplicazioni e inconsistency.

Sguardo al futuro: come il modello compositionale si integra con le nuove funzionalità di Vue 3 ( `