Funzionalità, strumenti e documentazione tecnica del gestionale Magenta Manager.
Setup, uso e troubleshooting delle funzionalità dell'applicazione
Agenti AI: Quando aggiungi o aggiorni documentazione su funzionalità dell'applicazione, inseriscila QUI in app/index.php. NON creare nuovi file .md nelle sottocartelle — si perdono e restano fuori dal flusso di conoscenza.
Funzionamento: Cron (2 esecuzioni Lun-Ven: 19:00 e 7:40). Verifica dati mancanti con getCantieriAlertData() → formatta con Groq AI → invia push. Sabato 7:40 escluso → follow-up venerdì va lunedì 7:40.
Fonte dati: Scansione su consuntivo_ore.php e _consuntivo_ore_tabelle.html (diario ignorato). Cantieri con $is_demo = true in index.php esclusi. telegram_notifier.php esegue chdir alla root del progetto per percorsi affidabili via CRON.
File: app/scripts/telegram_notifier.php, app/config/telegram_credentials.php, app/scripts/setup_telegram_scheduler.ps1
Cron (2 job): 0 19 * * 1-5 e 40 7 * * 1-5
Task Windows: MagentaManager_TelegramNotifier_19, MagentaManager_TelegramNotifier_740
Finestre orarie script: 7:00–8:59 e 17:00–20:59 (sera ampliata per tollerare Task a 17:30)
Server EST: 19:00 Italia = 13:00 EST, 7:40 Italia = 1:40 EST. Crontab: 0 13 * * 1-5 e 40 1 * * 1-5
Setup: Copia telegram_credentials.example.php → telegram_credentials.php. Test: php app/scripts/test_telegram_connection.php
Log: app/scripts/telegram_notifier.log
setup_telegram_scheduler.ps1 DEVE essere riflessa nelle variabili $finestra_mattina e $finestra_sera di telegram_notifier.php.Europe/Rome.Ricerca full-text su tutto il contenuto rilevante del gestionale: dalla barra di navigazione (o dalla pagina dedicata in App) si può cercare una parola o una frase e ottenere l’elenco delle pagine che la contengono (diari di cantiere, programmi, analisi fattibilità, manuali operativi, documentazione, report amministrativi). I risultati mostrano estratti con i termini evidenziati e link diretti alla sezione; l’indice viene aggiornato in automatico (di notte via Cron e a ogni salvataggio tramite Hook) così il contenuto resta sempre reperibile.
La ricerca supporta la mappatura inversa HTML → file binario per i prezzari: i file in amministrazione/prezziari/2025/cache_index/ contengono il commento ORIGIN_FILE; la funzione extractOriginFileFromHtml() in app/core/search_indexer.php legge tale commento e imposta il display_path sul PDF o Excel originale, così il link nei risultati punta al documento ufficiale e non al file di cache.
Architettura: app/core/search_indexer.php, search_query.php, search_hook.php, search_index.json. Pagina: app/search/results.php, sync: app/search/sync_index.php
Directory monitorate: cantieri/.../diario, programma, analisi; manuali_operativi; documentazione; amministrazione/report; amministrazione/prezziari/2025/cache_index (HTML da PDF/Excel per listini; link risultati → documento originale)
Sintassi: Proximity (termini vicini), frasi esatte "...", AND/OR, wildcard travi*
CLI: php app/core/search_indexer.php full (scan), stats, incremental /path/file
Cron: 0 2 * * * php app/core/search_indexer.php full
Hook: SearchHook::onFileSave(__FILE__) nei form di salvataggio
Nel progetto coesistono tre sistemi di generazione PDF. Non confonderli: tecnologie e punti di modifica sono diversi.
1. Export di Pagina (Dompdf)
Pulsante «Scarica PDF» sotto titolo e breadcrumb (in homepage solo nel footer). Singola pagina: invio HTML via POST a app/export/export_single_pdf.php (Dompdf lato server). Home: link diretto a app/export/export_tutte_pagine.php → PDF snello con Tree Explorer + 5 Manuali AI (sorgente index.php di amministrazione, cantieri, manuali_operativi, app, crm). Ordine sezioni: Amministrazione, Cantieri, Manuali, App, CRM. Titolo: «Magenta Manager - Struttura e Istruzioni AI». File: app/export/export_tutte_pagine.php, app/export/export_single_pdf.php, app/scripts/pdf_export.js, app/config/bootstrap.php (barra titolo), app/includes/footer.php (link home), app/includes/header.php (data-base-path). Dipendenza: dompdf/dompdf in app/vendor/ (Composer).
2. Export Tabellare Client-Side (DataTables + pdfMake)
Usato in crm/anagrafica.php, amministrazione/prezzario.php e amministrazione/storico_rese.php. Il pulsante «Scarica tabella PDF» è generato da DataTables Buttons (extend: 'pdfHtml5'). Il PDF viene costruito in browser con pdfMake (CDN: pdfmake, vfs_fonts, jszip, dataTables.buttons, buttons.html5). Nessuna chiamata al server: dati e layout sono presi dalla tabella DataTable. Parametri tipici: exportOptions.columns (es. 'th:not(.no-export)' o array [0–9]; escludere colonna Azioni), modifier: { search: 'none' }, orientation: 'landscape', pageSize: 'A3', customize(doc) per font e larghezze. Per modifiche: intervenire nel blocco buttons: [{ extend: 'pdfHtml5', ... }] e nelle columnDefs con render per type === 'export' (vedi Regole per Agenti AI – Export DataTables). Prezzario e Storico Rese (Agenti AI): in amministrazione/prezzario.php e amministrazione/storico_rese.php le tabelle usano DataTables senza Bootstrap (solo jquery.dataTables.min.css e buttons.dataTables.min.css) e sono avvolte in .prezzario-table-container risp. .storico-table-container; non caricare Bootstrap in quelle pagine per evitare conflitti con il menu di navigazione (style.css).
3. Export Tabellare Server-Side (CRM)
Le pagine crm/lead.php, crm/prospect.php, crm/opportunity.php e crm/target.php espongono un link «Scarica PDF tabella» che punta a script PHP in app/export/: export_crm_lead_pdf.php, export_crm_prospect_pdf.php, export_crm_opportunity_pdf.php, export_target_pdf.php. Generazione lato server con Dompdf (HTML tabella costruito in PHP, dati da JSON/manager). Per modificare colonne o layout si agisce sugli script PHP in app/export/. Nota: export_crm_anagrafica_pdf.php esiste ma non è referenziato da crm/anagrafica.php (anagrafica usa solo export client-side); vedi crm/index.php.
Server / 403 / PDF illeggibili (Dompdf): Dopo git pull eseguire composer install per app/vendor/. In app/export/ è presente .htaccess con Require all granted; in caso di 403 (LiteSpeed/ModSecurity) whitelist della cartella o della regola POST. Regola critica (Agenti AI): Gli script in app/export/ NON devono mai usare bootstrap.php (include header che emette HTML e corrompe il binario PDF). Usare solo auth.php, ob_end_clean() all'avvio e prima dell'output. Unicode: Dompdf richiede <meta charset="utf-8"/> e font DejaVu Sans; forzare font-family: DejaVu Sans !important. Vedi UnicodeHowTo.
Uso: Pulizia note dettate (modal Note) e formattazione messaggi Telegram. Piano FREE, no carta di credito.
Setup: Account su console.groq.com → API Key → app/config/groq_credentials.php (da example). NON committare credenziali.
API Note: app/api/clean_note_groq.php. Modello: llama-3.3-70b-versatile.
Limiti FREE: 30 req/min, 14.400 token/giorno
fast_prices.json, ricerca search_to_ai.php, risposta gemini_api.php (2.5 Flash/Pro). Single-Shot: un'unica chiamata per analisi completa. Schema: [ANALISI DELLE FONTI] | [PREZZO SU BASE UFFICIALE] | [PREZZO SU BASE AZIENDALE] | [CONCLUSIONI] | ### FINE_ANALISI ###. Margini: ((Base×1,15)×1,10). Fallback «prosegui» solo se troncata. Doc tecnica completa: amministrazione/index.php#chat-prezziari-technical-full
Riferimento tecnico per implementazione, API e prompt. Tutte le specifiche sotto.
Architettura file: Le note NON sono globali. Ogni cantiere ha cantieri/[ANNO]/[STATO]/[SLUG]/notes.txt e storico_note.json. Pagina consultazione: storico_note.php in ogni cartella cantiere.
Logica API (app/api/notes.php): POST standard sovrascrive notes.txt. L'archiviazione avviene SOLO con parametro esplicito action=archive: il contenuto viene spostato in storico_note.json con timestamp e notes.txt viene svuotato. Agenti AI senza sessione: usare app/scripts/archive_notes_cli.php <slug> (vedi cantieri/index.php#protocollo-privacy-rese-20).
Sync Git automatico: All'apertura modal (GET) l'API esegue git pull origin main dalla root del repo PRIMA di leggere notes.txt (allineamento da GitHub). Su Windows con Namecheap: eventuale pull da server via bundle SSH. Al salvataggio (POST): git add [percorso], git commit -m "Auto: Note cantiere [slug]", git push origin main. Tutti i comandi Git vanno eseguiti da root (chdir($repoRoot)).
Sync locale–server (PowerShell): app/scripts/sync_dynamic_data.ps1 esegue scansione ricorsiva in cantieri/ con Get-ChildItem -Recurse -Include "notes.txt","storico_note.json". Non usare elenchi statici; ogni nuovo file in cantieri/ viene sincronizzato automaticamente.
Modal (notes-modal.php) – Agenti AI: Lo slug cantiere si recupera con getCantiereContext(): 1) hidden #notesCantiereContext, 2) data-cantiere-context sul modal, 3) fallback regex URL /cantieri\/\d+\/(?:in_esecuzione|completati)\/([a-z0-9_]+)/. NO ricorsione: la funzione NON deve mai chiamare sé stessa come prima riga (causa stack overflow). Usare event delegation su document per il click su #notesBtn (funziona anche se il bottone non esiste all'init). Apertura modal: mostrare subito display=flex e «Caricamento...», poi fetch API; gli errori vanno mostrati nel modal, non bloccare l'apertura.
Sicurezza e tag: Il tag [CANTIERE: slug] è gestito dal frontend (app/includes/notes-modal.php). Se slug è "slug" o "nome_cantiere" il tag NON viene iniettato. Regex pulizia: /^\[CANTIERE:\s*[^\]]+\]\s*\n*/gi.
Integrazione prompt: Solo il prompt «Salvataggio note giornata lavorativa» (app/cursor/ai_prompt) può inviare action=archive, come ultimo atto del flusso. Creazione nuovo cantiere: struttura a 8 file PHP + _consuntivo_ore_tabelle.html + notes.txt/storico_note.json (generati a richiesta).
Contenuti pubblici gestiti da database: un solo entry point PHP, nessun nuovo file per pagina.
Router (Single Page): Il CMS usa un Single Page Router — un unico script nella root del progetto: page.php. Tutte le pagine dinamiche passano da lì; non esiste una coppia file-per-slug sotto cantieri/ o altrove per questi contenuti.
Ordine di bootstrap (Agenti AI): In page.php la prima dipendenza è require_once __DIR__ . '/app/config/bootstrap.php', poi config/db_config.php. Così sessione, paths.php (costante BASE_PATH URL-relativa per asset/link) e controlli auth sono attivi prima della query SQLite.
config/db_config.php e costanti: Le definizioni di BASE_PATH (filesystem root progetto) e DB_PATH sono avvolte in if (!defined(...)), così non collidono con le costanti già impostate da app/config/paths.php tramite bootstrap; DB_PATH per i file .db viene comunque creato quando mancante, usando il BASE_PATH corrente (se bootstrap ha già definito BASE_PATH come prefisso URL, verificare in ambienti complessi che il DSN SQLite punti al path assoluto corretto su disco).
Auth e ruolo cliente: Dopo bootstrap, page.php è soggetta a requireAuth() e requireAllowedByRole(). Il ruolo cliente ha whitelist limitata (dashboard cantieri e cartelle cantiere assegnate): page.php non è in whitelist → accesso come cliente provoca redirect silente verso i cantieri (come altre pagine vietate). Admin e utenti non-cliente autenticati raggiungono il CMS se consentiti dalla policy corrente.
Tipi contenuto (opzionale): config/post_types_config.php elenca etichette per post_type (es. page); la logica di routing resta su page.php + tabella contents.
Database e tabella: I contenuti risiedono nella tabella contents del file SQLite db/system_data.db (connessione via config/db_config.php, variabili $sys_db / $user_db inizializzate a fondo file; page.php usa $sys_db).
Campi tabella contents (riferimento per AI e migrazioni):
id — chiave primariatitle — titolo mostrato (H1 e breadcrumb)slug — identificatore URL univoco (senza spazi; usato nel parametro name)content — corpo HTML salvato nel DB (renderizzato nella pagina)post_type — tipo contenuto (es. 'page')status — 'published' (visibile al pubblico via router) oppure 'draft' (non servita: page.php filtra solo righe pubblicate)URL pubblico: page.php?name=slug-scelto (es. page.php?name=contatti). Slug assente → default comportamento definito in page.php (es. home).
Editor CMS visuale (solo Admin): in page.php è presente il pulsante 📝 Modifica Pagina accanto a Scarica PDF (render solo per $_SESSION['ruolo'] === 'admin'). L'editor apre una modal WYSIWYG Trumbowyg (open source) e salva via API app/api/cms_update_page.php con payload slug + title + content. La modal include azioni Annulla/Salva Modifiche; durante il submit il bottone Salva viene disabilitato e al successo la pagina ricarica automaticamente.
Regole rendering titolo: il titolo principale (H1) arriva dalla colonna title. In output, page.php rimuove dal contenuto DB il primo h1/h2 solo se il testo coincide con il titolo pagina (confronto normalizzato case-insensitive), così eventuali sottotitoli diversi inseriti nell'editor restano visibili.
contents (slug univoco, status coerente, HTML in content)..php per ogni pagina: il routing è già centralizzato in page.php.a-z, 0-9, -), senza spazi; prima dell’INSERT verificare l’unicità con query su slug.database is locked o resta system_data.db-journal, chiudere DB Browser/editor/query aperte e riprovare dopo aver liberato il lock. Non forzare cancellazioni a caldo del journal se il file è in uso.contents esista e includa almeno title, slug, content, post_type, status.http://localhost/magenta-manager/page.php?name=slug e risposta 200; se 404, ricontrollare slug e status='published'.db/system_data.db è versionato, dopo modifiche al DB ricordare commit/push secondo il flusso del progetto; in alternativa documentare dove viene aggiornato il DB in produzione.Specifiche tecniche API, Git sync e tracciamento utenti demo. Protocolli operativi → amministrazione/index.php#target-aziende.
Accessi demo (accessi_stats.json): Le visite utenti demo_* sono registrate da app/config/bootstrap.php → accessi_demo_record() in app/config/accessi_demo.php. File dati: app/config/accessi_stats.json (in .gitignore sul server). Sync: git_push_data_from_server() in app/config/git_sync_data.php (throttle max 1 push/h). Reset: app/api/accessi_reset.php → git_push(true) bypass throttle. Force sync (bypass throttle): l'AI esegue ssh namecheap "cd ~/public_html; php app/scripts/server_force_push.php" (script che usa PHP exec per evitare conflitti con la shell SSH). Funzione accessi_demo_get_sync_info() per last_updated.
Target stati (target_stati.json): API app/api/target_status_update.php (POST username, status). Salvataggio: save_target_status() in app/config/target_manager.php → git_push_target_stati_from_server(true) per push immediato. Last-write-wins in caso di conflitti. Schema JSON: {"stati": {"demo_xxx": "email_inviata_1", ...}, "_meta": {"last_modified": "..."}}.
Users (users.json): Qualsiasi modifica a app/gestione_utenti.php (add, update, delete) deve scatenare git_push_users_from_server(true) per allineare il server di produzione. Funzione in app/config/git_sync_data.php. Usata anche da target_add_row/target_delete_row/target_update_row per utenti demo.
Anagrafica CRM (crm_anagrafica.json): Ogni add/update/delete/update_stato/update_email_inviata in app/api/crm_anagrafica.php chiama crm_anagrafica_trigger_sync() che esegue git_push_crm_anagrafica_from_server(true) e git_push_data_from_server(true). Push immediato senza throttle. Blindatura produzione: in crm_anagrafica_manager.php la funzione crm_anagrafica_save_all esegue git pull origin main PRIMA di scrivere se l'ambiente è davidegobbi.pw (recupera modifiche pushate da locale). Verifica sync: app/api/check_sync.php (GET, solo Admin) restituisce records, md5 e id1_ragione_sociale per confronto rapido locale vs server.
Cartella db/ e SQLite nel repo (04/2026): database SQLite locali in root sotto db/. In .gitignore sono ignorati db/*.db e i file -wal/-journal/-shm, con eccezione !db/system_data.db se il DB di sistema deve restare tracciato in Git; altri file (es. user_data.db) restano solo in locale. Se si cambia quali DB sono versionati, aggiornare .gitignore e questa nota.
Protocollo Sincronizzazione Sicura V2.2 (prompts.csv, 03/2026): Il prompt "Aggiorna repo GitHub e davidegobbi.pw" in app/cursor/ai_prompt/prompts.csv definisce il Protocollo V2.2 - Full Automator. Sequenza: (1) git pull origin main; (2) verifica integrità crm_anagrafica.json: contare gli elementi in aziende (non confondere con l’ID massimo: possono esserci gap) e verificare che il record con id 1 abbia ragione_sociale = "Frigerio Legnami"; se l’ID 1 non corrisponde, stop; (3) gestione conflitti merge (analizzare blocchi, non usare ours/theirs alla cieca); (4-6) Analisi e Documentazione Intelligente: analizzare git diff, estrarre nuove logiche/istruzioni, inserirle nei rispettivi index.php delle 5 macro-sezioni e in master_index.php; (7) git add .; git commit -m "Documentazione e allineamento logiche di sistema"; git push origin main; git reset --hard origin/main; (8) Deploy produzione: ssh namecheap "cd ~/public_html; git fetch origin; git reset --hard origin/main" (il fetch aggiorna origin/main sul server; senza, il reset può restare a un commit vecchio) eseguito autonomamente dall'AI senza attendere input utente. PowerShell: usare ; per concatenare comandi. Moduli rimossi (Agenti AI): "Resoconto Crediti Cursor Pro" eliminato 03/2026; app/cursor/cursor_credits/, credits.php, update_credits.py non esistono più. Non ripristinare.
Funzionamento: Il sistema protegge l'accesso tramite credenziali (username + password). Esistono due ruoli: Admin (accesso totale; utente di sistema magentadg) e Cliente (solo cantieri assegnati, senza accesso a rese_di_posa.php, amministrazione/, app/gestione_utenti.php). Dettaglio in Gestione utenti e permessi.
File coinvolti:
app/config/auth.php — Costanti AUTH_USERNAME (magentadg) e AUTH_PASSWORD_HASH, funzioni isAuthenticated(), authenticate($username, $password), logout(), requireAuth($currentPage).app/config/bootstrap.php — Include auth.php e chiama requireAuth() per ogni pagina (tranne la login).index.php (root) — Pagina di login: form con campi username e password (entrambi obbligatori), ?logout per uscita, redirect dopo login riuscito.Sessione: Sessione PHP standard (session_start()). Lo stato di autenticazione è in $_SESSION['authenticated'] (true), $_SESSION['username'] (magentadg) e $_SESSION['login_time']. Il cookie usato è il cookie di sessione PHP predefinito (session_name(), tipicamente PHPSESSID). Accesso a pagine protette (es. rese_di_posa.php) senza credenziali valide → redirect automatico alla pagina di login.
Proteggere una nuova pagina: Includere require_once __DIR__ . '/path/to/app/config/bootstrap.php'; in cima allo script. Il bootstrap esegue il redirect automatico a index.php se la sessione non è attiva (tranne quando lo script è proprio index.php).
Login robusto: La funzione authenticate() applica trim() su username e password per evitare errori da spazi accidentali (es. copia-incolla). Per utenti da users.json è previsto un fallback: se password_verify() fallisce ma la password coincide con password_chiaro, l'accesso è consentito (utile per utenti demo generati in massa).
Tracciamento GA utenti demo: Per utenti con username che inizia con demo_, il parametro ?u=username viene aggiunto agli URL; menu-navbar e breadcrumbs usano urlWithGaUser($url). Il codice GA (G-Z8YKE304WL) è in app/includes/header.php. Fonte username per GA: lo script PHP legge $_SESSION['username'] e lo inietta in JavaScript (non dall'URL), così GA riceve l'identità anche dopo redirect o URL puliti. Configurazione gtag: user_id, page_title (con suffisso | username), page_path, custom_map per dimension1. Evento demo_view per ogni pagina vista da utente demo. Non rimuovere questa logica.
Non visualizzare mai la password in chiaro nei log o nelle risposte. Non modificare i file di autenticazione (app/config/auth.php, logica in bootstrap.php) senza autorizzazione esplicita dell'utente.
Architettura di protezione per il ruolo Cliente. Riferimento per non rompere le protezioni in sviluppo futuro.
app/config/auth.php (funzione requireAllowedByRole()) sono accessibili ai clienti. Qualsiasi nuova pagina è vietata finché non aggiunta alla whitelist.auth.php (redirect/403) sia localmente nel file stesso tramite check sul ruolo e exit; (es. master_index.php dopo il bootstrap). Due livelli riducono il rischio di bypass.cliente non deve mai vedere pulsanti di export PDF, link al Master Index, box «Rese di Posa» né box «Storico Note AI». La UI deve adattarsi dinamicamente (condizioni $_SESSION['ruolo'] !== 'cliente' in navbar, footer, bootstrap, dashboard cantieri). Nessun pulsante o link «di sistema» in vista per il cliente.Ruoli: Admin (vede tutto; magentadg è l'admin di sistema) e Cliente (vede solo i cantieri assegnati, nessun accesso a rese_di_posa.php, storico_note.php, amministrazione/, app/gestione_utenti.php).
Database utenti: app/config/users.json (gestito da app/config/users_db.php). Il percorso del file è risolto in modo assoluto tramite __DIR__ in users_db.php, così il puntamento a users.json è indipendente dalla posizione dello script e si evita l'errore file_exists(): Passing null in fase di login per gli utenti non-admin. Struttura per utente: username, password_hash, password_chiaro (solo per visualizzazione Admin), ruolo (admin/cliente), cantieri_assegnati (array di slug cartelle).
File: app/gestione_utenti.php. Accessibile solo dalla dashboard della sezione App (app/index.php), tramite il box "Gestione utenti" (visibile solo all'Admin); non è presente nel menu generale.
Admin di sistema (magentadg): privilegi assoluti; la sua password è l'unica non gestita dal database JSON (definita in app/config/auth.php). Nella tabella utenti per magentadg è indicato: Password di sistema (gestita in auth.php).
Interfaccia: layout Bootstrap (card per il form, tabella con .table .table-hover .table-striped, pulsanti .btn .btn-success / .btn-primary .btn-sm). La funzione Mostra (occhio) in tabella esegue automaticamente anche la copia della password negli appunti al click, con feedback visivo (badge "Copiato!" e icona ✓), per la massima velocità operativa. Nel messaggio di successo dopo creazione utente le credenziali vengono copiate negli appunti al caricamento della pagina.
Tabella: gli hash non sono mostrati; per magentadg resta solo la nota testuale senza pulsanti.
Lista cantieri assegnabili: generata dinamicamente leggendo le cartelle in cantieri/ANNO/in_esecuzione/ (funzione users_db_list_cantieri_available() in app/config/users_db.php). L'elenco checkbox in gestione utenti è sempre aggiornato in tempo reale in base al file system. La creazione di un nuovo cantiere aggiorna automaticamente l'elenco dei cantieri assegnabili in questa pagina. L'Admin può: vedere l'elenco utenti (colonna password con Mostra/Copia); aggiungere un nuovo utente (nome utente manuale, ruolo Admin/Cliente, cantieri tramite checkbox); modificare in ogni momento i permessi, i cantieri assegnati e rigenerare le password degli utenti esistenti tramite il tasto Modifica (icona matita); eliminare un utente tramite il tasto Elimina (icona cestino). Le modifiche ai cantieri assegnati hanno effetto al prossimo refresh della pagina per il cliente interessato. Generazione password: al salvataggio (nuovo utente o rigenera da Modifica) viene generata automaticamente una password di 8 caratteri (minuscole e numeri) e mostrata con tasto Copia.
Protocollo Eliminazione utenti (Agenti AI): La funzione users_db_delete_row($username) in app/config/users_db.php rimuove l'utente da users.json (non elimina magentadg). Per utenti demo_*: se la riga esiste in target_list.json, usare target_delete_row($username) (in app/config/target_manager.php) che rimuove da target_list, target_stati e users.json e lancia il push Git; se l'utente demo non è in target (orfano), usare users_db_delete_row + git_push_users_from_server(true). Per utenti non-demo usare solo users_db_delete_row + git_push_users_from_server(true). Regola: ogni add/update/delete in gestione_utenti deve scatenare il push verso produzione.
Modal Modifica: Lo script usa DOMContentLoaded, display: flex per il container, niente classe Bootstrap fade (può nascondere la modale). Listener su .btn-edit-user con data-username, data-ruolo, data-cantieri (JSON array).
Controllo accessi (cliente): In bootstrap.php dopo requireAuth() viene chiamato requireAllowedByRole(): blocca tutta la sezione amministrazione/, tutta la sezione app/ (qualsiasi pagina sotto app/), rese_di_posa.php in qualunque cantiere (403) e storico_note.php (redirect silente); per percorsi cantieri/ANNO/in_esecuzione/SLUG/ verifica che SLUG sia in $_SESSION['cantieri_ammessi']. La pagina cantieri/index.php mostra solo i cantieri assegnati al cliente. Un cliente non può accedere per nessuna ragione ad amministrazione/, ad alcuna pagina in app/, a rese_di_posa.php o a storico_note.php.
Interfaccia cliente (blindatura): L'interfaccia per il ruolo Cliente è minimalista e priva di documentazione tecnica o istruzioni per agenti AI. In navbar il cliente vede solo i link «I Miei Cantieri» e «Logout» (nessun accesso a Bacheca, Manuali, Amministrazione, App, Ricerca). Dopo il login il redirect è diretto a cantieri/index.php. La dashboard cantieri per il cliente mostra solo il titolo «I Miei Cantieri» e i box dei cantieri assegnati, senza indice, protocolli, parti I/II o regole per AI.
Blindatura Know-how: I box «Rese di Posa» e «Storico Note AI» sono rimossi visivamente per i clienti nella dashboard del singolo cantiere (app/templates/cantieri_in_esecuzione/index.php.template e index.php dei cantieri esistenti). L'accesso a rese_di_posa.php è protetto da Hard-Block 403 (requireAllowedByRole() in app/config/auth.php): un cliente che tenti l'accesso diretto via URL riceve 403 e die() senza contenuto. L'accesso a storico_note.php è bloccato con redirect silente verso cantieri/index.php.
È severamente vietato inserire tabelle o paragrafi riguardanti le «Rese Effettive» o lo «Storico per Preventivi» nei file diario_di_cantiere.php. Queste informazioni sono di esclusiva pertinenza del file rese_di_posa.php (protetto da Hard-Block).
Tabella di riferimento OBBLIGATORIA. Consulta PRIMA di cercare altrove.
| Tipo Informazione | File di Riferimento | Esempi |
|---|---|---|
| 🔐 Autenticazione / Login | app/config/auth.php, app/config/bootstrap.php, index.php (root) | Multi-utente, ruoli Admin/Cliente, dettagli |
| 👥 Gestione utenti | app/gestione_utenti.php, app/config/users_db.php, app/config/users.json | Solo Admin; permessi cliente, dettagli |
| 📐 Formule Matematiche | amministrazione/prezzario.php | Ore Uomo = Quantità ÷ Resa |
| 📊 Rese Operative | amministrazione/prezzario.php | Tegole, isolante, ecc. |
| 💰 Costi Orari | amministrazione/costo_orario_operaio.php, costo_orario_export.inc.php (per Chat AI) | €/ora operaio; export per Gemini |
| 📋 Protocolli Cantiere | cantieri/index.php | SOP-01, Diario, Programma |
| 🚨 Alert Bacheca (Home) | app/includes/cantieri-alert.php | Box visibile solo se dati mancanti (ore/presenze, rese, assenze senza motivazione). Cantieri con $is_demo = true in index.php esclusi. |
| 📄 Export PDF | app/export/, app/scripts/pdf_export.js, app/styles/style.css; crm/anagrafica.php, amministrazione/prezzario.php (DataTables pdfHtml5) | Tre sistemi: pagina (Dompdf), tabellare client-side (anagrafica, prezzario, storico rese), tabellare server-side (CRM). Sistemi di Esportazione PDF. Su mobile: full-width e margini (Best Practices) |
| 📱 UI responsive (titoli, PDF) | app/styles/style.css | Titoli: word-break per overflow. PDF: full-width e margini su mobile |
| 🎨 Bootstrap Icons (icona external-link CRM) | app/includes/header.php | Caricato per pagine CRM e gestione_utenti. Icona bi-box-arrow-up-right sui link Sito Web. CDN bootstrap-icons@1.11.3. Agenti: aggiungere nuove icone CRM richiede inclusione in header.php (stessa condizione di Bootstrap CSS). |
| 📊 Google Analytics / Tracciamento utenti demo | app/includes/header.php, app/config/auth.php (isDemoUserForGa, urlWithGaUser), bootstrap.php, menu-navbar.php | GA G-Z8YKE304WL. Username da sessione PHP → user_id, page_title, page_path, evento demo_view. |
| 📋 Accessi demo (sync auto, reset) | bootstrap.php, accessi_demo.php, git_sync_data.php, app/api/accessi_reset.php, amministrazione/target.php | Tracciamento demo_*. Push auto (1/h). Reset per utente: API accessi_reset, git_push(true) bypass throttle. Dettagli |
| 🏗️ Tecniche Costruttive | manuali_operativi/manuale_tetto_legno.php | Tetto legno |
| 💣 Demolizioni | manuali_operativi/manuale_demolizioni.php | Strip-out |
| 📝 Sync Note Git / Modal | app/api/notes.php, app/includes/notes-modal.php, app/scripts/sync_dynamic_data.ps1 | Git pull on load, push on save; scansione ricorsiva cantieri/; getCantiereContext senza ricorsione, event delegation per notesBtn, dettagli |
| 📁 Cartella app/temp/ | app/temp/ | File temporanei di sviluppo (markdown doc temporanea, script di test). Eliminabili quando non servono. Script principali in app/scripts/. |
⚠️ Prima di inventare procedure o dati, CONSULTA i file indicati.
🛡️ Protocollo sicurezza cantieri (Divieto Ipotesi, Isolamento Demo, Verifica Identità) → cantieri/index.php#protocollo-sicurezza-agenti
OGNI tool call consuma crediti. Usa il MINIMO numero di chiamate: batch operations, riusa contesto, grep > read_file. NO chiamate speculative.
Master Index = solo hub navigazione. Dati operativi, rese, protocolli → nei file core (prezzario, cantieri).
Se modifichi l'Indice Navigazione Rapida di cantieri, manuali, amministrazione o app → aggiorna master_index.php per riflettere le stesse modifiche.
E tassativamente proibito all'AI eseguire i punti del Protocollo di Sincronizzazione (Git Add/Commit/Push/Reset) e il Deploy SSH verso Namecheap di propria iniziativa. L'AI deve limitarsi allo sviluppo del codice nei file richiesti. Il deploy e un'operazione critica che deve essere autorizzata ESPLICITAMENTE dall'utente con la frase: "Esegui Protocollo di Allineamento Finale". Senza questa frase, qualsiasi comando git o ssh e una violazione del protocollo di sicurezza.
DIVIETO ASSOLUTO DI CSS INLINE: E tassativamente vietato iniettare CSS direttamente nei tag HTML o usare blocchi <style> nei file .php. Ogni modifica estetica deve avvenire esclusivamente tramite classi nel file app/styles/style.css per garantire l'integrita del design system.
Ogni volta che viene modificata la struttura fondamentale dei file di cantiere (es. aggiunta colonne alle tabelle consuntivo, cambio whitelist in cantieri-alert.php, nuovi file .html di cache), l'AI deve obbligatoriamente aggiornare anche i file corrispondenti in app/templates/cantieri_in_esecuzione/ (incluso _consuntivo_ore_tabelle.html.template) per evitare divergenze tecniche tra vecchi e nuovi cantieri.
Per modificare gli export PDF generati da DataTables Buttons (pdfHtml5, es. crm/anagrafica.php):
export: In columnDefs il callback render(data, type, row) viene invocato con type === 'export' quando DataTables prepara i dati per il PDF. Restituire in quel caso un valore testuale pulito (niente HTML): es. per la colonna Sito Web restituire l’URL senza tag <a>; per colonne con select estrarre il testo dell’opzione selezionata.exportOptions.columns: L’array indica gli indici (0-based) delle colonne da includere nel PDF. Escludere sempre la colonna Azioni (ultima). Se aggiungi o rimuovi colonne nell’HTML (thead/tbody), ricalibra questo array e gli indici in columnDefs.targets e order.customize(doc): pdfMake passa l’oggetto documento doc (pdfmake definition). Puoi modificare doc.defaultStyle.fontSize, doc.styles.tableHeader.fontSize, e doc.content[1].table.widths (array di larghezze, es. Array(n).fill('*')). Non usare doc.content[0] per la tabella: è il titolo; la tabella è in doc.content[1].<?php
require_once __DIR__ . '/app/config/bootstrap.php';
$pageTitle = 'Titolo';
$breadcrumbs = [['label' => 'Home', 'url' => 'index.php'], ['label' => 'Sezione']];
?>
<?php includePageHeader(); ?>
<div class="content-container">...</div>
<?php includeComponent('footer'); ?>
Nomenclatura: File/cartelle snake_case, variabili camelCase, classi CSS kebab-case.
CSS: app/styles/style.css | Breakpoints: 768px, 480px | Container: .content-container max-width 1200px
UI responsive: Titoli (h1, h2, h3) usano word-break: break-word e overflow-wrap: break-word per evitare overflow su mobile (parole lunghe vanno a capo). Pulsante «Scarica PDF» (.btn-pdf-export): su viewport ≤768px è full-width, con margini aumentati (.pdf-export-row). Non rimuovere queste regole.
git status → git add . → git commit -m "..."git push origin mainssh namecheap "cd ~/public_html && git pull origin main"PowerShell: Usa ; non &&. File esclusi: namecheap_credentials, telegram_credentials, groq_credentials.
Regola per Agenti AI: I file dinamici che devono sincronizzare tra server e locale (es. stati target) vanno in formato tracciato (JSON, CSV), mai in file *.log (ignorati da .gitignore). Esempi tracciati: app/config/target_stati.json (push immediato via git_push_target_stati_from_server), notes.txt, prompts.csv. Eccezione: app/config/accessi_stats.json è in .gitignore per non sovrascrivere i dati reali sul server; struttura di riferimento app/config/accessi_stats.json.example. Sul server il push automatico (git_sync_data.php, throttle 1h) aggiorna il repo con le visite; in locale il file non è tracciato.
File: app/scripts/search_highlight.js. Regola: Non fare localStorage.clear(). Usa prefissi specifici (notesCache_, promptCopy_) per pulizia selettiva.