9.9 KiB
Phase 4: Progetti — Multi-Project per Cliente - Context
Gathered: 2026-05-20 Status: Ready for planning
## Phase BoundaryRistrutturazione del modello dati per supportare N progetti per cliente. Un cliente può avere più brand/progetti; ogni progetto ha il proprio workspace (fasi, task, pagamenti, preventivo, timer). Il timer si sposta dal livello cliente al livello progetto. La dashboard cliente mostra i suoi progetti con tabs se multipli. Il link cliente diventa personalizzabile tramite slug opzionale.
Sostituisce la Fase 4 AI Onboarding (spostata a Fase 5) perché è prerequisito architetturale per tutto ciò che viene dopo.
Tutti i dati attuali sono di test — nessuna migrazione soft necessaria. Schema ricreato da zero dove serve.
## Implementation DecisionsModello dati
- D-01: Nuova tabella
projectscon campi:id,client_id(FK → clients),name(nome brand/progetto),archived(bool),created_at. Nessunaccepted_totaldiretto — viene calcolato/denormalizzato dai quote_items a livello progetto. - D-02: Le seguenti tabelle spostano la FK da
client_idaproject_id:phases,payments,quote_items,time_entries,documents,notes. La tabellacommentsrimane suentity_idgenerico — invariata. - D-03:
clientsperde i campi che diventano di pertinenza del progetto:accepted_totalsi sposta suprojects. Il cliente mantiene:id,name,brand_name(riutilizzato come nome display),token,slug(nuovo),archived,created_at. - D-04: Campo
slugaggiunto aclients— testo opzionale, univoco, URL-safe (es.mario-rossi). Se assente, il link usa il token random come prima. URL:/c/[slug-o-token]. - D-05:
projects.accepted_total(text, nullable) — denormalizzato come ora su clients, ma al livello progetto. L'admin lo imposta manualmente nel tab Preventivo del progetto.
Link e accesso cliente
- D-06: Il token rimane su
clientsper l'autenticazione middleware — non è il campo slug. Il middleware controlla prima lo slug (lookup DB), poi il token (come ora). Entrambi portano alla dashboard del cliente. - D-07: Lo slug si imposta nella pagina
/admin/clients/[id]/edit— campo opzionale con preview del link risultante. - D-08: La route
/c/[token-or-slug]rimane invariata nel path — il middleware risolve entrambi.
Dashboard cliente (frontend)
- D-09: Se il cliente ha 1 progetto → la dashboard mostra direttamente quel progetto (nessun selettore).
- D-10: Se il cliente ha 2+ progetti → tabs in cima con i nomi dei brand (es. "Brand Blu | Brand Verde"). Le tab usano il componente Tabs di shadcn/ui già presente.
- D-11: La struttura della dashboard cliente cambia: la vista di un singolo progetto mostra le stesse sezioni di oggi (stato fasi/task, pagamenti, approvazioni deliverable, commenti) ma scoped al progetto.
Admin — vista Clienti
- D-12: La lista
/admin/clientsmostra ogni cliente con i nomi dei brand sotto il nome (es. "Mario Rossi" + riga sottile "Brand Blu | Brand Verde"). Life Time Value = somma degliaccepted_totaldi tutti i progetti del cliente. - D-13: Cliccando un cliente si apre
/admin/clients/[id]che mostra la lista progetti di quel cliente (cards o righe), non più il workspace direttamente.
Admin — vista Progetti
- D-14: Nuova pagina
/admin/projects(link nel NavBar) — lista di tutti i progetti con colonne: Nome progetto, Cliente genitore, Valore progetto (accepted_total), Acconto (stato), Saldo (stato), Timer (play/stop), €/h calcolato. - D-15: Il timer nella lista Progetti mostra il bottone play/stop per il progetto corrente. Solo un timer attivo alla volta (come ora, ma scoped al progetto).
- D-16: Cliccando un progetto si apre
/admin/projects/[id]— workspace identico all'attuale/admin/clients/[id]ma al livello progetto: tabs Panoramica, Fasi, Documenti, Pagamenti, Note, Preventivo, Timer, Commenti.
Creazione progetto (admin)
- D-17: Progetto creabile da due punti: (1) dal dettaglio cliente
/admin/clients/[id]con un bottone "+ Nuovo Progetto", (2) dalla lista/admin/projectscon "+ Nuovo Progetto" che chiede prima il cliente. - D-18: Form di creazione progetto: Nome progetto (brand name) + selezione cliente (se creato dalla lista globale). Nessun campo aggiuntivo al momento della creazione — tutto il resto si configura nel workspace del progetto.
Timer e analytics profittabilità
- D-19:
time_entries.client_iddiventatime_entries.project_id. Il timer gira per progetto. - D-20: Analytics profittabilità nel tab Timer di ogni progetto — card con: ore totali, accepted_total, €/h reale (accepted_total ÷ ore), target_rate × ore (costo ideale), delta (guadagno/perdita vs target).
- D-21:
target_hourly_rateè un valore globale impostato dall'admin — stored in una tabellasettings(key-value) o direttamente come env var configurabile. Impostabile da una nuova sezione "Impostazioni" nel NavBar admin. - D-22: La Statistiche page mostra la profittabilità aggregata per tutti i progetti + breakdown per cliente.
Claude's Discretion
- Struttura esatta della tabella
settings(key-value o colonne specifiche) — scegliere l'approccio più semplice (probabile: tabellasettingsconkey text PK, value text). - Ordine delle tabs nel dettaglio progetto — seguire l'ordine attuale del dettaglio cliente.
- Stile delle cards progetto nel dettaglio cliente — seguire i pattern UI esistenti.
<canonical_refs>
Canonical References
Downstream agents MUST read these before planning or implementing.
Schema attuale (punto di partenza)
src/db/schema.ts— schema completo con tutte le tabelle e relazioni. Le FK da migrare: phases.client_id → project_id, payments.client_id → project_id, quote_items.client_id → project_id, time_entries.client_id → project_id, documents.client_id → project_id, notes.client_id → project_id.
Architettura constraints (LOCKED)
CLAUDE.md§Architecture Constraints — specialmente: token rotatable (mai PK), quote_items mai esposti via client API, deliverables.approved_at immutable. Questi vincoli si applicano anche al livello progetto.
Patterns UI esistenti da replicare
src/components/admin/tabs/— pattern tab workspace esistente (QuoteTab, ecc.) da replicare per il dettaglio progetto.src/components/admin/TimerCell.tsx— timer da adattare da client_id a project_id.src/components/admin/ClientRow.tsx— pattern riga lista da replicare per ProjectRow.src/app/admin/clients/[id]/page.tsx— layout tabs workspace da replicare per /admin/projects/[id].
Dashboard cliente
src/lib/client-view.ts— la query che alimenta la dashboard cliente. Va riscritta per supportare progetto singolo e multi-progetto.src/app/c/[token]/page.tsx— dashboard cliente da ristrutturare per mostrare tabs progetto.
Phase 3 artifacts (prerequisito)
.planning/phases/03-service-catalog-quote-builder/03-CONTEXT.md— decisioni sul preventivo e catalogo (quote_items → project_id in questa fase)..planning/phases/03-service-catalog-quote-builder/03-03-SUMMARY.md— implementazione QuoteTab.
</canonical_refs>
<code_context>
Existing Code Insights
Reusable Assets
src/components/ui/tabs.tsx— Tabs shadcn già presente, usato in dettaglio cliente. Riutilizzare per il selettore progetto nella dashboard cliente e per il workspace progetto admin.src/components/admin/TimerCell.tsx— implementazione timer completa, da adattare con project_id invece di client_id.src/components/admin/tabs/QuoteTab.tsx— quote builder completo, da ri-wiring con project_id.src/lib/admin-queries.ts—getClientFullDetailè il template pergetProjectFullDetail.src/app/admin/clients/[id]/page.tsx— layout workspace admin con tabs, da clonare per /admin/projects/[id].
Established Patterns
- Server Actions con
requireAdmin()per tutte le operazioni admin-only. - Query pattern: un'unica funzione
getXFullDetailche recupera tutto in parallelo per ridurre round-trip. drizzle-kit pushper applicare le modifiche schema al DB Neon live.- Token middleware in
src/proxy.ts— da estendere per slug lookup.
Integration Points
- Il middleware
src/proxy.tsdeve risolvere/c/[slug-o-token]→ lookup slug prima, poi token. src/lib/client-view.tsva riscritta completamente per il modello multi-progetto.src/components/admin/NavBar.tsx— aggiungere link "Progetti" e "Impostazioni".getAllClientsWithPaymentsin admin-queries.ts va riscritta per includere i progetti annidati.
</code_context>
## Specific Ideas- Screenshot di riferimento (utente): Lista Clienti mostra "Mario Rossi" in bold con "Brand Blu | Brand Verde" come testo secondario sotto, Life Time Value come somma, link /c/slug.
- Screenshot di riferimento (utente): Lista Progetti mostra "Brand Blu" in bold con "Mario Rossi" come testo secondario, colonne Valore, Acconto, Saldo, Timer (play icon), €/h calcolato.
- Analytics formula (utente): accepted_total ÷ ore_lavorate = €/h reale. target_rate × ore = costo ideale. Delta = accepted - costo_ideale. Mostra se si guadagna, perde, o break-even.
- Target rate: valore globale (es. 50€/h) che l'admin imposta una volta. Non per progetto.
- Link cliente: preferibilmente con nome cliente (es. /c/mario-rossi). Customizzabile dall'admin. Fallback al token se non impostato.
- Fatturazione per progetto — calcolo automatico fatture basato su pagamenti. Fuori scope (out of scope globale del progetto).
- Export PDF preventivo per progetto — utile ma separato. Fase futura.
- AI Onboarding (ex Fase 4) — spostato a Fase 5. Richiede questa ristrutturazione come prerequisito.
- Notifiche email al cliente — quando le fasi cambiano stato. Fase futura.
Phase: 4 — Progetti Multi-Project Context gathered: 2026-05-20