Provides getAnalyticsByYear, getMonthlyCollected, and getAvailableYears
to power the admin dashboard analytics view (not yet wired to a page).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removed per-task/deliverable CommentList/CommentForm from PhaseTimeline and
ClientKanban. Replaced with a single ChatSection at the bottom of the dashboard
that handles general, task, and deliverable messages in a unified chat UI.
Added "general" entity_type to the comment API (entity_id = client UUID).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix button contrast: add all missing shadcn tokens (primary-foreground,
ring, input, muted, destructive) aligned to iamcavalli brand
- NavBar: #1A463C green bar with white text
- Login page: clean brand layout with iamcavalli wordmark
- Admin pages: brand colors on headings, borders, links
- Admin ClientRow: semantic payment badges (green/yellow/red)
- Admin phases tab: Lista ↔ Kanban toggle with @dnd-kit drag & drop
between Da fare / In corso / Fatto columns (optimistic updates)
- Client dashboard: Timeline ↔ Kanban toggle, expandable task cards
with approve button + comment form inline
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ApproveButton: 'use client', POSTs to /api/client/approve with token + deliverableId, calls router.refresh(); shows immutable "Approvato il [date]" badge once approved_at is set
- CommentForm: 'use client', POSTs to /api/client/comment, calls router.refresh() on success; clears textarea after submit
- CommentList: presentational Server Component, labels client author as "Tu" and admin as "iamcavalli"
- page.tsx: fetches all comments server-side (scoped to client's task/deliverable ids), passes token + comments to ClientDashboard; revalidate=0 ensures approvals and comments always fresh
- client-dashboard.tsx: passes token + comments down to PhaseTimeline
- phase-timeline.tsx: renders ApproveButton on each deliverable (pending/submitted/approved), CommentList + CommentForm below each deliverable and each task
- approve: validates token, checks deliverable ownership via phase→client join, sets status=approved + approved_at=now() only if approved_at is currently null (CLAUDE.md immutability rule enforced)
- comment: validates token, checks entity ownership (task or deliverable) via phase→client chain, inserts comment with author='client'
- both routes return 404 on invalid token or unknown entity
- neither route references quote_items (CLAUDE.md constraint enforced)
- Zod validation on comment body: min 1 char, max 2000 chars (T-02-20 DoS mitigation)
- SUMMARY.md for Plan 02-03: Radix Tabs workspace with all four tab components
- Documents deviations: Next.js 16 params await fix and FormData type annotations
- Records all threat mitigations applied (T-02-10 through T-02-14)
- Create /admin/clients/[id]/page.tsx — Server Component using Radix Tabs (Fasi & Task, Pagamenti, Documenti, Commenti)
- Create PhasesTab: phases list with add-phase form, task lists with add-task form, status selects for phases and tasks
- Create PaymentsTab: accepted_total editor (splits to 50% on each payment), payment status selects with paid_at on saldato
- Create DocumentsTab: add document (label + URL) form, document list with delete action
- Create CommentsTab: chronological comment display (admin vs cliente style), admin reply form with entity selector
- All mutations via inline Server Action closures bound to action= props; revalidatePath ensures fresh data
- /admin page: Server Component fetching all clients with payment badges
- ClientRow component with Acconto/Saldo status badges and secret link
- /admin/clients/new: form wired to createClient Server Action
- createClient action: Zod validation, inserts client + 2 payment stubs (Acconto 50%, Saldo 50%)
- Token auto-generated server-side via nanoid $defaultFn
- Redirects to /admin/clients/[id] after creation; revalidates /admin
- src/lib/admin-queries.ts: getAllClientsWithPayments() and getClientById() for admin DB reads
- src/components/admin/NavBar.tsx: minimal nav with Clienti link and Esci (logout) button
- src/app/admin/layout.tsx: wraps all /admin/* pages with NavBar + centered main content area
- scripts/seed.ts: inserts one complete test client with 3 phases,
6 tasks, 4 deliverables, 2 payments, 2 documents, 2 notes; prints
shareable URL to console
- globals.css: add @source not directives to exclude .01_projects/
and .claude/ — Tailwind v4 was scanning the SparklingOrbit .venv
Python files and generating invalid CSS class [-:|] from a regex
pattern in a markdown-it table parser, causing dev server 500s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- DocumentsSection: link clickabili con target="_blank" rel="noopener noreferrer"
icone SVG inline per documento ed external link, hover state con colore accent
- NotesSection: note read-only con timestamp in locale it-IT (D-12: cliente legge, admin scrive)
empty state informativo per entrambi i componenti
- SVG inline al posto di lucide-react per compatibilita' massima
- Mostra accepted_total formattato in EUR (unico importo permesso — LOCKED)
- Righe pagamento: solo label + badge stato (da_saldare/inviata/saldato)
- Nessun importo singolo visibile al cliente (T-04-001 mitigato)
- Dot colorato + badge per ogni riga: blu=da_saldare, giallo=inviata, verde=saldato
- Layout a due colonne: indicatore cerchio (sinistra) + card fase (destra)
- Icone SVG inline per stato fase (done/active/upcoming) e task (done/in_progress/todo)
- Badge stato fase con colori semantici (verde/blu/grigio)
- Progress bar per fase con contatore task done/totale
- Task list con line-through per done, testo grigio chiaro
- Deliverable annidati sotto ogni task con badge "Approvato" se approved
- Linea verticale tra fasi (non sull'ultima)
- 01-03-SUMMARY.md: 3/3 tasks complete, npm run build passes
- Edge proxy pattern (proxy.ts), validate-token API route, ClientView type system
- /c/[token] Server Component operational, ready for Plan 04 dashboard UI
- Connected to postgresql://178.104.27.55:5432/clienthub
- 10 tables created: clients, phases, tasks, deliverables, comments,
payments, documents, notes, service_catalog, quote_items
- UNIQUE constraint on clients.token active at DB level
- All FK constraints and CASCADE rules applied
- Verified via information_schema.tables query
- 10 tables: clients, phases, tasks, deliverables, comments, payments,
documents, notes, service_catalog, quote_items
- UNIQUE constraint on clients.token enforced at DB level
- All FK cascades correct (deliverables->tasks->phases->clients)
- approved_at: timestamp with time zone (nullable, immutable)
- drizzle.config.ts already correct from Plan 01 (no changes needed)
- clients: token as separate text field (notNull, unique, nanoid) — never PK
- accepted_total denormalized on clients — client API never touches quote_items
- deliverables.approved_at immutable timestamp (TIMESTAMPTZ) — audit trail
- payments: label (Acconto 50% / Saldo 50%), status (da_saldare/inviata/saldato)
- comments: polymorphic entity_type+entity_id pattern
- service_catalog + quote_items: admin-only, never exposed to client API
- Full relations defined for all FK chains
- TypeScript types exported: Client, Phase, Task, Deliverable, etc.
- ID strategy: text + nanoid() via $defaultFn (cryptographically secure, URL-safe)