Files
clienthub/.planning/phases/11-catalog-database-view-ux-legacy-consolidation/11-04-SUMMARY.md
T
simone 0387805041 docs(11-04): complete catalog database-view plan
- Mark OFFER-10 complete (REQUIREMENTS.md) — client-side search delivered
- STATE.md: position advanced to Phase 11 plans 1-4 all executed (92%), session/decisions/metrics updated
- 11-04-SUMMARY.md: append self-check results
2026-06-13 16:05:13 +02:00

11 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
11-catalog-database-view-ux-legacy-consolidation 04 ui
react
nextjs
tailwind
server-actions
catalog
inline-edit
tags
search
phase plan provides
11-catalog-database-view-ux-legacy-consolidation 11-02 ServiceWithTags type, getAllServices(), updateServiceField/quickAddService/addTagToService/removeTagFromService server actions
phase plan provides
11-catalog-database-view-ux-legacy-consolidation 11-03 EditableCell (text/number/textarea/toggle) and TagMultiSelect shared UI primitives
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)
12
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
created modified deleted
src/app/admin/catalog/CatalogSearch.tsx
src/components/admin/catalog/ServiceTable.tsx
src/app/admin/catalog/page.tsx
src/components/admin/catalog/ServiceForm.tsx
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.
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
OFFER-07
OFFER-08
OFFER-09
OFFER-10
12min 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

Self-Check: PASSED

  • FOUND: src/components/admin/catalog/ServiceTable.tsx
  • FOUND: src/app/admin/catalog/page.tsx
  • FOUND: src/app/admin/catalog/CatalogSearch.tsx
  • CONFIRMED DELETED: src/components/admin/catalog/ServiceForm.tsx
  • FOUND: .planning/phases/11-catalog-database-view-ux-legacy-consolidation/11-04-SUMMARY.md
  • FOUND commit: c0bedf3
  • FOUND commit: 912a892
  • FOUND commit: 9bc1e43