Crop values were stored in DB but never passed back to ImageUpload on reload,
causing images to revert to object-contain. Now both admin and user item pages
pass persisted crop data so the cropped view displays correctly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Admin item edit page now uses the same ImageUpload component as the rest
of the app (file upload, preview, crop editor). Also adds a "Fetch from URL"
input that uses /api/images/from-url. Renames "Source URL" to "Product Page URL".
Backend updated to accept imageFilename, dominantColor, cropZoom/X/Y fields
and return presignedImageUrl for display.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Admin item/tag edit pages weren't rendering because TanStack Router treated
them as children of the list route (which had no Outlet). Moving to
directory-based routing (items/index.tsx + items/$itemId.tsx) makes them
siblings that render directly in the admin layout.
Also adds UAT results for phases 35-38 and backlog item 999.12 (Admin UX Polish).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create admin-tags.ts with GET list, GET single, POST, PUT (cycle guard → 400), DELETE
- Register /tags route in admin.ts
- Add 13-test integration suite covering CRUD, cycle detection, orphan behavior
- Add parentId self-ref FK to tags table (ON DELETE SET NULL)
- Generate Drizzle migration 0010_yielding_random.sql
- Extend tag.service.ts with getAdminTags, getTagWithCounts, createTag, updateTag, deleteTag, isDescendant
- Add service tests (14 tests, all pass)
Two plans across 2 waves: backend (schema + service + routes + tests)
then frontend (hooks + tree list page + edit page + sidebar activation).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Spacing: change tree row indent from pl-5 (20px) to pl-4 (16px); remove non-standard exception entry
- Copywriting: change delete confirmation button from "Delete" to "Delete Tag"
- Visuals: declare focal point for list page (tree view) and edit page (name input)
- Typography: lower Label/Display from 12px to 11px, establishing 3px gap above 14px body
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add listGlobalItemsForAdmin: paginated with batched tag/ownerCount queries
- Add updateGlobalItemById: partial update in transaction, syncs tags
- Add deleteGlobalItem: nullifies FK refs, removes tag associations before delete
- Create src/server/routes/admin-items.ts with GET/GET:id/PUT/DELETE endpoints
- Mount adminItemRoutes at /items in admin.ts (protected by requireAuth+requireAdmin)
- Extend global-item.service.test.ts with 13 new tests (all passing)
Closes ADMN-02, ADMN-03, ADMN-04 (server side)
Plans 37-01 (server: services + admin-items routes) and 37-02 (client:
hooks, list page, edit page, sidebar) with full acceptance criteria and
read_first blocks per phase context, research, and UI-SPEC artifacts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Import eq from drizzle-orm and users from schema
- Export requireAdmin(c, next) that returns 401 if userId not in context, 403 if user.isAdmin is falsy