docs(phase-18): create phase plan — cleanup & consolidamento

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 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 11:51:03 +02:00
parent 10a390239a
commit b3670d164b
4 changed files with 791 additions and 11 deletions
@@ -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"
---
<objective>
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.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
</context>
<tasks>
<task type="auto">
<name>Task 1: Rimuovi rotta Forecast — file, sidebar, revalidatePath (CLEAN-01)</name>
<read_first>
- 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")
</read_first>
<files>
src/components/admin/AdminSidebar.tsx,
src/app/admin/projects/project-actions.ts
</files>
<action>
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.
</action>
<verify>
<automated>
grep -r "admin/forecast" /Users/simonecavalli/Vault/IAMCAVALLI/src --include="*.tsx" --include="*.ts" | grep -v "node_modules" | grep -v ".next" | wc -l
</automated>
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).
</verify>
<acceptance_criteria>
- 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")
</acceptance_criteria>
<done>
La voce Forecast è assente dalla sidebar, la rotta /admin/forecast è 404, nessun server action
chiama revalidatePath su quella rotta.
</done>
</task>
<task type="auto">
<name>Task 2: Rimuovi rotta Quote Builder manuale e il suo entry point (CLEAN-02)</name>
<read_first>
- 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
</read_first>
<files>
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
</files>
<action>
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.
</action>
<verify>
<automated>
grep -r "quotes/new" /Users/simonecavalli/Vault/IAMCAVALLI/src --include="*.tsx" --include="*.ts" | grep -v "node_modules" | grep -v ".next" | wc -l
</automated>
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.
</verify>
<acceptance_criteria>
- 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"
</acceptance_criteria>
<done>
La rotta /admin/quotes/new è 404, il pulsante di navigazione nel SendQuoteModal è rimosso,
i componenti esclusivi del quote builder sono eliminati.
</done>
</task>
</tasks>
<threat_model>
## 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 |
</threat_model>
<verification>
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"
</verification>
<success_criteria>
- 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)
</success_criteria>
<output>
After completion, create `.planning/phases/18-cleanup-consolidamento/18-01-SUMMARY.md`
</output>
@@ -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"
---
<objective>
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.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
</context>
<interfaces>
<!-- Estratto da src/app/admin/analytics/page.tsx — contratti da portare nella dashboard -->
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.
</interfaces>
<tasks>
<task type="auto">
<name>Task 1: Integra statistiche annuali nella Dashboard (CLEAN-03)</name>
<read_first>
- 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)
</read_first>
<files>
src/app/admin/page.tsx,
src/components/admin/YearSelector.tsx
</files>
<action>
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 ── */}
<div className="mt-10 space-y-10">
<div className="flex items-center justify-between">
<div>
<h2 className="text-xl font-bold text-gray-900">Statistiche</h2>
<p className="text-sm text-gray-400 mt-0.5">Panoramica per anno</p>
</div>
<YearSelector currentYear={year} availableYears={availableYears} />
</div>
{/* Sezione economica */}
<div className="space-y-4">
<h3 className="text-sm font-bold text-[#71717a] uppercase tracking-wider">Fatturato</h3>
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
<MetricCard label="Contrattualizzato" value={fmtEur(data.contracted)}
sub={`${data.clientsAcquired} client${data.clientsAcquired === 1 ? "e" : "i"}`} accent />
<MetricCard label="Incassato" value={fmtEur(data.collected)}
sub={`${collectedPct}% del contrattualizzato`} />
<MetricCard label="Da incassare" value={fmtEur(data.pending)} sub="Tutti gli anni" />
<MetricCard label="Clienti acquisiti" value={String(data.clientsAcquired)} sub={`Anno ${year}`} />
</div>
<MonthlyChart data={monthly} year={year} />
</div>
{/* Sezione time tracking */}
<div className="space-y-4">
<h3 className="text-sm font-bold text-[#71717a] uppercase tracking-wider">Tempo tracciato</h3>
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
<MetricCard label="Ore totali" value={`${totalHours}h`} sub={`Anno ${year}`} accent />
</div>
{/* ... tabella ore per cliente (copia da analytics/page.tsx) ... */}
</div>
</div>
```
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).
</action>
<verify>
<automated>
grep "getAnalyticsByYear\|getMonthlyCollected\|getAvailableYears" /Users/simonecavalli/Vault/IAMCAVALLI/src/app/admin/page.tsx | wc -l
</automated>
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".
</verify>
<acceptance_criteria>
- 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
</acceptance_criteria>
<done>
La Dashboard mostra le statistiche annuali con selettore anno; il selettore naviga
correttamente a /admin?year=X.
</done>
</task>
<task type="auto">
<name>Task 2: Elimina rotta /admin/analytics (CLEAN-03)</name>
<read_first>
- src/app/admin/analytics/page.tsx — conferma che non è più necessario (Task 1 ha già portato
tutto il contenuto nella dashboard)
</read_first>
<files>
src/app/admin/analytics/page.tsx
</files>
<action>
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).
</action>
<verify>
<automated>
test -f /Users/simonecavalli/Vault/IAMCAVALLI/src/app/admin/analytics/page.tsx && echo "ESISTE_ANCORA" || echo "OK_RIMOSSO"
</automated>
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.
</verify>
<acceptance_criteria>
- src/app/admin/analytics/page.tsx non esiste più
- grep -r "admin/analytics" src/ produce 0 risultati
- npm run build completa senza errori
</acceptance_criteria>
<done>
La rotta /admin/analytics è eliminata. Navigarci restituisce 404.
Tutte le statistiche sono accessibili alla Dashboard /admin.
</done>
</task>
</tasks>
<threat_model>
## 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 |
</threat_model>
<verification>
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
</verification>
<success_criteria>
- 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
</success_criteria>
<output>
After completion, create `.planning/phases/18-cleanup-consolidamento/18-02-SUMMARY.md`
</output>
@@ -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"
---
<objective>
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.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/ROADMAP.md
@.planning/REQUIREMENTS.md
@.planning/STATE.md
</context>
<tasks>
<task type="auto">
<name>Task 1: Verifica CLEAN-04 e aggiorna planning docs</name>
<read_first>
- .planning/ROADMAP.md — sezione fasi 13/15/16/17, verifica che abbiano label/status esplicito
- .planning/REQUIREMENTS.md — sezione CLEAN-04, verifica stato attuale
</read_first>
<files>
.planning/ROADMAP.md,
.planning/REQUIREMENTS.md
</files>
<action>
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.
</action>
<verify>
<automated>
grep "CLEAN-04" /Users/simonecavalli/Vault/IAMCAVALLI/.planning/REQUIREMENTS.md
</automated>
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).
</verify>
<acceptance_criteria>
- 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
</acceptance_criteria>
<done>
Tutti i requisiti CLEAN-01..04 sono marcati Complete nei planning docs.
La build TypeScript è pulita. Phase 18 è formalmente chiusa.
</done>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<name>Checkpoint: Verifica visuale Dashboard e assenza rotte rimosse</name>
<what-built>
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.
</what-built>
<how-to-verify>
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
</how-to-verify>
<resume-signal>
Scrivi "ok" se tutto funziona correttamente.
Se trovi problemi, descrivi cosa non funziona e l'esecuzione correggerà prima di chiudere la fase.
</resume-signal>
</task>
</tasks>
<threat_model>
## 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 |
</threat_model>
<verification>
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)
</verification>
<success_criteria>
- 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
</success_criteria>
<output>
After completion, create `.planning/phases/18-cleanup-consolidamento/18-03-SUMMARY.md`
</output>