82 lines
4.7 KiB
Markdown
82 lines
4.7 KiB
Markdown
---
|
|
phase: quick
|
|
plan: 260420-vk0
|
|
subsystem: admin
|
|
tags: [bugfix, uat, image-upload, routing, tags]
|
|
dependency_graph:
|
|
requires: []
|
|
provides: [image-fetch-preview, tag-duplicate-error, tag-form-polish]
|
|
affects: [src/server/routes/images.ts, src/client/routes/admin/items/$itemId.tsx, src/server/routes/admin-tags.ts, src/client/routes/admin/tags/index.tsx]
|
|
tech_stack:
|
|
added: []
|
|
patterns: [presigned-url-passthrough, api-error-message-surfacing, card-form-pattern]
|
|
key_files:
|
|
created: []
|
|
modified:
|
|
- src/server/routes/images.ts
|
|
- src/client/routes/admin/items/$itemId.tsx
|
|
- src/server/routes/admin-tags.ts
|
|
- src/client/routes/admin/tags/index.tsx
|
|
decisions:
|
|
- "ApiError.message carries the server's error field from JSON response body — no custom parsing needed in catch blocks"
|
|
- "Task 2 (tag routing) was already resolved by commit 31a9e3c before this quick task ran — no changes needed"
|
|
metrics:
|
|
duration: "~8 minutes"
|
|
completed: "2026-04-20"
|
|
tasks_completed: 3
|
|
files_modified: 4
|
|
---
|
|
|
|
# Quick Task 260420-vk0: Fix UAT Issues — Image Fetch Preview, Tag Routing, Duplicate Error, Form UX
|
|
|
|
**One-liner:** Presigned URL passthrough to client fixes fetch-from-URL image preview; 409 unique constraint handler + card-form polish closes tag UAT gaps.
|
|
|
|
## Tasks Completed
|
|
|
|
| Task | Status | Commit | Files |
|
|
|------|--------|--------|-------|
|
|
| 1: Fix image fetch-from-URL preview and cropping | Done | b41b832 | images.ts, $itemId.tsx |
|
|
| 2: Fix tag edit page routing | Done (pre-existing) | 31a9e3c | routeTree.gen.ts (prior commit) |
|
|
| 3: Handle duplicate tag name error + polish inline form | Done | 113e689 | admin-tags.ts, tags/index.tsx |
|
|
|
|
## What Was Built
|
|
|
|
**Task 1 — Image fetch-from-URL preview:**
|
|
- `images.ts`: Added `getImageUrl` import from storage service; after `fetchImageFromUrl` completes, calls `getImageUrl(result.filename)` to generate a presigned URL and includes it in the response as `presignedUrl`.
|
|
- `$itemId.tsx`: Updated `handleFetchFromUrl` type annotation to include `presignedUrl` and `dominantColor`; after successful fetch, sets `imageUrl: result.presignedUrl` and `dominantColor` in form state. This causes `ImageUpload` to receive the presigned URL via its `imageUrl` prop and render the image preview immediately, making the crop button visible and functional.
|
|
|
|
**Task 2 — Tag edit page routing:**
|
|
Already resolved by commit 31a9e3c (which moved both items and tags to directory-based routing: `items/index.tsx` + `items/$itemId.tsx` / `tags/index.tsx` + `tags/$tagId.tsx`). The route tree correctly registers `AdminTagsTagIdRoute` and `AdminTagsIndexRoute` as siblings under `AdminRoute`. No additional changes required.
|
|
|
|
**Task 3 — Duplicate tag name error + form polish:**
|
|
- `admin-tags.ts`: Wrapped `createTag` in try/catch; detects SQLite UNIQUE constraint violations by checking `err.message` for "UNIQUE constraint failed" or "unique constraint", returning `{ error: "A tag named \"X\" already exists" }` with status 409.
|
|
- `tags/index.tsx`: Updated `handleCreate` catch to use `err instanceof Error ? err.message : "Failed to create tag"` — `ApiError` (thrown by `apiPost`) carries the server's `error` field as its message, so the friendly 409 message surfaces directly.
|
|
- `tags/index.tsx`: Replaced bare flex-row form with card-style wrapper (`rounded-xl border border-gray-100 bg-white p-4`), section header, field labels for Name and Parent, and `shrink-0` on the submit button. Error message moved inside the card below the form.
|
|
|
|
## Deviations from Plan
|
|
|
|
### Pre-resolved Issues
|
|
|
|
**Task 2 already fixed before this quick task ran**
|
|
- **Found during:** Investigation of tag routing
|
|
- **Issue:** Plan described investigating why `/admin/tags/$tagId` showed the list — but commit 31a9e3c (landed same day, prior to this quick task) already moved tag routes to directory structure and regenerated the route tree. Routes are correctly registered as siblings under AdminRoute.
|
|
- **Action taken:** Verified route tree, confirmed no changes needed, documented as pre-resolved. Continued to Task 3.
|
|
|
|
## Known Stubs
|
|
|
|
None. All implemented functionality is wired to real data.
|
|
|
|
## Threat Flags
|
|
|
|
None. No new network endpoints or auth paths introduced.
|
|
|
|
## Self-Check: PASSED
|
|
|
|
- [x] `src/server/routes/images.ts` exists and contains `getImageUrl` import and `presignedUrl` in response
|
|
- [x] `src/client/routes/admin/items/$itemId.tsx` contains `result.presignedUrl` and `imageUrl: result.presignedUrl` in form state update
|
|
- [x] `src/server/routes/admin-tags.ts` contains try/catch with 409 for UNIQUE constraint
|
|
- [x] `src/client/routes/admin/tags/index.tsx` contains card-style form with labels
|
|
- [x] Commit b41b832 exists (Task 1)
|
|
- [x] Commit 113e689 exists (Task 3)
|
|
- [x] `bun run lint` passes with no errors
|