docs(planning): archivia v2.1/v2.2/v2.3 e documenta v2.4
.planning/ documentava in dettaglio cio che era vecchio e per niente cio
che e in produzione: le fasi 11-22 (v2.1 e v2.2, chiuse a giugno) erano
ancora in phases/ mentre v1.0 e v2.0 stavano gia in milestones/, e il
lavoro degli ultimi due mesi - gate OTP e ciclo di vita dei retainer, cioe
quello che gira su hub.iamcavalli.net - non aveva nessuna cartella.
- phases/{11,12,14} -> milestones/v2.1-phases/, phases/{18..22} ->
milestones/v2.2-phases/. Ora phases/ contiene solo la milestone in
corso, che e quello che state.cjs conta per il progresso
- v2.1-ROADMAP.md ricostruito: era l'unica milestone senza archivio,
interrotta dal reset del 19/06 e mai chiusa formalmente
- v2.3-ROADMAP.md + v2.3-REQUIREMENTS.md: v2.3 e stata eseguita fuori dal
ciclo GSD, non esistono PLAN/SUMMARY per fase. L'archivio E la doc
- REQUIREMENTS.md riscritto per v2.4 con il backlog reale
- phases/13 e phases/26: SUMMARY ricostruiti da commit, migration e
STATUS.md. 26 e il primo numero libero
- research/: cancellate 4 varianti dello stesso PITFALLS e FEATURES/
SUMMARY, superati da PROJECT.md. Diverse anti-feature erano ormai
contraddette dai fatti (il Kanban e stato costruito in Phase 19,
l'email in v2.3, il time tracking esiste)
- cancellati UI-RULES.md e DESIGN-SYSTEM.md (CLAUDE.md li dichiara
superseded: impongono l'inverso della regola attuale) e HANDOFF.md,
fermo al 13/06
- SECURITY-*.md -> security/: audit chiuso, ma i report restano la doc di
cosa e stato ruotato e perche
- PROJECT.md/MILESTONES.md/ROADMAP.md allineati: milestone corrente v2.4,
sessione OTP 90gg non 30, migrazioni fino alla 0016
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -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,156 @@
|
||||
---
|
||||
phase: 18-cleanup-consolidamento
|
||||
plan: "01"
|
||||
subsystem: ui
|
||||
tags: [next.js, admin, cleanup, sidebar, server-actions]
|
||||
|
||||
requires: []
|
||||
provides:
|
||||
- Forecast route removed (/admin/forecast → 404)
|
||||
- Admin sidebar without Forecast entry
|
||||
- project-actions.ts without revalidatePath forecast calls
|
||||
- Quote builder route removed (/admin/quotes/new → 404)
|
||||
- SendQuoteModal without navigation to quotes/new
|
||||
- QuoteBuilderForm, OfferSelector, PriceOverrideInput, QuotePreview components deleted
|
||||
affects: [phase-21-ai-quote-agent, any future admin nav changes]
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Dead-code deletion: remove page files + directories + all entry points atomically before Sales Loop phase"
|
||||
|
||||
key-files:
|
||||
created: []
|
||||
modified:
|
||||
- src/components/admin/AdminSidebar.tsx
|
||||
- src/app/admin/projects/project-actions.ts
|
||||
- src/components/admin/leads/SendQuoteModal.tsx
|
||||
- src/lib/admin-queries.ts
|
||||
deleted:
|
||||
- src/app/admin/forecast/page.tsx
|
||||
- src/app/admin/quotes/new/page.tsx
|
||||
- src/app/admin/quotes/new/actions.ts
|
||||
- src/components/admin/quotes/QuoteBuilderForm.tsx
|
||||
- src/components/admin/quotes/OfferSelector.tsx
|
||||
- src/components/admin/quotes/PriceOverrideInput.tsx
|
||||
- src/components/admin/quotes/QuotePreview.tsx
|
||||
|
||||
key-decisions:
|
||||
- "Kept lib/forecast-queries.ts and lib/quote-actions.ts as tolerable deadweight — no broken imports, no consumer"
|
||||
- "SendQuoteModal Tabs UI replaced with flat single-form layout (only 'existing' flow remains)"
|
||||
- "quotes/new/actions.ts (re-export shim) deleted along with page since its only consumer was QuoteBuilderForm"
|
||||
- "Stale JSDoc comment in admin-queries.ts referencing /admin/quotes/new cleaned up (Rule 1 auto-fix)"
|
||||
|
||||
patterns-established:
|
||||
- "Cleanup tasks: always grep for all entry points (revalidatePath, navigation, JSDoc) before marking done"
|
||||
|
||||
requirements-completed: [CLEAN-01, CLEAN-02]
|
||||
|
||||
duration: 12min
|
||||
completed: 2026-06-19
|
||||
---
|
||||
|
||||
# Phase 18 Plan 01: Cleanup — Remove Forecast and Manual Quote Builder Routes Summary
|
||||
|
||||
**Deleted /admin/forecast and /admin/quotes/new routes with all entry points (sidebar, revalidatePath, navigation button, exclusive components) to clear the codebase for the Sales Loop AI phase.**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** ~12 min
|
||||
- **Started:** 2026-06-19T10:04:00Z
|
||||
- **Completed:** 2026-06-19T10:16:00Z
|
||||
- **Tasks:** 2
|
||||
- **Files modified/deleted:** 11
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- Removed Forecast route: deleted `src/app/admin/forecast/page.tsx`, removed sidebar nav entry and `TrendingUp` import, stripped 3 `revalidatePath("/admin/forecast")` calls from project-actions.ts
|
||||
- Removed Quote Builder route: deleted `quotes/new/page.tsx`, `quotes/new/actions.ts`, and all 4 exclusive components (QuoteBuilderForm, OfferSelector, PriceOverrideInput, QuotePreview)
|
||||
- Simplified SendQuoteModal from two-tab layout to single flat form — "Crea Nuovo" tab and `window.location` navigation removed entirely; "existing quote" flow unchanged
|
||||
- Build passes clean: 0 TypeScript errors, 0 broken imports
|
||||
|
||||
## Task Commits
|
||||
|
||||
1. **Task 1: Rimuovi rotta Forecast** - `7d88409` (chore)
|
||||
2. **Task 2: Rimuovi rotta Quote Builder** - `268f56c` (chore)
|
||||
|
||||
**Plan metadata:** (see final commit below)
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `src/components/admin/AdminSidebar.tsx` - Removed Forecast NAV_ITEMS entry and TrendingUp import
|
||||
- `src/app/admin/projects/project-actions.ts` - Removed 3 revalidatePath("/admin/forecast") calls
|
||||
- `src/components/admin/leads/SendQuoteModal.tsx` - Removed "Crea Nuovo" tab and quotes/new navigation
|
||||
- `src/lib/admin-queries.ts` - Removed stale JSDoc comment referencing /admin/quotes/new
|
||||
|
||||
**Deleted:**
|
||||
- `src/app/admin/forecast/page.tsx`
|
||||
- `src/app/admin/quotes/new/page.tsx`
|
||||
- `src/app/admin/quotes/new/actions.ts`
|
||||
- `src/components/admin/quotes/QuoteBuilderForm.tsx`
|
||||
- `src/components/admin/quotes/OfferSelector.tsx`
|
||||
- `src/components/admin/quotes/PriceOverrideInput.tsx`
|
||||
- `src/components/admin/quotes/QuotePreview.tsx`
|
||||
|
||||
## Decisions Made
|
||||
|
||||
- Kept `lib/forecast-queries.ts` and `lib/quote-actions.ts` intact — they have no broken imports and are tolerable deadweight; removing them was explicitly out of scope per the plan
|
||||
- Deleted `quotes/new/actions.ts` (not listed in plan) because it was a server re-export shim with `QuoteBuilderForm` as its only consumer — Rule 3 auto-fix (would have blocked clean directory removal)
|
||||
- Stale JSDoc comment in `admin-queries.ts` updated — Rule 1 auto-fix (stale reference counts as dead code)
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 1 - Bug] Removed stale JSDoc comment referencing deleted route**
|
||||
- **Found during:** Task 2 (final grep verification)
|
||||
- **Issue:** `admin-queries.ts` line 862 had a `* Used by: /admin/quotes/new form (OfferSelector dropdown)` comment — the route no longer exists
|
||||
- **Fix:** Removed the stale line from the JSDoc block
|
||||
- **Files modified:** src/lib/admin-queries.ts
|
||||
- **Verification:** `grep -r "quotes/new" src/` → 0 results
|
||||
- **Committed in:** 268f56c (Task 2 commit)
|
||||
|
||||
**2. [Rule 3 - Blocking] Deleted quotes/new/actions.ts (unlisted file)**
|
||||
- **Found during:** Task 2 — directory was non-empty after deleting page.tsx
|
||||
- **Issue:** `src/app/admin/quotes/new/actions.ts` was a re-export shim (`export { createQuote } from "@/lib/quote-actions"`) with QuoteBuilderForm as its only consumer. It would leave a broken directory if not removed.
|
||||
- **Fix:** Confirmed no other consumers via grep, then deleted the file
|
||||
- **Files modified:** src/app/admin/quotes/new/actions.ts (deleted)
|
||||
- **Verification:** `grep -r "createQuote" src/` shows only lib/quote-actions.ts (the source) — no broken references
|
||||
- **Committed in:** 268f56c (Task 2 commit)
|
||||
|
||||
---
|
||||
|
||||
**Total deviations:** 2 auto-fixed (1 Rule 1 stale comment, 1 Rule 3 blocking unlisted file)
|
||||
**Impact on plan:** Both auto-fixes necessary for completeness and clean directory state. No scope creep.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
- A linter hook reverted `SendQuoteModal.tsx` after the first Write. On re-read, the linter had actually applied the intended changes (removed Tabs imports, removed tab state, flattened to single form). Confirmed the file was correct before staging.
|
||||
|
||||
## User Setup Required
|
||||
|
||||
None — no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
- CLEAN-01 and CLEAN-02 complete: codebase is clear of forecast and manual quote builder dead routes
|
||||
- Ready for Phase 21 (AI Quote Agent) which will provide the replacement quote creation flow
|
||||
- `lib/forecast-queries.ts` and `lib/quote-actions.ts` remain as inert deadweight — can be cleaned in a future pass if desired
|
||||
|
||||
---
|
||||
*Phase: 18-cleanup-consolidamento*
|
||||
*Completed: 2026-06-19*
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- `src/components/admin/AdminSidebar.tsx` — FOUND (modified)
|
||||
- `src/app/admin/projects/project-actions.ts` — FOUND (modified)
|
||||
- `src/components/admin/leads/SendQuoteModal.tsx` — FOUND (modified)
|
||||
- `src/lib/admin-queries.ts` — FOUND (modified)
|
||||
- `src/app/admin/forecast/page.tsx` — MISSING (deleted as intended)
|
||||
- `src/app/admin/quotes/new/page.tsx` — MISSING (deleted as intended)
|
||||
- Commit 7d88409 — FOUND
|
||||
- Commit 268f56c — FOUND
|
||||
- `grep -r "admin/forecast" src/` → 0 results
|
||||
- `grep -r "quotes/new" src/` → 0 results
|
||||
- Build: 0 errors
|
||||
@@ -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,113 @@
|
||||
---
|
||||
phase: 18-cleanup-consolidamento
|
||||
plan: "02"
|
||||
subsystem: ui
|
||||
tags: [nextjs, analytics, dashboard, react, tailwind]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: analytics-queries
|
||||
provides: getAnalyticsByYear, getMonthlyCollected, getAvailableYears, getTimeByClient, getTotalTrackedHours
|
||||
provides:
|
||||
- Admin dashboard at /admin integrates annual statistics (MetricCard, MonthlyChart, time tracking per client)
|
||||
- /admin/analytics route deleted — returns 404
|
||||
- YearSelector navigates to /admin?year=Y
|
||||
affects: [18-cleanup-consolidamento, admin-ui, analytics]
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- Server page accepts searchParams for year filtering
|
||||
- Analytics queries co-located with dashboard queries in same async page
|
||||
|
||||
key-files:
|
||||
created: []
|
||||
modified:
|
||||
- src/app/admin/page.tsx
|
||||
- src/components/admin/YearSelector.tsx
|
||||
deleted:
|
||||
- src/app/admin/analytics/page.tsx
|
||||
|
||||
key-decisions:
|
||||
- "Unified fmtEur to accept number (analytics version); KPI card callers wrapped with parseFloat() for string DB values"
|
||||
- "Two separate awaits in AdminDashboard: getDashboardStats() first, then analytics Promise.all — acceptable for clarity"
|
||||
- "Stale .next cache (OfferSelector.tsx reference) cleared before final build — pre-existing issue, not introduced by this plan"
|
||||
|
||||
patterns-established:
|
||||
- "Statistics section appended after activity feed — existing dashboard structure preserved above new section"
|
||||
|
||||
requirements-completed:
|
||||
- CLEAN-03
|
||||
|
||||
# Metrics
|
||||
duration: 15min
|
||||
completed: 2026-06-19
|
||||
---
|
||||
|
||||
# Phase 18 Plan 02: Consolidate Analytics Dashboard Summary
|
||||
|
||||
**Merged /admin/analytics statistics (MetricCard, MonthlyChart, per-client time tracking) into /admin dashboard and deleted the duplicate route**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** ~15 min
|
||||
- **Started:** 2026-06-19T10:04:00Z
|
||||
- **Completed:** 2026-06-19T10:19:00Z
|
||||
- **Tasks:** 2
|
||||
- **Files modified:** 3 (2 modified, 1 deleted)
|
||||
|
||||
## Accomplishments
|
||||
- AdminDashboard now shows annual statistics section below activity feed: MetricCard economic metrics, MonthlyChart, and per-client time tracking bars
|
||||
- /admin/analytics route deleted — navigating there returns 404
|
||||
- YearSelector updated to navigate to /admin?year=Y instead of /admin/analytics?year=Y
|
||||
- fmtEur unified to number-accepting version (more robust); existing KPI card string values wrapped with parseFloat()
|
||||
|
||||
## Task Commits
|
||||
|
||||
1. **Task 1: Integra statistiche annuali nella Dashboard** — included in `14bdbab` (feat)
|
||||
2. **Task 2: Elimina rotta /admin/analytics** — included in `14bdbab` (feat)
|
||||
|
||||
**Plan metadata:** (docs commit below)
|
||||
|
||||
## Files Created/Modified
|
||||
- `src/app/admin/page.tsx` — Added analytics imports, searchParams, analytics queries, MetricCard, fmtSeconds, fmtEur(number), statistics section
|
||||
- `src/components/admin/YearSelector.tsx` — Updated router.push from /admin/analytics to /admin
|
||||
- `src/app/admin/analytics/page.tsx` — Deleted
|
||||
|
||||
## Decisions Made
|
||||
- Unified `fmtEur` to the `number` version from analytics (cleaner, no `parseFloat` internally). Updated the two KPI card callers that received string values from DB to pass `parseFloat(kpi.revenueTotale)` and `parseFloat(kpi.pagamentiInSospeso)`.
|
||||
- Used two sequential awaits (getDashboardStats first, then analytics Promise.all) rather than one large combined Promise.all — avoids mixing query concerns and follows plan guidance for acceptable two-await pattern.
|
||||
- Preserved all existing dashboard content (FollowUpWidget, KPI cards, activity feed) exactly; statistics section appended at the bottom with `mt-10`.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 3 - Blocking] Cleared stale .next cache referencing deleted OfferSelector.tsx**
|
||||
- **Found during:** Build verification after Task 2
|
||||
- **Issue:** Stale `.next/tsconfig.tsbuildinfo` incremental cache listed `src/components/admin/quotes/OfferSelector.tsx` as a root file. That file had been deleted in a prior session. TypeScript errored with "File not found — root file specified for compilation." The pre-existing cache was masking this because prior builds hit cached output.
|
||||
- **Fix:** Ran `rm -rf .next` to clear the stale incremental cache, then rebuilt clean.
|
||||
- **Files modified:** .next/ (cache only — not tracked in git)
|
||||
- **Verification:** Clean build passes with TypeScript check and all routes compiled correctly.
|
||||
- **Committed in:** n/a (cache not committed)
|
||||
|
||||
---
|
||||
|
||||
**Total deviations:** 1 auto-fixed (Rule 3 - blocking)
|
||||
**Impact on plan:** Required to get a clean build. Pre-existing issue unrelated to this plan's scope. .next/ is gitignored so no source changes.
|
||||
|
||||
## Issues Encountered
|
||||
- Stale `.next` incremental TypeScript cache referenced `OfferSelector.tsx` (deleted in a prior session). Cleared cache, rebuilt clean. Build passes correctly.
|
||||
|
||||
## User Setup Required
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
- /admin is the single analytics entry point — ready for 18-03 and any future admin UI work
|
||||
- No stale routes remain in the analytics path
|
||||
- Build is clean
|
||||
|
||||
---
|
||||
*Phase: 18-cleanup-consolidamento*
|
||||
*Completed: 2026-06-19*
|
||||
@@ -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>
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
plan: 18-03
|
||||
status: complete
|
||||
completed_at: 2026-06-19
|
||||
---
|
||||
|
||||
# Plan 18-03 Summary — Cleanup Verification & Planning Docs
|
||||
|
||||
## Tasks completed
|
||||
|
||||
**Task 1 (auto):**
|
||||
- REQUIREMENTS.md: CLEAN-01, CLEAN-02, CLEAN-03, CLEAN-04 → Complete (requirements table + traceability table)
|
||||
- ROADMAP.md: fasi 13/15/16/17 già avevano label espliciti da reset 2026-06-19 (CONGELATA/ABBANDONATA/RI-SCOPATA)
|
||||
- Build: `npm run build` → 0 errori, 0 warning. Route /admin/forecast, /admin/analytics, /admin/quotes/new assenti dalla route list.
|
||||
|
||||
**Task 2 (checkpoint umano):**
|
||||
- Verifica visuale superata dall'utente dopo deploy su Coolify.
|
||||
- Dashboard /admin mostra statistiche con MetricCard e grafico mensile.
|
||||
- Rotte rimosse restituiscono 404.
|
||||
- Selettore anno naviga a /admin?year=X.
|
||||
- SendQuoteModal senza bottone preventivo manuale.
|
||||
|
||||
## Files modified
|
||||
- `.planning/REQUIREMENTS.md` — CLEAN-01..04 marcati Complete
|
||||
|
||||
## Deviations
|
||||
Nessuna.
|
||||
Reference in New Issue
Block a user