docs(11-04): add plan summary and log unused createService action
- 11-04-SUMMARY.md documents ServiceTable database-view rewrite + CatalogSearch - deferred-items.md: log now-unused createService/serviceSchema in actions.ts (item 6)
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
---
|
||||
phase: 11-catalog-database-view-ux-legacy-consolidation
|
||||
plan: 04
|
||||
subsystem: ui
|
||||
tags: [react, nextjs, tailwind, server-actions, catalog, inline-edit, tags, search]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: 11-catalog-database-view-ux-legacy-consolidation
|
||||
plan: "11-02"
|
||||
provides: "ServiceWithTags type, getAllServices(), updateServiceField/quickAddService/addTagToService/removeTagFromService server actions"
|
||||
- phase: 11-catalog-database-view-ux-legacy-consolidation
|
||||
plan: "11-03"
|
||||
provides: "EditableCell (text/number/textarea/toggle) and TagMultiSelect shared UI primitives"
|
||||
provides:
|
||||
- "Database-view /admin/catalog: 6-column inline-editable ServiceTable (Nome, Descrizione, Categoria, Prezzo, Tag, Stato), no Azioni column"
|
||||
- "QuickAddRow — creates services via quickAddService(name) on Enter, unit_price=0 (D-12)"
|
||||
- "Active/inactive split with 'Servizi disattivati' divider + opacity-50 (D-13)"
|
||||
- "CatalogSearch client component — instant client-side name/tag filter, no reload (OFFER-10)"
|
||||
affects: ["12"]
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Co-located client filter wrapper (CatalogSearch) between an async Server Component page and a presentational table — useMemo filter over already-fetched data, zero new fetches on query change"
|
||||
- "ServiceRow per-row error display via a conditional colSpan=6 trailing <td>, keeping row height stable in the success path"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- src/app/admin/catalog/CatalogSearch.tsx
|
||||
modified:
|
||||
- src/components/admin/catalog/ServiceTable.tsx
|
||||
- src/app/admin/catalog/page.tsx
|
||||
deleted:
|
||||
- src/components/admin/catalog/ServiceForm.tsx
|
||||
|
||||
key-decisions:
|
||||
- "Left createService (and its serviceSchema) in src/app/admin/catalog/actions.ts as unused dead code rather than editing actions.ts, which was outside this plan's files_modified scope — logged to deferred-items.md for a future cleanup pass."
|
||||
|
||||
patterns-established:
|
||||
- "ServiceTable/CatalogSearch is now the canonical /admin/catalog database-view UX — any future catalog-adjacent admin table (Phase 12+) should follow the same EditableCell/TagMultiSelect/QuickAddRow/search-filter pattern per DESIGN-SYSTEM.md"
|
||||
|
||||
requirements-completed: [OFFER-07, OFFER-08, OFFER-09, OFFER-10]
|
||||
|
||||
# Metrics
|
||||
duration: 12min
|
||||
completed: 2026-06-13
|
||||
---
|
||||
|
||||
# Phase 11 Plan 4: Catalog Database-View UX — ServiceTable Rewrite + Search Summary
|
||||
|
||||
**`/admin/catalog` is now a Notion/Airtable-style database view: every `services` cell (name, description, category, price, tags, active status) is click-to-edit via `EditableCell`/`TagMultiSelect`, a quick-add row creates new services on Enter, a search bar filters client-side by name/tag instantly, and inactive services sink below a "Servizi disattivati" divider at reduced opacity — with zero "Azioni" column anywhere.**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** ~12 min
|
||||
- **Started:** 2026-06-13T13:55:00Z
|
||||
- **Completed:** 2026-06-13T14:02:06Z
|
||||
- **Tasks:** 2 of 2
|
||||
- **Files modified:** 3 (1 created, 1 deleted, 2 modified — counting page.tsx + ServiceTable.tsx as modified, CatalogSearch.tsx as created, ServiceForm.tsx as deleted)
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- `ServiceTable.tsx` fully rewritten as a database-view table: 6 columns (Nome, Descrizione, Categoria, Prezzo, Tag, Stato), every cell rendered via `EditableCell` (text/textarea/number/toggle) or `TagMultiSelect`, no "Azioni" column (D-14).
|
||||
- `ServiceRow` wires each field's `onSave` to `updateServiceField(service.id, field, value)` and the tags column to `TagMultiSelect`'s `onTagsChanged`; both call `router.refresh()` after the server action resolves. Per-row save errors render inline via a `colSpan={6}` trailing cell without affecting row height in the success path.
|
||||
- `QuickAddRow` renders a borderless `Input` with placeholder "+ Aggiungi servizio"; pressing Enter with non-empty text calls `quickAddService(name)`, clears the input, and refreshes (D-12).
|
||||
- Services are partitioned into `activeServices`/`inactiveServices`; active services render first, then `QuickAddRow`, then (if any) a "Servizi disattivati" divider row followed by inactive services with `opacity-50` (D-13).
|
||||
- New `src/app/admin/catalog/CatalogSearch.tsx` client component: holds search query state, filters `ServiceWithTags[]` by `name` or any `tags[]` entry (case-insensitive substring match) via `useMemo`, and renders `ServiceTable` with the filtered list — purely client-state, no `router.push`/`refresh`/`<form>` (OFFER-10).
|
||||
- `page.tsx` rewritten: remains an async Server Component calling `getAllServices()`, no longer imports `ServiceForm`, renders `CatalogSearch` (or the existing "Nessun servizio..." message, reworded to point at the table's quick-add row, when the catalog is empty).
|
||||
- `ServiceForm.tsx` deleted entirely — its "+ Aggiungi servizio" full-form creation flow is fully replaced by `ServiceTable`'s `QuickAddRow`.
|
||||
- `npx tsc --noEmit`: zero errors project-wide. `npx eslint` on all 3 touched files: zero issues. `npx next build`: 0 errors, 0 warnings — `/admin/catalog` (auth-gated dynamic route) was not statically pre-rendered, so no live-DB query was attempted (consistent with the plan's DB-state note; not a firewall block, build was simply clean).
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Rewrite ServiceTable as database-view (inline edit, tags, quick-add, active/inactive split)** - `c0bedf3` (feat)
|
||||
2. **Task 2: Add client-side search bar to page.tsx, remove ServiceForm** - `912a892` (feat)
|
||||
|
||||
**Plan metadata:** (this commit, following SUMMARY)
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `src/components/admin/catalog/ServiceTable.tsx` - Full rewrite: `ServiceRow` (EditableCell x5 + TagMultiSelect), `QuickAddRow`, `ServiceTable` with active/inactive split and "Servizi disattivati" divider
|
||||
- `src/app/admin/catalog/CatalogSearch.tsx` - New client component: search input (Lucide `Search` icon) + `useMemo` name/tag filter wrapping `ServiceTable`
|
||||
- `src/app/admin/catalog/page.tsx` - Removed `ServiceForm` import/render; now renders `CatalogSearch` with `ServiceWithTags[]` from `getAllServices()`
|
||||
- `src/components/admin/catalog/ServiceForm.tsx` - Deleted (102 lines); quick-add functionality fully replaced by `ServiceTable`'s `QuickAddRow`
|
||||
|
||||
## Decisions Made
|
||||
|
||||
- Left `createService` (and the `serviceSchema` zod validator it shares with `updateService`) in `src/app/admin/catalog/actions.ts` as now-unused dead code, rather than editing `actions.ts` — that file was not in this plan's `files_modified` scope, and `updateService` still depends on `serviceSchema`. Logged to `deferred-items.md` (item #6) for a future cleanup pass.
|
||||
- Followed the plan's prescribed code for `ServiceTable.tsx`/`CatalogSearch.tsx`/`page.tsx` verbatim — no changes needed to satisfy lint/typecheck (unlike Plan 03's `EditableCell`, no `useEffect`/ref patterns were introduced here that would trigger `react-hooks/set-state-in-effect` or `react-hooks/refs`).
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None - plan executed exactly as written. All 12 behavior tests for Task 1 and all 7 behavior tests for Task 2 are satisfied by the code as specified in `11-04-PLAN.md`.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
None.
|
||||
|
||||
## Known Stubs
|
||||
|
||||
None - `ServiceTable` and `CatalogSearch` are both fully wired to live data (`getAllServices()` -> `ServiceWithTags[]`) and Plan 02's server actions (`updateServiceField`, `quickAddService`, `addTagToService`/`removeTagFromService` via `TagMultiSelect`). No hardcoded/empty/placeholder values flow to rendering.
|
||||
|
||||
## Threat Flags
|
||||
|
||||
None - this plan introduces no new endpoints, auth paths, or trust-boundary changes beyond what was already reviewed in `11-04-PLAN.md`'s threat model:
|
||||
|
||||
- T-11-14 (Information Disclosure, accept): `CatalogSearch` receives the full `ServiceWithTags[]` (including inactive services) regardless of search query — same as pre-Phase-11 `ServiceTable`, and `/admin/catalog` remains behind the Auth.js admin session guard.
|
||||
- T-11-15 (Tampering, mitigate): `QuickAddRow` uses `startTransition` and only clears the input on a successful `quickAddService` resolve; a failed call surfaces an inline error without a partial row (atomic DB insert).
|
||||
- T-11-16 (DoS, accept): catalog size remains bounded by manual admin entry; no bulk import in this phase.
|
||||
|
||||
## User Setup Required
|
||||
|
||||
None - no new environment variables or external service configuration needed.
|
||||
|
||||
### DB-state note (carried from Plans 01-03, non-blocking for this plan)
|
||||
|
||||
The `tags` table (Plan 01) and the `addTagToService`/`removeTagFromService`/`updateServiceField`/`quickAddService` server actions (Plan 02) remain unverified against the **live** Postgres DB — the migration apply step is firewalled and pending manual SSH+docker exec by the user (tracked in `STATE.md` Blockers since Plan 01). This plan's verification was code-only (`npx tsc --noEmit`, `eslint`, `next build`), per the plan's `<db_state_note>`. `next build` did not attempt to reach the live DB for `/admin/catalog` (auth-gated dynamic route, not statically rendered) — the build was simply clean, no firewall error encountered.
|
||||
|
||||
**End-to-end runtime verification of the full database-view UX (inline edit persisting, tag creation persisting, quick-add row creating a row, active/inactive split with real data) requires the Plan 01 `tags` table migration to be applied to the live DB first.** This is the same outstanding checkpoint documented in `11-01-SUMMARY.md`, `11-02-SUMMARY.md`, and `11-03-SUMMARY.md`.
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
- **Phase 11 UI deliverable complete:** `/admin/catalog` now satisfies OFFER-07 (inline edit), OFFER-08 (tag multi-select), OFFER-09 (quick-add), OFFER-10 (search/filter), and D-13/D-14 (inactive split, no Azioni column) at the code level. All 4 plans of Phase 11 (01-04) are now executed.
|
||||
- **Pending before milestone close:** Apply the Plan 01 `tags` table migration (`scripts/push-11-tags-migration.ts`) and the Phase 11 legacy-consolidation scripts (`migrate-services.ts`, `validate-services-migration.ts`, `migrate-tags.ts`, `validate-tags-migration.ts`) to the live Postgres DB via SSH+docker exec, per `STATE.md` Blockers. This is required for OFFER-13 and for end-to-end runtime verification of this plan's UI.
|
||||
- **Recommendation for next session:** Resolve the DB-migration checkpoint (apply Plan 01's migration + Phase 11 consolidation scripts), then do a manual smoke test of `/admin/catalog`: inline-edit each column type, add/remove a tag (including creating a brand-new tag), use the quick-add row, toggle a service's active state, and verify the search bar filters by name/tag.
|
||||
- **Phase 12 readiness:** `ServiceWithTags`/`getAllServices()`/`updateServiceField` etc. are the now-proven query/action/UI stack for `services` — Phase 12 (Offer Composition Drag&Drop & CSV Import) can build on this same foundation when rewiring `/admin/offers` to read from `services`.
|
||||
- **Cleanup candidate (non-blocking):** `createService`/`serviceSchema` dead code in `src/app/admin/catalog/actions.ts` (deferred-items.md #6).
|
||||
|
||||
---
|
||||
*Phase: 11-catalog-database-view-ux-legacy-consolidation*
|
||||
*Completed: 2026-06-13*
|
||||
@@ -43,3 +43,13 @@ Items discovered during execution that are out of scope for the current plan/tas
|
||||
- **Impact:** Low — both requirements legitimately complete once 11-04 lands (this plan is a direct, immediate prerequisite, same wave sequence, no risk of the milestone closing prematurely mid-phase). However the "Complete" status in REQUIREMENTS.md was technically premature at the time 11-02 marked it.
|
||||
- **Recommended fix:** No action needed if 11-04 executes next as planned. If 11-04 is ever skipped/deferred, re-open OFFER-07/08 status in REQUIREMENTS.md to "In Progress" until the UI wiring lands.
|
||||
- **Status:** Not fixed — pre-existing from 11-02, informational only, expected to self-resolve when 11-04 completes.
|
||||
|
||||
## From Plan 11-04
|
||||
|
||||
### 6. `createService` server action now unused after `ServiceForm.tsx` deletion
|
||||
|
||||
- **Found during:** 11-04, Task 2
|
||||
- **Issue:** `src/app/admin/catalog/actions.ts` exports `createService(formData: FormData)`, whose only consumer was `src/components/admin/catalog/ServiceForm.tsx`. This plan deletes `ServiceForm.tsx` (its create-service UX is replaced by `ServiceTable`'s `QuickAddRow` + `quickAddService`), leaving `createService` (and its `serviceSchema` zod validator, also used by `updateService`) as dead/unused exported code.
|
||||
- **Impact:** Low — `npx tsc --noEmit` and `eslint` both pass cleanly (unused *exported* functions are not flagged by this project's lint config). No runtime impact; `createService` simply has zero callers.
|
||||
- **Recommended fix:** Remove `createService` (and `serviceSchema` if `updateService` no longer needs it — `updateService` still uses it, so keep the schema) from `src/app/admin/catalog/actions.ts` in a follow-up cleanup pass. `src/app/admin/catalog/actions.ts` was not in this plan's `files_modified` list, so removing it here would be out of scope (Rule 1/3 do not apply — not a bug, not blocking).
|
||||
- **Status:** Not fixed. Logged for future cleanup (Phase 12 or a standalone hygiene pass).
|
||||
|
||||
Reference in New Issue
Block a user