From b3670d164b1589d1701e420afbf1ab4adeba2cbc Mon Sep 17 00:00:00 2001 From: Simone Cavalli Date: Fri, 19 Jun 2026 11:51:03 +0200 Subject: [PATCH] =?UTF-8?q?docs(phase-18):=20create=20phase=20plan=20?= =?UTF-8?q?=E2=80=94=20cleanup=20&=20consolidamento?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 3 piani in 2 wave: 18-01 (rimozioni Forecast+QuoteBuilder), 18-02 (fusione analytics→dashboard), 18-03 (CLEAN-04 verify + build check). ROADMAP.md aggiornato con plan list Phase 18. Co-Authored-By: Claude Sonnet 4.6 --- .planning/ROADMAP.md | 27 +- .../18-cleanup-consolidamento/18-01-PLAN.md | 233 ++++++++++++ .../18-cleanup-consolidamento/18-02-PLAN.md | 345 ++++++++++++++++++ .../18-cleanup-consolidamento/18-03-PLAN.md | 197 ++++++++++ 4 files changed, 791 insertions(+), 11 deletions(-) create mode 100644 .planning/phases/18-cleanup-consolidamento/18-01-PLAN.md create mode 100644 .planning/phases/18-cleanup-consolidamento/18-02-PLAN.md create mode 100644 .planning/phases/18-cleanup-consolidamento/18-03-PLAN.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index e28af03..de14b1c 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -17,11 +17,11 @@ - [~] **Phase 15: Dashboard Revenue Stats** - ❌ ABBANDONATA (reset 2026-06-19): mockup mai arrivato; analytics confluisce nella dashboard via CLEAN-03 - [~] **Phase 16: Proposal AI — Data Foundations & Auto-Provisioning** - ❌ RI-SCOPATA in v2.2; Stripe Payment Link + auto-provisioning → backlog post-R5 - [~] **Phase 17: Proposal AI — Builder, Pagina Pubblica & Email** - ❌ RI-SCOPATA in v2.2 (Phase 21/22 con transcript + flusso chiaro) -- [ ] **Phase 18 (R1): Cleanup & Consolidamento** - Rimuovi Forecast + quote builder manuale; fondi `/admin/analytics` nella dashboard; archivia fasi residue v2.1 -- [ ] **Phase 19 (R2): Pipeline CRM Kanban** - Board lead stile Pipedrive con colonne per stage + drag-drop; vinto/perso come cambio-colonna manuale -- [ ] **Phase 20 (R3): Knowledge Base Cliente (transcript)** - Schema additivo + UI per incollare transcript datati multipli per lead/cliente -- [ ] **Phase 21 (R4): Agente AI — generazione preventivo** - Builder: admin sceglie cliente+offerta, l'AI (Claude) legge transcript + offerta e genera bozza preventivo; admin revisiona -- [ ] **Phase 22 (R5): Pagina pubblica `/preventivo/[slug]` + email** - Pagina pubblica HTML/CSS, accept/reject → CRM, invio link via email (Resend) +- [ ] **Phase 18: Cleanup & Consolidamento** - Rimuovi Forecast + quote builder manuale; fondi `/admin/analytics` nella dashboard; archivia fasi residue v2.1 +- [ ] **Phase 19: Pipeline CRM Kanban** - Board lead stile Pipedrive con colonne per stage + drag-drop; vinto/perso come cambio-colonna manuale +- [ ] **Phase 20: Knowledge Base Cliente** - Schema additivo + UI per incollare transcript datati multipli per lead/cliente +- [ ] **Phase 21: Agente AI — generazione preventivo** - Builder: admin sceglie cliente+offerta, l'AI (Claude) legge transcript + offerta e genera bozza preventivo; admin revisiona +- [ ] **Phase 22: Pagina pubblica preventivo + email** - Pagina pubblica HTML/CSS, accept/reject → CRM, invio link via email (Resend) ## Phase Details @@ -150,7 +150,7 @@ Plans: ## v2.2 — Sales Loop (fasi attive) -### Phase 18 (R1): Cleanup & Consolidamento +### Phase 18: Cleanup & Consolidamento **Goal**: Sgomberare il campo dai doppioni e dal peso morto prima di costruire il loop di vendita, senza perdere dati. **Mode:** ui (solo rimozioni/rotte, nessun drop di tabelle) **Depends on**: nessuna (può partire subito) @@ -160,9 +160,14 @@ Plans: 2. Il quote builder manuale (`/admin/quotes/new`) e il suo entry point non esistono più 3. Le statistiche annuali di `/admin/analytics` sono visibili nella Dashboard `/admin` come vista unica; la rotta `/admin/analytics` è eliminata (nessun doppione) 4. Le fasi v2.1 residue (13/15/16/17) sono marcate cancellate/congelate nel planning -**Status**: Pending planning — `/gsd-plan-phase 18` +**Plans**: 3 plans +**Plan list**: + - [ ] 18-01-PLAN.md — Rimozione Forecast + Quote Builder manuale (CLEAN-01, CLEAN-02) + - [ ] 18-02-PLAN.md — Fusione analytics nella Dashboard, eliminazione rotta /admin/analytics (CLEAN-03) + - [ ] 18-03-PLAN.md — Verifica CLEAN-04 planning docs + build check + checkpoint visuale +**Status**: Planned — ready for `/gsd-execute-phase 18` -### Phase 19 (R2): Pipeline CRM Kanban +### Phase 19: Pipeline CRM Kanban **Goal**: I lead si gestiscono in una board Kanban stile Pipedrive con drag-drop tra gli stage; vinto/perso è un cambio-colonna manuale. **Mode:** ui **Depends on**: Phase 14 (CRM lead esistente). Riusa `@dnd-kit` (pattern KanbanBoard progetti). @@ -173,7 +178,7 @@ Plans: 3. Spostare un lead su "Vinto"/"Perso" è l'azione manuale che ne registra l'esito **Status**: Pending planning — `/gsd-plan-phase 19` -### Phase 20 (R3): Knowledge Base Cliente (transcript) +### Phase 20: Knowledge Base Cliente **Goal**: Memorizzare i transcript datati delle call (multipli per lead/cliente) e mostrarli nel profilo, pronti per essere dati in pasto all'AI. **Mode:** schema + ui **Depends on**: Phase 14 (lead) / clienti. Migration a prod via SSH PRIMA del codice dipendente. @@ -184,7 +189,7 @@ Plans: 3. I transcript sono elencati in ordine cronologico nel profilo **Status**: Pending planning — `/gsd-plan-phase 20` -### Phase 21 (R4): Agente AI — generazione preventivo +### Phase 21: Agente AI — generazione preventivo **Goal**: L'admin seleziona cliente + offerta; l'agente AI (Claude) legge i transcript + i dati dell'offerta e genera una bozza di preventivo personalizzata, che l'admin può rivedere ed editare. **Mode:** ai + ui **Depends on**: Phase 20 (transcript) + DB Offerte (Phase 11/12, fatto) @@ -196,7 +201,7 @@ Plans: **Note**: decisioni di design AI (modello Claude, prompt, storage output) in fase di planning dedicata **Status**: Pending planning — `/gsd-plan-phase 21` -### Phase 22 (R5): Pagina pubblica `/preventivo/[slug]` + email +### Phase 22: Pagina pubblica preventivo + email **Goal**: Pubblicare la proposta come pagina pubblica a `/preventivo/[slug]`, con accept/reject che si riflette nel CRM, e inviare il link via email. **Mode:** ui **Depends on**: Phase 21 (modello dati proposta). Evolve la meccanica di `/quote/[token]`. diff --git a/.planning/phases/18-cleanup-consolidamento/18-01-PLAN.md b/.planning/phases/18-cleanup-consolidamento/18-01-PLAN.md new file mode 100644 index 0000000..8d24f4a --- /dev/null +++ b/.planning/phases/18-cleanup-consolidamento/18-01-PLAN.md @@ -0,0 +1,233 @@ +--- +phase: 18-cleanup-consolidamento +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - src/components/admin/AdminSidebar.tsx + - src/app/admin/forecast/page.tsx + - src/app/admin/quotes/new/page.tsx + - src/components/admin/leads/SendQuoteModal.tsx + - src/app/admin/projects/project-actions.ts +autonomous: true +requirements: + - CLEAN-01 + - CLEAN-02 + +must_haves: + truths: + - "La rotta /admin/forecast non è più raggiungibile (404 o redirect)" + - "La voce 'Forecast' non appare più nella sidebar admin" + - "La rotta /admin/quotes/new non è più raggiungibile" + - "SendQuoteModal non ha più il bottone che naviga a /admin/quotes/new" + - "project-actions.ts non chiama più revalidatePath('/admin/forecast')" + artifacts: + - path: "src/components/admin/AdminSidebar.tsx" + provides: "Sidebar senza voce Forecast" + contains: "NON deve contenere href: \"/admin/forecast\"" + - path: "src/app/admin/forecast/page.tsx" + provides: "File eliminato (rotta rimossa)" + - path: "src/app/admin/quotes/new/page.tsx" + provides: "File eliminato (rotta rimossa)" + - path: "src/components/admin/leads/SendQuoteModal.tsx" + provides: "Modal senza bottone navigazione a quotes/new" + - path: "src/app/admin/projects/project-actions.ts" + provides: "Server actions senza revalidatePath forecast" + key_links: + - from: "AdminSidebar.tsx NAV_ITEMS" + to: "/admin/forecast" + via: "href nel NAV_ITEMS array" + pattern: "forecast" + - from: "SendQuoteModal.tsx" + to: "/admin/quotes/new" + via: "window.location.href" + pattern: "quotes/new" +--- + + +Rimuovere le rotte /admin/forecast e /admin/quotes/new e tutti i loro entry point. + +Purpose: CLEAN-01 e CLEAN-02 — eliminare feature obsolete prima del Sales Loop. Il forecast è sostituito dal loop AI; il quote builder manuale è sostituito dall'agente AI in Phase 21. +Output: Due rotte rimosse, sidebar pulita, SendQuoteModal senza entry point obsoleto, project-actions.ts senza revalidatePath forecast. + + + +@$HOME/.claude/get-shit-done/workflows/execute-plan.md +@$HOME/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + + + + + + Task 1: Rimuovi rotta Forecast — file, sidebar, revalidatePath (CLEAN-01) + + + - src/components/admin/AdminSidebar.tsx — array NAV_ITEMS, riga con href: "/admin/forecast" + - src/app/admin/forecast/page.tsx — conferma contenuto prima di eliminare + - src/app/admin/projects/project-actions.ts — righe 138, 145, 161 con revalidatePath("/admin/forecast") + + + + src/components/admin/AdminSidebar.tsx, + src/app/admin/projects/project-actions.ts + + + + 1. In AdminSidebar.tsx: rimuovi la riga dell'oggetto Forecast dall'array NAV_ITEMS: + `{ href: "/admin/forecast", label: "Forecast", icon: TrendingUp },` + Rimuovi anche l'import `TrendingUp` da lucide-react se non è usato altrove nel file. + + 2. In project-actions.ts: rimuovi le tre chiamate `revalidatePath("/admin/forecast")` alle righe ~138, ~145, ~161. + Ogni funzione che la contiene (addProjectOffer, removeProjectOffer, updateProjectOfferTotal) + mantiene le proprie altre revalidatePath (es. `/admin/projects/${projectId}`) — togli SOLO le righe forecast. + + 3. Elimina il file della rotta forecast: + - src/app/admin/forecast/page.tsx + Elimina anche la directory se è rimasta vuota: + - src/app/admin/forecast/ (directory) + + NON toccare: tabelle DB, lib/forecast-queries.ts (deadweight tollerabile, non blocca nulla), + nessun'altra pagina o componente. + + + + + grep -r "admin/forecast" /Users/simonecavalli/Vault/IAMCAVALLI/src --include="*.tsx" --include="*.ts" | grep -v "node_modules" | grep -v ".next" | wc -l + + Risultato atteso: 0 righe (nessun riferimento a /admin/forecast rimasto nel codice sorgente). + + Verifica aggiuntiva sidebar: + grep "TrendingUp\|forecast" /Users/simonecavalli/Vault/IAMCAVALLI/src/components/admin/AdminSidebar.tsx + Risultato atteso: nessun output (zero match). + + + + - grep -r "admin/forecast" src/ produce 0 risultati (esclusi node_modules e .next) + - Il file src/app/admin/forecast/page.tsx non esiste più + - AdminSidebar.tsx non contiene la stringa "forecast" né "TrendingUp" (se rimosso) + - project-actions.ts non contiene revalidatePath("/admin/forecast") + + + + La voce Forecast è assente dalla sidebar, la rotta /admin/forecast è 404, nessun server action + chiama revalidatePath su quella rotta. + + + + + Task 2: Rimuovi rotta Quote Builder manuale e il suo entry point (CLEAN-02) + + + - src/app/admin/quotes/new/page.tsx — conferma contenuto prima di eliminare + - src/components/admin/leads/SendQuoteModal.tsx — riga ~120 con window.location.href = /admin/quotes/new + - src/components/admin/quotes/QuoteBuilderForm.tsx — identifica che è usato solo da quotes/new + - src/components/admin/quotes/OfferSelector.tsx — identifica che è usato solo da QuoteBuilderForm + - src/components/admin/quotes/PriceOverrideInput.tsx — stesso + - src/components/admin/quotes/QuotePreview.tsx — stesso + + + + src/app/admin/quotes/new/page.tsx, + src/components/admin/leads/SendQuoteModal.tsx, + src/components/admin/quotes/QuoteBuilderForm.tsx, + src/components/admin/quotes/OfferSelector.tsx, + src/components/admin/quotes/PriceOverrideInput.tsx, + src/components/admin/quotes/QuotePreview.tsx + + + + 1. In SendQuoteModal.tsx: trova il blocco che naviga a /admin/quotes/new: + `window.location.href = /admin/quotes/new?lead_id=${leadId};` + Rimuovi il pulsante / branch che lo contiene. Se il modal ha una logica "crea nuovo preventivo" + che porta a quella rotta, rimuovi quella branch. Mantieni tutto il resto del modal intatto + (il flusso "preventivo esistente" non va toccato). + Prima di modificare, leggi il file per capire la struttura esatta del branch da eliminare. + + 2. Elimina i file della rotta e i componenti esclusivi: + - src/app/admin/quotes/new/page.tsx + - src/components/admin/quotes/QuoteBuilderForm.tsx + - src/components/admin/quotes/OfferSelector.tsx + - src/components/admin/quotes/PriceOverrideInput.tsx + - src/components/admin/quotes/QuotePreview.tsx + Elimina le directory rimaste vuote: + - src/app/admin/quotes/new/ (directory) + - src/components/admin/quotes/ (directory, solo se completamente vuota dopo la rimozione) + + NON toccare: src/app/admin/quotes/ se esistono altre sotto-rotte (verifica prima), + lib/admin-queries.ts (getAllOfferMacrosWithMicros — usata altrove), DB. + + ATTENZIONE — verifica preventiva: prima di eliminare src/components/admin/quotes/, + esegui: grep -r "quotes/" src/components --include="*.tsx" --include="*.ts" + per confermare che i quattro componenti sopra non sono importati da altri file al di fuori di quotes/new. + Se ci sono altri consumer, NON eliminare il componente e segnala in SUMMARY. + + + + + grep -r "quotes/new" /Users/simonecavalli/Vault/IAMCAVALLI/src --include="*.tsx" --include="*.ts" | grep -v "node_modules" | grep -v ".next" | wc -l + + Risultato atteso: 0 righe. + + Verifica esistenza file: + test -f /Users/simonecavalli/Vault/IAMCAVALLI/src/app/admin/quotes/new/page.tsx && echo "ESISTE_ANCORA" || echo "OK_RIMOSSO" + Risultato atteso: OK_RIMOSSO + + Verifica SendQuoteModal: + grep "quotes/new" /Users/simonecavalli/Vault/IAMCAVALLI/src/components/admin/leads/SendQuoteModal.tsx + Risultato atteso: nessun output. + + + + - grep -r "quotes/new" src/ produce 0 risultati + - src/app/admin/quotes/new/page.tsx non esiste più + - src/components/admin/quotes/QuoteBuilderForm.tsx non esiste più + - SendQuoteModal.tsx non contiene la stringa "quotes/new" + + + + La rotta /admin/quotes/new è 404, il pulsante di navigazione nel SendQuoteModal è rimosso, + i componenti esclusivi del quote builder sono eliminati. + + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| admin UI → file system | Operazioni di eliminazione file irreversibili | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-18-01 | Tampering | project-actions.ts | accept | Rimozione di sole righe revalidatePath inerte — nessun path di dati toccato; le funzioni restano funzionali | +| T-18-02 | Denial of Service | SendQuoteModal.tsx | mitigate | Leggere il file prima di modificare per evitare di rompere il flusso "preventivo esistente" che resta necessario | + + + +Al termine del piano: +1. `npm run build` deve completare senza errori TypeScript (nessun import rotto) +2. `grep -r "admin/forecast" src/` → 0 risultati +3. `grep -r "quotes/new" src/` → 0 risultati +4. La sidebar admin non mostra la voce "Forecast" + + + +- CLEAN-01: /admin/forecast → 404, sidebar senza voce Forecast, project-actions.ts senza revalidatePath forecast +- CLEAN-02: /admin/quotes/new → 404, SendQuoteModal senza navigazione a quotes/new, componenti quotes/ rimossi +- Build TypeScript pulita (nessun import broken) + + + +After completion, create `.planning/phases/18-cleanup-consolidamento/18-01-SUMMARY.md` + diff --git a/.planning/phases/18-cleanup-consolidamento/18-02-PLAN.md b/.planning/phases/18-cleanup-consolidamento/18-02-PLAN.md new file mode 100644 index 0000000..6624d6f --- /dev/null +++ b/.planning/phases/18-cleanup-consolidamento/18-02-PLAN.md @@ -0,0 +1,345 @@ +--- +phase: 18-cleanup-consolidamento +plan: 02 +type: execute +wave: 1 +depends_on: [] +files_modified: + - src/app/admin/page.tsx + - src/app/admin/analytics/page.tsx + - src/components/admin/YearSelector.tsx +autonomous: true +requirements: + - CLEAN-03 + +must_haves: + truths: + - "La Dashboard /admin mostra le statistiche annuali (MetricCard fatturato, grafico mensile, time tracking)" + - "La rotta /admin/analytics non esiste più (404)" + - "Il selettore anno naviga a /admin?year=X, non a /admin/analytics?year=X" + - "Non esiste più il file src/app/admin/analytics/page.tsx" + artifacts: + - path: "src/app/admin/page.tsx" + provides: "Dashboard con sezione Statistiche integrata" + contains: "getAnalyticsByYear" + - path: "src/app/admin/analytics/page.tsx" + provides: "File eliminato" + - path: "src/components/admin/YearSelector.tsx" + provides: "YearSelector che naviga a /admin?year=Y" + contains: "router.push(`/admin?year=${y}`)" + key_links: + - from: "src/app/admin/page.tsx" + to: "lib/analytics-queries" + via: "import getAnalyticsByYear, getMonthlyCollected, getAvailableYears, getTimeByClient, getTotalTrackedHours" + pattern: "analytics-queries" + - from: "YearSelector" + to: "/admin" + via: "router.push" + pattern: "router.push.*admin" +--- + + +Fondere le statistiche di /admin/analytics nella Dashboard /admin ed eliminare la rotta duplicata. + +Purpose: CLEAN-03 — unica vista admin per statistiche. Elimina il doppione /admin/analytics e porta +tutto il suo contenuto (MetricCard economiche + MonthlyChart + time tracking per cliente) nella dashboard +esistente, sotto le KPI card e il feed attività già presenti. +Output: /admin mostra statistiche annuali, /admin/analytics → 404, YearSelector aggiornato. + + + +@$HOME/.claude/get-shit-done/workflows/execute-plan.md +@$HOME/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + + + + + +Imports da copiare in admin/page.tsx: +```typescript +import { + getAnalyticsByYear, + getMonthlyCollected, + getAvailableYears, + getTimeByClient, + getTotalTrackedHours, +} from "@/lib/analytics-queries"; +import { YearSelector, MonthlyChart } from "@/components/admin/YearSelector"; +``` + +Funzioni helper da copiare in admin/page.tsx: +```typescript +function fmtEur(n: number) { /* formatta in EUR it-IT */ } +function fmtSeconds(s: number): string { /* h m format */ } +``` +ATTENZIONE: admin/page.tsx ha già una funzione `fmtEur` (ma accetta `string`, non `number`). +Rinominare una delle due o unificarle — preferire la versione che accetta `number` (più robusta) +e aggiornare i consumer nel file. + +Componente MetricCard (da analytics/page.tsx) — da spostare in admin/page.tsx: +```typescript +function MetricCard({ label, value, sub, accent }: { + label: string; value: string; sub?: string; accent?: boolean; +}) { ... } +``` +Questo componente è diverso da KpiCard già presente in admin/page.tsx: +KpiCard ha icona + colore; MetricCard ha stile accent verde o bianco con bordo. +Mantieni ENTRAMBI (scopi diversi): KpiCard per le 4 metriche operative in cima, +MetricCard per le statistiche economiche annuali nella nuova sezione. + +Firma del componente analytics/page.tsx (async, searchParams): +```typescript +export default async function AnalyticsPage({ + searchParams, +}: { + searchParams: Promise<{ year?: string }>; +}) { + const { year: yearParam } = await searchParams; + const year = parseInt(yearParam ?? "") || new Date().getFullYear(); + ... +} +``` +La stessa logica `year` va aggiunta al componente AdminDashboard in admin/page.tsx. + + + + + + Task 1: Integra statistiche annuali nella Dashboard (CLEAN-03) + + + - src/app/admin/page.tsx — struttura attuale (KpiCard, FollowUpWidget, activity feed, fmtEur esistente) + - src/app/admin/analytics/page.tsx — tutto il contenuto da portare (già in contesto da discovery) + - src/components/admin/YearSelector.tsx — YearSelector e MonthlyChart (già in contesto da discovery) + + + + src/app/admin/page.tsx, + src/components/admin/YearSelector.tsx + + + + STEP 1 — Aggiorna AdminDashboard in src/app/admin/page.tsx: + + a) Aggiungi alla firma del componente il parametro searchParams (come in analytics/page.tsx): + ```typescript + export default async function AdminDashboard({ + searchParams, + }: { + searchParams: Promise<{ year?: string }>; + }) { + const { year: yearParam } = await searchParams; + const year = parseInt(yearParam ?? "") || new Date().getFullYear(); + ``` + + b) Aggiungi gli import mancanti in cima al file: + ```typescript + import { + getAnalyticsByYear, + getMonthlyCollected, + getAvailableYears, + getTimeByClient, + getTotalTrackedHours, + } from "@/lib/analytics-queries"; + import { YearSelector, MonthlyChart } from "@/components/admin/YearSelector"; + ``` + + c) Aggiungi le query analytics al Promise.all esistente (o crea un secondo await per separare + le query di diversa frequenza — è accettabile avere due await distinti per chiarezza): + ```typescript + const [data, monthly, availableYears, timeByClient, totalHours] = await Promise.all([ + getAnalyticsByYear(year), + getMonthlyCollected(year), + getAvailableYears(), + getTimeByClient(year), + getTotalTrackedHours(year), + ]); + ``` + + d) Copia la funzione MetricCard da analytics/page.tsx nel file (accanto a KpiCard). + + e) Risolvi il conflitto fmtEur: + - La versione attuale in admin/page.tsx accetta `string` e fa `parseFloat(val)`. + - Quella in analytics/page.tsx accetta `number`. + - Unifica in una sola funzione che accetta `number`, aggiorna i consumer esistenti + nel file che passavano una stringa (es. `fmtEur(kpi.revenueTotale)` e + `fmtEur(kpi.pagamentiInSospeso)`) convertendo a number dove necessario, + oppure mantieni entrambe con nomi distinti (`fmtEurStr` / `fmtEurNum`). + Scegli l'approccio più pulito senza rompere i KPI card esistenti. + + f) Aggiungi la sezione Statistiche DOPO il feed attività esistente (mantieni tutto quello + che c'era prima intatto — FollowUpWidget, KPI card, activity feed): + ```tsx + {/* ── SEZIONE STATISTICHE ANNUALI ── */} +
+
+
+

Statistiche

+

Panoramica per anno

+
+ +
+ + {/* Sezione economica */} +
+

Fatturato

+
+ + + + +
+ +
+ + {/* Sezione time tracking */} +
+

Tempo tracciato

+
+ +
+ {/* ... tabella ore per cliente (copia da analytics/page.tsx) ... */} +
+
+ ``` + Ricopia fedelmente il blocco "ore per cliente" da analytics/page.tsx (righe 127-160) + nella sezione time tracking della dashboard. + + Calcola collectedPct prima del return: + ```typescript + const collectedPct = data.contracted > 0 + ? Math.round((data.collected / data.contracted) * 100) : 0; + const maxClientSeconds = timeByClient[0]?.totalSeconds ?? 1; + ``` + + STEP 2 — Aggiorna YearSelector per navigare verso /admin: + In src/components/admin/YearSelector.tsx, riga ~18: + ```typescript + // PRIMA: + router.push(`/admin/analytics?year=${y}`); + // DOPO: + router.push(`/admin?year=${y}`); + ``` + + NON modificare: MonthlyChart (rimane nello stesso file), struttura esistente della dashboard + (FollowUpWidget, KPI card, activity feed — tutto invariato sopra la nuova sezione). +
+ + + + grep "getAnalyticsByYear\|getMonthlyCollected\|getAvailableYears" /Users/simonecavalli/Vault/IAMCAVALLI/src/app/admin/page.tsx | wc -l + + Risultato atteso: 3 (tutte e tre le query importate e usate). + + Verifica YearSelector: + grep "router.push" /Users/simonecavalli/Vault/IAMCAVALLI/src/components/admin/YearSelector.tsx + Risultato atteso: contiene "/admin?year=" e NON "/admin/analytics". + + + + - src/app/admin/page.tsx importa da @/lib/analytics-queries + - src/app/admin/page.tsx importa YearSelector e MonthlyChart + - YearSelector.tsx naviga a /admin?year=Y (non a /admin/analytics) + - Il file compila senza errori TypeScript + + + + La Dashboard mostra le statistiche annuali con selettore anno; il selettore naviga + correttamente a /admin?year=X. + +
+ + + Task 2: Elimina rotta /admin/analytics (CLEAN-03) + + + - src/app/admin/analytics/page.tsx — conferma che non è più necessario (Task 1 ha già portato + tutto il contenuto nella dashboard) + + + + src/app/admin/analytics/page.tsx + + + + 1. Verifica preventiva — assicurati che nessun altro file nel progetto importi da + src/app/admin/analytics/page.tsx direttamente (è una page, non un modulo, quindi + non dovrebbe avere consumer diretti — ma controlla): + grep -r "admin/analytics" src/ --include="*.tsx" --include="*.ts" + Se trovi riferimenti diversi da YearSelector (già aggiornato in Task 1), risolvili prima. + + 2. Elimina: + - src/app/admin/analytics/page.tsx + - Directory src/app/admin/analytics/ (se vuota dopo la rimozione del file) + + NON eliminare: lib/analytics-queries.ts (ancora importata dalla dashboard), + src/components/admin/YearSelector.tsx (ancora usata dalla dashboard). + + + + + test -f /Users/simonecavalli/Vault/IAMCAVALLI/src/app/admin/analytics/page.tsx && echo "ESISTE_ANCORA" || echo "OK_RIMOSSO" + + Risultato atteso: OK_RIMOSSO + + Verifica nessun riferimento rimasto: + grep -r "admin/analytics" /Users/simonecavalli/Vault/IAMCAVALLI/src --include="*.tsx" --include="*.ts" | grep -v "node_modules" | grep -v ".next" + Risultato atteso: 0 righe. + + + + - src/app/admin/analytics/page.tsx non esiste più + - grep -r "admin/analytics" src/ produce 0 risultati + - npm run build completa senza errori + + + + La rotta /admin/analytics è eliminata. Navigarci restituisce 404. + Tutte le statistiche sono accessibili alla Dashboard /admin. + + + +
+ + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| admin/page.tsx → analytics-queries | Aggiunta di query server-side già esistenti — nessuna nuova superficie | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-18-03 | Information Disclosure | admin/page.tsx | accept | Le statistiche erano già accessibili a /admin/analytics — stessa autenticazione Auth.js, nessuna nuova esposizione | +| T-18-04 | Tampering | YearSelector.tsx | accept | Il cambio da /admin/analytics a /admin nella navigazione è una semplice redirect di path — nessun dato mutato | + + + +Al termine del piano: +1. `npm run build` completa senza errori TypeScript +2. `grep -r "admin/analytics" src/` → 0 risultati +3. La Dashboard /admin mostra le sezioni Statistiche con selettore anno +4. Navigare a /admin/analytics restituisce 404 +5. YearSelector porta a /admin?year=X quando si cambia anno + + + +- CLEAN-03: /admin mostra le statistiche annuali (MetricCard + MonthlyChart + time tracking) +- /admin/analytics → 404 (rotta eliminata) +- YearSelector naviga a /admin?year=X +- Build TypeScript pulita + + + +After completion, create `.planning/phases/18-cleanup-consolidamento/18-02-SUMMARY.md` + diff --git a/.planning/phases/18-cleanup-consolidamento/18-03-PLAN.md b/.planning/phases/18-cleanup-consolidamento/18-03-PLAN.md new file mode 100644 index 0000000..2b9920d --- /dev/null +++ b/.planning/phases/18-cleanup-consolidamento/18-03-PLAN.md @@ -0,0 +1,197 @@ +--- +phase: 18-cleanup-consolidamento +plan: 03 +type: execute +wave: 2 +depends_on: + - "18-01" + - "18-02" +autonomous: false +files_modified: + - .planning/ROADMAP.md + - .planning/REQUIREMENTS.md +requirements: + - CLEAN-04 + +must_haves: + truths: + - "Le fasi 13/15/16/17 sono marcate esplicitamente come cancellate/congelate/ri-scopate nel ROADMAP.md" + - "REQUIREMENTS.md riflette lo stato aggiornato dei requirement corrispondenti" + - "CLEAN-04 è marcato Done in REQUIREMENTS.md" + - "La build del progetto passa dopo le rimozioni dei piani precedenti" + artifacts: + - path: ".planning/ROADMAP.md" + provides: "Fasi 13/15/16/17 con status esplicito cancellate/congelate" + contains: "CONGELATA\|ABBANDONATA\|RI-SCOPATA" + - path: ".planning/REQUIREMENTS.md" + provides: "CLEAN-04 marcato Complete" + key_links: + - from: "ROADMAP.md fasi 13/15/16/17" + to: "STATUS field" + via: "checklist e label espliciti" + pattern: "Congelata|Abbandonata|Ri-scopata" +--- + + +Verificare formalmente il completamento di CLEAN-04 e validare la build post-cleanup. + +Purpose: CLEAN-04 — le fasi v2.1 residue sono già state archiviate/marcate nel reset 2026-06-19. +Questo piano le verifica, le sigla formalmente nel planning e valida che i piani 01/02 +non abbiano introdotto errori di build. +Output: CLEAN-04 marcato Done, build TypeScript verificata, check umano che la dashboard funziona. + + + +@$HOME/.claude/get-shit-done/workflows/execute-plan.md +@$HOME/.claude/get-shit-done/templates/summary.md + + + +@.planning/ROADMAP.md +@.planning/REQUIREMENTS.md +@.planning/STATE.md + + + + + + Task 1: Verifica CLEAN-04 e aggiorna planning docs + + + - .planning/ROADMAP.md — sezione fasi 13/15/16/17, verifica che abbiano label/status esplicito + - .planning/REQUIREMENTS.md — sezione CLEAN-04, verifica stato attuale + + + + .planning/ROADMAP.md, + .planning/REQUIREMENTS.md + + + + STEP 1 — Verifica ROADMAP.md: + Leggi le voci delle fasi 13, 15, 16, 17 nel ROADMAP.md. + Devono avere tutte uno status esplicito. Controlla che la checklist mostri: + - Phase 13: [~] con label "❌ CONGELATA (reset 2026-06-19)" + - Phase 15: [~] con label "❌ ABBANDONATA (reset 2026-06-19)" + - Phase 16: [~] con label "❌ RI-SCOPATA in v2.2" + - Phase 17: [~] con label "❌ RI-SCOPATA in v2.2" + Se uno di questi status manca o è incompleto, aggiungilo/completalo. + Aggiungi anche una nota nella tabella Progress in fondo con la data di chiusura 2026-06-19 + dove mancante. + + STEP 2 — Aggiorna REQUIREMENTS.md: + Nella tabella "Cleanup & Consolidamento (Phase 18 / R1)": + - CLEAN-01: cambia Status da "Pending" a "Complete" + - CLEAN-02: cambia Status da "Pending" a "Complete" + - CLEAN-03: cambia Status da "Pending" a "Complete" + - CLEAN-04: cambia Status da "In corso (questo reset)" a "Complete" + + Nella tabella Traceability in fondo: + - CLEAN-01 | Phase 18 (R1) | Complete + - CLEAN-02 | Phase 18 (R1) | Complete + - CLEAN-03 | Phase 18 (R1) | Complete + - CLEAN-04 | Phase 18 (R1) | Complete + + STEP 3 — Build verification: + Esegui: cd /Users/simonecavalli/Vault/IAMCAVALLI && npm run build + Se la build fallisce: + - Leggi l'output dell'errore + - Identifica il file con import rotto + - Risolvi (probabilmente un import di componente eliminato o una funzione non trovata) + - Ri-esegui npm run build fino a successo + Registra nel SUMMARY se ci sono stati fix necessari. + + + + + grep "CLEAN-04" /Users/simonecavalli/Vault/IAMCAVALLI/.planning/REQUIREMENTS.md + + Risultato atteso: riga contenente "CLEAN-04" e "Complete". + + Verifica fasi archiviate: + grep -E "Phase 13|Phase 15|Phase 16|Phase 17" /Users/simonecavalli/Vault/IAMCAVALLI/.planning/ROADMAP.md | grep -E "CONGELATA|ABBANDONATA|RI-SCOPATA" | wc -l + Risultato atteso: 4 (tutte e quattro le fasi con label esplicito). + + + + - REQUIREMENTS.md: CLEAN-04 è "Complete" + - REQUIREMENTS.md: CLEAN-01, CLEAN-02, CLEAN-03 sono "Complete" + - ROADMAP.md: fasi 13/15/16/17 hanno label di stato esplicito (CONGELATA/ABBANDONATA/RI-SCOPATA) + - npm run build completa senza errori + + + + Tutti i requisiti CLEAN-01..04 sono marcati Complete nei planning docs. + La build TypeScript è pulita. Phase 18 è formalmente chiusa. + + + + + Checkpoint: Verifica visuale Dashboard e assenza rotte rimosse + + + Piano 01 ha rimosso /admin/forecast e /admin/quotes/new. + Piano 02 ha fuso le statistiche di /admin/analytics nella Dashboard /admin + e rimosso la rotta /admin/analytics. + Il selettore anno nella dashboard naviga a /admin?year=X. + + + + 1. Avvia il dev server: `npm run dev` (o `npx next dev`) + 2. Vai su http://localhost:3000/admin — verifica: + - Sidebar: NON compare la voce "Forecast" + - Dashboard: in fondo alla pagina compare la sezione "Statistiche" con selettore anno, + MetricCard economiche (Contrattualizzato / Incassato / Da incassare / Clienti acquisiti), + grafico mensile a barre, sezione ore per cliente + - KPI card esistenti (Clienti attivi, Revenue totale, Progetti in corso, Pagamenti in sospeso) + sono ancora presenti in cima + - FollowUpWidget e feed attività sono ancora presenti + 3. Vai su http://localhost:3000/admin/forecast → deve restituire 404 + 4. Vai su http://localhost:3000/admin/analytics → deve restituire 404 + 5. Vai su http://localhost:3000/admin/quotes/new → deve restituire 404 + 6. Clicca sul selettore anno nella sezione Statistiche → cambia anno e verifica che + l'URL diventa /admin?year=XXXX (non /admin/analytics) + 7. Nel dettaglio di un lead, apri il modal "Invia preventivo" → verifica che NON + compare più il bottone per creare un nuovo preventivo manuale + + + + Scrivi "ok" se tutto funziona correttamente. + Se trovi problemi, descrivi cosa non funziona e l'esecuzione correggerà prima di chiudere la fase. + + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| planning docs → stato del progetto | Aggiornamento documenti di tracking — nessuna superficie di attacco | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-18-05 | Repudiation | ROADMAP.md / REQUIREMENTS.md | accept | I planning docs sono in git — ogni modifica è tracciata e reversibile | + + + +Al termine del piano: +1. REQUIREMENTS.md: CLEAN-01, CLEAN-02, CLEAN-03, CLEAN-04 → tutti "Complete" +2. ROADMAP.md: fasi 13/15/16/17 con status esplicito +3. npm run build → 0 errori +4. Checkpoint umano superato (Dashboard mostra statistiche, rotte rimosse → 404) + + + +- CLEAN-04: fasi v2.1 residue formalmente chiuse nei planning docs +- Planning docs aggiornati con stati finali Phase 18 +- Build pulita confermata +- Verifica visuale umana completata + + + +After completion, create `.planning/phases/18-cleanup-consolidamento/18-03-SUMMARY.md` +