diff --git a/.planning/phases/02-admin-area-interactive-features/02-02-SUMMARY.md b/.planning/phases/02-admin-area-interactive-features/02-02-SUMMARY.md new file mode 100644 index 0000000..6131b92 --- /dev/null +++ b/.planning/phases/02-admin-area-interactive-features/02-02-SUMMARY.md @@ -0,0 +1,144 @@ +--- +phase: 02-admin-area-interactive-features +plan: "02" +subsystem: ui +tags: [nextjs, server-actions, drizzle, shadcn, zod, nanoid, tailwind] + +# Dependency graph +requires: + - phase: 02-01 + provides: Auth.js session guard protecting all /admin/* routes via middleware + +provides: + - Admin client list at /admin with payment status badges (Acconto/Saldo per client) + - New client creation form at /admin/clients/new with Server Action + - Automatic payment stub creation (Acconto 50% + Saldo 50%) on client insert + - ClientWithPayments query type and getAllClientsWithPayments() utility + - Admin layout with NavBar (ClientHub logo, Clienti link, Esci logout button) + +affects: + - 02-03 + - 02-04 + - client-detail page (Plan 03 will build /admin/clients/[id]) + +# Tech tracking +tech-stack: + added: [] + patterns: + - "Server Components for admin data pages (no client state, no useEffect)" + - "Server Actions with Zod validation for form mutations (D-05)" + - "revalidatePath('/admin') + redirect after mutation" + - "nanoid token generated server-side via $defaultFn — never user-supplied" + - "Two-query fetch pattern: clients then payments, merged in-memory (avoids JOIN complexity)" + +key-files: + created: + - src/lib/admin-queries.ts + - src/components/admin/NavBar.tsx + - src/app/admin/layout.tsx + - src/components/admin/ClientRow.tsx + - src/app/admin/page.tsx + - src/app/admin/clients/new/page.tsx + - src/app/admin/clients/new/actions.ts + modified: [] + +key-decisions: + - "Zod validates createClient input server-side before any DB write — malformed input throws cleanly with no partial inserts" + - "Payment stubs inserted immediately on client creation with amount=0 and status=da_saldare — amounts updated separately by admin" + - "Token is $defaultFn(() => nanoid()) — server-generated, never derived from user input, satisfies T-02-08" + - "Admin page uses revalidate=0 to always fetch fresh data — admin operations require real-time list" + - "Two-query pattern (clients + payments) merged in-memory chosen over Drizzle relations JOIN for simplicity at this scale" + +patterns-established: + - "Server Action pattern: 'use server' + Zod schema + db.insert + revalidatePath + redirect" + - "ClientRow: presentational component receiving ClientWithPayments, no data fetching" + - "Badge variant mapping: da_saldare=destructive, inviata=secondary, saldato=default" + +requirements-completed: + - ADMIN-01 + - ADMIN-02 + +# Metrics +duration: 30min +completed: 2026-05-15 +--- + +# Phase 02 Plan 02: Admin Client List + Create Client Summary + +**Admin home shows all clients with Acconto/Saldo payment badges; new client form inserts client row + two payment stubs via Zod-validated Server Action with nanoid token auto-generation** + +## Performance + +- **Duration:** ~30 min +- **Started:** 2026-05-15 +- **Completed:** 2026-05-15 +- **Tasks:** 2 (Task 1 pre-committed, Task 2 executed in this run) +- **Files modified:** 7 + +## Accomplishments + +- Admin dashboard at /admin renders all clients in a table with name, brand, totale, Acconto badge, Saldo badge, and truncated secret link +- Empty state renders gracefully with a link to create the first client +- /admin/clients/new form with nome, brand, brief fields wired to `createClient` Server Action +- `createClient` validates with Zod, inserts client row (token auto-generated by nanoid), inserts Acconto 50% + Saldo 50% payment stubs, revalidates /admin, redirects to /admin/clients/[id] +- Admin layout wraps all /admin/* pages with NavBar showing "ClientHub" + "Clienti" link + "Esci" logout button + +## Task Commits + +1. **Task 1: Create admin-queries.ts, NavBar, and admin layout** - `7029583` (feat) +2. **Task 2: Admin client list page and create-client flow** - `f77051a` (feat) + +**Plan metadata:** (docs commit follows) + +## Files Created/Modified + +- `src/lib/admin-queries.ts` - `getAllClientsWithPayments()` and `getClientById()` query utilities; `ClientWithPayments` type +- `src/components/admin/NavBar.tsx` - Client component with logo, Clienti nav link, signOut button +- `src/app/admin/layout.tsx` - Layout wrapper applying NavBar to all /admin/* pages +- `src/components/admin/ClientRow.tsx` - Table row with payment status Badge components and secret link +- `src/app/admin/page.tsx` - Server Component fetching all clients; renders table or empty state +- `src/app/admin/clients/new/page.tsx` - Form page (Server Component) wired to createClient action +- `src/app/admin/clients/new/actions.ts` - Server Action: Zod validation + db.insert(clients) + db.insert(payments) x2 + +## Decisions Made + +- Zod validates createClient input before any DB operation — malformed input throws a clean error with no partial writes +- Payment stubs created with `amount: "0"` — amounts set later by admin via separate update flow (Plan 03) +- `revalidate = 0` on /admin page ensures admin always sees fresh data after mutations +- Token is entirely server-generated (`$defaultFn(() => nanoid())`) — user cannot supply or influence it (T-02-08 mitigated) + +## Deviations from Plan + +None - plan executed exactly as written. + +## Issues Encountered + +None. Build passed cleanly (existing CSS warning is pre-existing and unrelated to this plan). + +## Known Stubs + +- `/admin/clients/[id]` — redirect destination after client creation. The route does not exist yet; Next.js will render a 404 until Plan 03 builds the client detail page. This is explicitly noted in the plan as acceptable at this stage ("stub until Plan 03"). + +## Threat Surface Scan + +All threats in the plan's threat register are addressed: + +| Threat ID | Disposition | Status | +|-----------|-------------|--------| +| T-02-06 | mitigate | Zod validates createClient before any DB write | +| T-02-07 | mitigate | /admin/* protected by 02-01 middleware session guard | +| T-02-08 | mitigate | Token is `$defaultFn(() => nanoid())`, never user-supplied | +| T-02-09 | accept | Token shown truncated in UI; full token only via /c/[token] link | + +No new security surfaces introduced beyond the threat model. + +## Next Phase Readiness + +- /admin client list and /admin/clients/new are fully functional end-to-end +- createClient Server Action is the canonical pattern for future admin mutations +- Plan 03 can build /admin/clients/[id] detail page using `getClientById()` already exported from admin-queries.ts +- Payment stub amounts need an update flow (Plan 03 or later) + +--- +*Phase: 02-admin-area-interactive-features* +*Completed: 2026-05-15* \ No newline at end of file