Gestione strategia commerciale e aziende target
Riferimento CMS (non CRM): pagine web dinamiche da SQLite e router page.php sono documentate in app/index.php → Gestione CMS Dinamico (SQLite).
ANAGRAFICA CENTRALE (Single Source of Truth)
PATH anagrafica: crm/anagrafica.php.
PATH dati anagrafica: app/config/crm_anagrafica.json.
I dati legali/istituzionali (Ragione Sociale, Partita IVA, indirizzo, email, sito) sono centralizzati in anagrafica e non vengono duplicati nelle fasi funnel. Lo stato operativo funnel è nel campo stato della stessa anagrafica.
SCHEMA ANAGRAFICA E IMPORT CSV (aggiornato 03/2026)
Campi record: id, ragione_sociale, piva (alias partita_iva_cf), localita, percorrenza_min (INT, nullable, minuti di percorrenza), email_principale, email_inviata, sito_web, fonte, stato (+ legacy indirizzo_completo). Campo telefono rimosso (03/2026): telefono_istituzionale non è più nello schema; usare solo piva. email_inviata: stringa data (YYYY-MM-DD) o null; traccia "Prima email inviata" ai target/lead; API crm_anagrafica.php action update_email_inviata; colonna 📩 nelle tabelle: solo testo (DD/MM/YYYY o "—"); modifica tramite modal Modifica in anagrafica.php; migrazione automatica da boolean legacy. Helper: crm_anagrafica_get_localita($a) restituisce localita o fallback indirizzo_completo. Fonte: "Web" per dati inseriti manualmente, es. "ANCE Brescia.csv" per import da CSV. Mapping CSV→anagrafica: ragione_sociale, piva, localita, email→email_principale, sito_web, fonte. ID CSV: ignorare o usare campo di supporto; preferire auto-increment interno.
sito_web: Salvato senza protocollo (es. www.azienda.it). La funzione crm_anagrafica_strip_sito_web_protocol() rimuove http:// e https:// in add/update/normalize. In visualizzazione il link usa href="https://" + valore.
Colonne tabelle CRM: Anagrafica, Lead, Prospect, Opportunity: ID, Ragione Sociale, P.IVA, Località, Percorrenza (min), Email, 📩 (email_inviata), Sito Web, Fonte, Stato Funnel, Azioni. Target: + P.IVA (sostituisce Telefono), Username Demo, Password Demo, Visite. Colonna Sito Web: link esterno con icona bi-box-arrow-up-right (Bootstrap Icons, caricata da app/includes/header.php). DataTables indici (Agenti AI): Stato Funnel colonna 9 (anagrafica/lead/prospect/opportunity), 12 (target); 📩 colonna 6 (o 6 in target); Sito Web colonna 7; Azioni colonna 10 (o 13 in target). Aggiungere colonne richiede ricalibrazione di columnDefs, order e render per type sort. target_get_all_rows(): array [num, azienda, piva, localita, percorrenza_min, email, sito_web, fonte, username, anagrafica_id]; indici r[9]=anagrafica_id, r[8]=username, r[7]=fonte. pageLength: 10 (lengthMenu [10, 50, 100, 200]).
Export PDF: anagrafica.php utilizza esportazione CLIENT-SIDE (DataTables Buttons pdfHtml5 + pdfMake in browser): formato A3 landscape, font 8pt corpo e 9pt intestazione, exportOptions.columns 'th:not(.no-export)' (include ID–Stato Funnel, esclude solo Azioni; colonne 0–9), modifier: { search: 'none' }. Le altre pagine CRM (lead, prospect, opportunity, target) usano link a script server-side in app/export/ (Dompdf). Nota: app/export/export_crm_anagrafica_pdf.php esiste ma è attualmente non referenziato e silente (anagrafica non lo usa).
Protocollo Ricalibrazione Colonne CRM (Agenti AI): Aggiunta o rimozione di colonne richiede aggiornamento sincronizzato in: (1) HTML thead/tbody di anagrafica, lead, prospect, opportunity, target; (2) DataTables columnDefs, order; (3) Export PDF: per anagrafica intervenire su exportOptions.columns nel file JS del DataTable (crm/anagrafica.php, blocco buttons: [{ extend: 'pdfHtml5', ... }]); per lead, prospect, opportunity, target agire sugli script PHP in app/export/ (export_crm_lead_pdf.php, export_crm_prospect_pdf.php, export_crm_opportunity_pdf.php, export_target_pdf.php); (4) FILTERED_TARGET_ROWS e target_get_all_rows() in target_manager.php; (5) modal payload e attributi data-* sulle righe; (6) crm_anagrafica_manager.php se tocca lo schema; (7) questa documentazione in crm/index.php.
SORGENTE DATI
PATH UI fase 1: crm/target.php.
PATH dati funnel: app/config/target_list.json (schema: anagrafica_id + username).
Le righe funnel usano ID anagrafica come riferimento e mostrano solo dati derivati da anagrafica. In crm/target.php la colonna ID deve mostrare l'ID reale anagrafica (non un contatore di tabella).
STATI FUNNEL ANAGRAFICA
Definizione canonica: crm_funnel_status_options() in app/config/crm_anagrafica_manager.php:
0 - NULL - Non a target,
1 - Target,
2 - Lead,
3 - Prospect,
4 - Opportunity.
Default nuove aziende: 1 - Target. Update stato via API: app/api/crm_anagrafica.php con action update_stato.
Filtro pagine: crm/target.php mostra solo 1 - Target; crm/lead.php solo 2 - Lead; crm/prospect.php solo 3 - Prospect; crm/opportunity.php solo 4 - Opportunity. Lo stato 0 - NULL - Non a target resta visibile solo in crm/anagrafica.php.
UTENTI DEMO
Creazione username: demo_ + slug Ragione Sociale in crm/target.php.
Creazione password: users_db_generate_password() in app/config/users_db.php genera 8 caratteri (a-z0-9).
Persistenza utenti: app/config/users.json, ruolo cliente, cantiere assegnato demo_villa_monza.
Protocollo "Elimina credenziali demo" (Agenti AI): In crm/target.php il tasto "🗑️ Elimina credenziali" chiama target_delete_row($username) via API target_crud.php action delete. Vincolo tassativo: NON elimina mai il record da crm_anagrafica.json. L'azione rimuove SOLO: entry da target_list.json, stato da target_stati.json, utente da users.json. L'azienda resta nel CRM (anagrafica intatta). Dopo l'eliminazione la riga si aggiorna con reload mostrando "➕ Aggiungi" e "—" in Username/Password/Visite. Il tasto Modifica riga è stato rimosso; Prepara Email 📧 resta invariato.
TEMPLATE EMAIL TARGET (Agenti AI, 03/2026)
Il template dell'email generata per i target è in crm/target.php, variabile originalTexts['email-corpo']. Blocco credenziali: etichette con icone 👤 Nome utente: e 🔑 Password:; Username e Password su righe distinte (<br>); nessuno spazio extra prima/dopo i valori (trim in preparaMail) per copia-incolla pulito. Frase riscontro: "Resto in attesa di un suo riscontro per una breve chiamata conoscitiva." Placeholder template: demo e z82bj7ok; la funzione preparaMail sostituisce con regex /👤 Nome utente:<br>demo<br><br>🔑 Password:<br>z82bj7ok/. Se si modifica il blocco credenziali, aggiornare contemporaneamente template e regex in preparaMail. Ordine competenze nel corpo (04/2026): nell'elenco puntato delle squadre, prima Carpentieri per C.A. Strutturale, poi Montatori Tetti in Legno, poi Squadre di Strip-out. Credibilità B2B: paragrafo opzionale su accreditation / fornitore qualificato (es. riferimento a partner strutturati come Facchetti Costruzioni) posizionato subito prima del box con link demo e credenziali.
TRACKING VISITE
PATH tracking: app/config/accessi_stats.json.
Lettura visite in UI: crm/target.php usa accessi_demo_get_stats() da app/config/accessi_demo.php, mostra badge visite e dettaglio ultime 10 pagine.
Reset visite: endpoint app/api/accessi_reset.php → funzione accessi_demo_reset_user().
SYNC GIT
Commit Auto-sync (produzione → repo): messaggi Git tipo Auto-sync: anagrafica CRM, lista target, utenti demo, visite demo aggiornano solo i JSON tracciati (crm_anagrafica.json, target_list.json, users.json, accessi_stats.json) senza toccare il PHP. Dopo un pull con molti commit di questo tipo, rieseguire comunque il controllo integrità (conteggio aziende + id 1 = Frigerio Legnami).
Accessi: accessi_demo_record() e accessi_demo_reset_user() chiamano git_push_data_from_server() / git_push_data_from_server(true) in app/config/git_sync_data.php.
CRUD funnel fase 1: in crm/target.php salvataggio su target_list.json con chiamata git_push_target_list_from_server(true); modifiche utenti su users.json con chiamata git_push_users_from_server(true); modifiche anagrafica/stato su crm_anagrafica.json via crm_anagrafica_trigger_sync().
DataTables/UI: pagine target, lead, prospect, opportunity usano DataTables Bootstrap 5 e wrapper table-responsive. In target.php il dettaglio visite è aperto da click sul badge in colonna Visite (child-row DataTables), non da pulsanti dedicati.
Event Delegation (Agenti AI): I pulsanti e controlli nelle righe (Modifica ✏️, Elimina 🗑️, select Stato Funnel) devono usare delegazione eventi su tbody, non document.querySelectorAll().forEach(addEventListener). DataTables riordina/filtra le righe: i listener diretti si perdono. Pattern obbligatorio: $('#anagraficaTable tbody').on('click', '.btn-edit', function() { ... }). Stesso per .btn-delete, .crm-stato-select. Colonna 📩 Prima Email: nelle tabelle è di sola lettura (testo DD/MM/YYYY o "—"); la modifica avviene solo tramite modal Modifica in anagrafica.php. Le righe devono avere attributi data-* sulla <tr> per popolare i modal.
Protocollo migrazione campi CRM (Agenti AI, 03/2026): Quando si cambia il tipo di un campo nello schema anagrafica (es. boolean→data), aggiornare in ordine: (1) crm_anagrafica_manager.php: funzione normalize, add, update, update_*; aggiungere helper di formato se serve display; migrazione automatica in crm_anagrafica_get_all con needsRewrite; (2) app/api/crm_anagrafica.php: payload API; (3) tutte le pagine CRM (anagrafica, lead, prospect, opportunity, target): thead, tbody con data-* corretti, controlli UI (per campi editabili inline: input; per campi read-only: solo testo); columnDefs con type: 'date' o type: 'num' e render per sort (DD/MM/YYYY→YYYY-MM-DD, null→9999-12-31 per date); (4) event handlers: solo per campi editabili inline—per colonne read-only (es. 📩 Prima Email) NON usare listener change sulle celle; (5) modal add/edit: controlli e payloadFromModal (unico punto modifica per campi read-only in tabella); (6) export PDF: usare helper formato (es. crm_anagrafica_format_email_inviata); (7) documentazione in crm/index.php e master_index.php. Non usare document.querySelectorAll per controlli in tabelle DataTables: solo event delegation.
PATH strategia: crm/piano_di_marketing.php.
Obbligo operativo: consultare crm/piano_di_marketing.php prima di proporre azioni commerciali su target, lead, prospect e opportunity.
Struttura contenuti: indice a 7 sezioni (Definizione prodotto/servizio, Analisi concorrenza/USP, Target di riferimento, Lead Discovery, Canali marketing, Funnel vendita, KPI).
Parametri lead discovery persistenti: select costo tabella 4.2 salvata via app/api/lead_discovery_cost_update.php e funzione client in crm/piano_di_marketing.php con source_id.