- 11-04-SUMMARY.md documents ServiceTable database-view rewrite + CatalogSearch - deferred-items.md: log now-unused createService/serviceSchema in actions.ts (item 6)
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 |
|
|
|
|
|
|
|
|
|
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.tsxfully rewritten as a database-view table: 6 columns (Nome, Descrizione, Categoria, Prezzo, Tag, Stato), every cell rendered viaEditableCell(text/textarea/number/toggle) orTagMultiSelect, no "Azioni" column (D-14).ServiceRowwires each field'sonSavetoupdateServiceField(service.id, field, value)and the tags column toTagMultiSelect'sonTagsChanged; both callrouter.refresh()after the server action resolves. Per-row save errors render inline via acolSpan={6}trailing cell without affecting row height in the success path.QuickAddRowrenders a borderlessInputwith placeholder "+ Aggiungi servizio"; pressing Enter with non-empty text callsquickAddService(name), clears the input, and refreshes (D-12).- Services are partitioned into
activeServices/inactiveServices; active services render first, thenQuickAddRow, then (if any) a "Servizi disattivati" divider row followed by inactive services withopacity-50(D-13). - New
src/app/admin/catalog/CatalogSearch.tsxclient component: holds search query state, filtersServiceWithTags[]bynameor anytags[]entry (case-insensitive substring match) viauseMemo, and rendersServiceTablewith the filtered list — purely client-state, norouter.push/refresh/<form>(OFFER-10). page.tsxrewritten: remains an async Server Component callinggetAllServices(), no longer importsServiceForm, rendersCatalogSearch(or the existing "Nessun servizio..." message, reworded to point at the table's quick-add row, when the catalog is empty).ServiceForm.tsxdeleted entirely — its "+ Aggiungi servizio" full-form creation flow is fully replaced byServiceTable'sQuickAddRow.npx tsc --noEmit: zero errors project-wide.npx eslinton 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:
- Task 1: Rewrite ServiceTable as database-view (inline edit, tags, quick-add, active/inactive split) -
c0bedf3(feat) - 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,ServiceTablewith active/inactive split and "Servizi disattivati" dividersrc/app/admin/catalog/CatalogSearch.tsx- New client component: search input (LucideSearchicon) +useMemoname/tag filter wrappingServiceTablesrc/app/admin/catalog/page.tsx- RemovedServiceFormimport/render; now rendersCatalogSearchwithServiceWithTags[]fromgetAllServices()src/components/admin/catalog/ServiceForm.tsx- Deleted (102 lines); quick-add functionality fully replaced byServiceTable'sQuickAddRow
Decisions Made
- Left
createService(and theserviceSchemazod validator it shares withupdateService) insrc/app/admin/catalog/actions.tsas now-unused dead code, rather than editingactions.ts— that file was not in this plan'sfiles_modifiedscope, andupdateServicestill depends onserviceSchema. Logged todeferred-items.md(item #6) for a future cleanup pass. - Followed the plan's prescribed code for
ServiceTable.tsx/CatalogSearch.tsx/page.tsxverbatim — no changes needed to satisfy lint/typecheck (unlike Plan 03'sEditableCell, nouseEffect/ref patterns were introduced here that would triggerreact-hooks/set-state-in-effectorreact-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):
CatalogSearchreceives the fullServiceWithTags[](including inactive services) regardless of search query — same as pre-Phase-11ServiceTable, and/admin/catalogremains behind the Auth.js admin session guard. - T-11-15 (Tampering, mitigate):
QuickAddRowusesstartTransitionand only clears the input on a successfulquickAddServiceresolve; 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/catalognow 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
tagstable 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, perSTATE.mdBlockers. 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()/updateServiceFieldetc. are the now-proven query/action/UI stack forservices— Phase 12 (Offer Composition Drag&Drop & CSV Import) can build on this same foundation when rewiring/admin/offersto read fromservices. - Cleanup candidate (non-blocking):
createService/serviceSchemadead code insrc/app/admin/catalog/actions.ts(deferred-items.md #6).
Phase: 11-catalog-database-view-ux-legacy-consolidation Completed: 2026-06-13