Commit Graph

17 Commits

Author SHA1 Message Date
Simone Cavalli 69f8a7eae3 feat(02-01): extend proxy.ts with admin session guard, add login page
- Extend src/proxy.ts to guard /admin/* routes with getToken() JWT check
- /admin/login and /api/auth/* exempted from session guard (pass-through)
- Unauthenticated /admin/* requests redirect to /admin/login?callbackUrl=...
- /c/:path* client token validation logic preserved unchanged
- matcher updated: ["/admin/:path*", "/c/:path*"]
- Create src/app/admin/login/page.tsx: email+password form, signIn('credentials'), error on failure, redirect on success
- Fix: Next.js 16 requires export named 'proxy' not 'middleware'
- Fix: useSearchParams wrapped in Suspense boundary (Next.js App Router requirement)
2026-05-15 10:42:21 +02:00
Simone Cavalli 5d363a633d feat(02-01): install next-auth@4, configure CredentialsProvider auth
- Add next-auth@4 dependency (stable v4, not beta v5)
- Create src/lib/auth.ts with CredentialsProvider validating ADMIN_EMAIL/ADMIN_PASSWORD env vars
- Create src/app/api/auth/[...nextauth]/route.ts catch-all handler (GET + POST)
- JWT session strategy — stateless, no DB users table
- Custom sign-in page set to /admin/login
- Add NEXTAUTH_URL, NEXTAUTH_SECRET, ADMIN_EMAIL, ADMIN_PASSWORD to .env.local
2026-05-15 10:40:30 +02:00
Simone Cavalli 073eec7193 feat(seed): add seed script + fix Tailwind scanning adjacent projects
- 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>
2026-05-14 23:33:03 +02:00
Simone Cavalli 8602bfa92f feat(01-04): DocumentsSection + NotesSection — link esterni e log decisioni read-only
- 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
2026-05-14 22:13:33 +02:00
Simone Cavalli a4e2de0611 feat(01-04): PaymentStatus — totale accettato + righe stato pagamento (senza importi)
- 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
2026-05-14 22:13:27 +02:00
Simone Cavalli 5d5c8eaa7d feat(01-04): PhaseTimeline — timeline laterale con indicatori, progress bar per fase, task list
- 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)
2026-05-14 22:13:20 +02:00
Simone Cavalli debd3916db feat(01-04): ClientDashboard wrapper con header, progress bar globale, layout sezioni
- Header sticky: logo iamcavalli (xs, angolo sinistro) + brand_name cliente (prominente, centrato)
- Progress bar globale con percentuale visibile
- Brief cliente con accent bar sinistra
- Sezioni: PhaseTimeline, PaymentStatus (sempre), Documents/Notes (condizionali)
- Footer con avviso link privato
- Server Component puro, nessun 'use client' necessario
2026-05-14 22:13:11 +02:00
Simone Cavalli 4e703d7068 feat(01-04): design tokens Tailwind v4 + wire ClientDashboard in page.tsx
- globals.css: aggiunto @theme con palette light & clean (primary, secondary,
  tertiary, bg-subtle, border-light, accent, success, warning, info)
- app/c/[token]/page.tsx: import ClientDashboard, generateMetadata dinamico,
  React.cache() per deduplicare DB call tra metadata e render
2026-05-14 21:43:41 +02:00
Simone Cavalli 8b5e723f81 feat(01-03): add /c/[token] Server Component route + layout
- src/app/c/[token]/page.tsx: Server Component calls getClientView(), notFound() on null
- src/app/c/[token]/layout.tsx: layout with metadata for client portal
- [Rule 1 - Bug] Renamed middleware.ts → proxy.ts and export middleware → proxy
  (Next.js 16 deprecated 'middleware' file convention; requires 'proxy' export name)
- params typed as Promise<{ token: string }> per Next.js 15+ breaking change
- npm run build: SUCCESS (no TypeScript errors)
2026-05-14 21:11:32 +02:00
Simone Cavalli 14787bab10 feat(01-03): add ClientView type system and getClientView() query function
- ClientView interface enforces admin data exclusion: no quote_items, no service prices
- getClientView() queries clients.token, phases, tasks, deliverables, payments, documents, notes
- inArray() scoping prevents full table scan on tasks and deliverables
- accepted_total: client.accepted_total ?? '0' null coalescing
- Progress percentages calculated server-side (per-phase + global)
- Payment amount intentionally excluded — only label and status returned to client
2026-05-14 20:58:30 +02:00
Simone Cavalli ef3481744c feat(01-03): add Edge middleware + internal validate-token API route
- src/middleware.ts: Edge-compatible token validation via fetch() (no Drizzle import)
- src/app/api/internal/validate-token/route.ts: Node.js route queries clients.token via Drizzle
- Invalid tokens rewrite to /not-found (404); matcher scoped to /c/:path*
2026-05-14 20:15:11 +02:00
Simone Cavalli abcbb5224e feat(01-02): [BLOCKING] drizzle-kit push — schema live on Postgres
- 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
2026-05-13 22:47:51 +02:00
Simone Cavalli a6ec599188 chore(01-02): generate Drizzle migration from schema (0000_pretty_typhoid_mary.sql)
- 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)
2026-05-13 22:46:54 +02:00
Simone Cavalli 1bdbe7ab5d feat(01-02): create complete Drizzle schema with all 10 tables
- 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)
2026-05-13 22:46:30 +02:00
Simone Cavalli f8420072f4 feat(01-01): install shadcn/ui components and lucide-react icons
- components.json configured (Radix preset, CSS variables, @/ aliases)
- src/lib/utils.ts: cn() helper with clsx + tailwind-merge
- 10 shadcn/ui components: button, card, badge, progress, input, label,
  select, separator, table, textarea
- lucide-react@0.511 installed for iconography
- clsx, tailwind-merge, class-variance-authority added as dependencies
2026-05-13 15:32:19 +02:00
Simone Cavalli 6b5609b0cb feat(01-01): install Drizzle ORM, postgres-js, and configure DB client
- drizzle-orm@0.45.2 + postgres@3.4.9 installed (postgres-js driver)
- drizzle-kit@0.31.10 installed as dev dependency
- nanoid@5, zod@4, react-hook-form, @hookform/resolvers installed
- src/db/index.ts: Drizzle client initialized with postgres-js driver
- drizzle.config.ts: configured for postgresql dialect + src/db/schema.ts
- .env.example: added as public template (no secrets)
- .gitignore: allow .env.example while blocking all other .env* files
2026-05-13 15:30:53 +02:00
Simone Cavalli 9563b87c81 chore(01-01): bootstrap Next.js 16 with TypeScript, App Router, Tailwind CSS v4
- Created Next.js 16.2.6 project with App Router, src/ directory, TypeScript strict mode
- Configured Tailwind CSS v4 with postcss.config.mjs
- Simplified src/app/page.tsx to Welcome to ClientHub placeholder
- Updated layout.tsx with ClientHub metadata, Italian lang, viewport export (Next.js 16 API)
- Added .gitignore covering node_modules, .env*, .next/, build artifacts

Note: create-next-app installed Next.js 16.2.6 (latest stable) instead of 15.x — fully compatible upgrade
2026-05-13 15:28:58 +02:00