- Add requireAdmin() to all unprotected admin server actions
(clients/new, clients/[id], timer-actions — 17 functions total)
- Protect /api/internal/* endpoints with X-Internal-Secret header
(proxy.ts sends it; routes reject requests without it)
- Randomize auto-generated client slugs with 4-char suffix
to prevent enumeration via predictable name-based slugs
- Add in-memory rate limiting to /api/client/approve (20/min)
and /api/client/comment (10/min) per IP
- Add security headers: X-Frame-Options, X-Content-Type-Options,
Referrer-Policy, Permissions-Policy, X-DNS-Prefetch-Control
- Reduce JWT session from 30 days to 7 days with daily rotation
- Remove hardcoded NEXTAUTH_URL from Dockerfile (pass via Coolify env)
- Genericize client API error messages to not leak data structure
- Update .env.example with all required variables including INTERNAL_SECRET
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Middleware (proxy.ts): switch internal API calls to localhost instead of
request.url — avoids Docker hairpin NAT issues where the container can't
reach its own external hostname via Traefik
- ProjectRow timer: pass projectId={project.id} to TimerCell so it calls
startTimer(projectId) directly instead of startTimerForClient(project.id)
- Admin client list: add slug field to ClientWithPayments + show slug link
when available (falls back to token) — so admins see the human-readable URL
- Analytics contracted: sum projects.accepted_total (authoritative) instead
of clients.accepted_total (always 0 in multi-project architecture)
- createClient: auto-generate slug from client name at creation time
(e.g. "Mario Rossi" → "mario-rossi"), with -2/-3 suffix on conflict
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Schema:
- clients.archived boolean (default false)
- time_entries table (client_id, started_at, ended_at, duration_seconds)
Client management:
- /admin/clients/[id]/edit — form pre-compilato con nome, brand, brief
- ClientActions: Modifica / Archivia / Elimina con doppia conferma
- setClientArchived: toggle archiviazione senza perdere dati
- deleteClient: elimina con cascade, redirect a /admin
- Admin list: toggle "Mostra archiviati" via ?archived=1, righe archiviate opache
Time tracker:
- startTimer: crea sessione, ferma automaticamente quella precedente
- stopTimer: chiude sessione, calcola duration_seconds
- TimerCell: ▶/⏹ per ogni cliente, contatore live in secondi, totale cumulativo
- Una sola sessione attiva alla volta su tutta la lista
Analytics:
- Sezione "Fatturato" (invariata) + sezione "Tempo tracciato" separata
- Ore totali per anno + barre orizzontali per cliente
- getTotalTrackedHours, getTimeByClient queries
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>
- 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