docs(02-02): complete admin client list and create-client plan summary
- Covers Task 1 (admin-queries, NavBar, layout) and Task 2 (admin page, ClientRow, new client form + Server Action)
This commit is contained in:
@@ -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*
|
||||
Reference in New Issue
Block a user