docs(38-02): complete admin tag management client UI plan

- Add 38-02-SUMMARY.md
- Advance STATE.md to 38-02 complete
- Mark 38-02-PLAN.md complete in ROADMAP.md
This commit is contained in:
2026-04-19 22:33:36 +02:00
parent 0571ee47fb
commit 6a5ffe8e2f
3 changed files with 100 additions and 6 deletions

View File

@@ -280,7 +280,7 @@ Plans:
Plans:
- [x] 38-01-PLAN.md — Schema migration (parentId), service layer (CRUD + cycle detection), API routes, tests
- [ ] 38-02-PLAN.md — Client hooks, tag list page (tree view + quick-add + search), edit page (rename/reparent/delete), sidebar activation
- [x] 38-02-PLAN.md — Client hooks, tag list page (tree view + quick-add + search), edit page (rename/reparent/delete), sidebar activation
**UI hint**: yes

View File

@@ -3,8 +3,8 @@ gsd_state_version: 1.0
milestone: v2.4
milestone_name: Admin Foundation
status: executing
stopped_at: Completed 35-03-PLAN.md — FIX-05 (cursor-pointer audit) resolved
last_updated: "2026-04-19T20:29:07.741Z"
stopped_at: Completed 38-02-PLAN.md — admin tag management client UI
last_updated: "2026-04-19T20:32:22Z"
last_activity: 2026-04-19
progress:
total_phases: 20
@@ -30,7 +30,7 @@ Plan: 2 of 2
Status: Ready to execute
Last activity: 2026-04-19
Progress: [████████░] 94%
Progress: [████████░] 97%
## Performance Metrics
@@ -110,6 +110,6 @@ Items carried forward from v2.3:
## Session Continuity
Last session: 2026-04-19T20:29:07.738Z
Stopped at: Completed 35-03-PLAN.md — FIX-05 (cursor-pointer audit) resolved
Last session: 2026-04-19T20:32:22Z
Stopped at: Completed 38-02-PLAN.md — admin tag management client UI
Resume file: None

View File

@@ -0,0 +1,94 @@
---
phase: 38-admin-tag-management
plan: "02"
subsystem: client
tags: [admin, tags, react-query, tree-view, crud]
dependency_graph:
requires: ["38-01"]
provides: ["admin-tag-ui"]
affects: ["src/client/routes/admin/", "src/client/hooks/"]
tech_stack:
added: []
patterns:
- collapsible tree view with buildTree/flattenTree/filterTree utilities
- dual React Query key invalidation (admin-tags + tags)
- cycle-safe parent picker via getDescendantIds client-side filtering
- impact-aware delete confirmation (item count + child count)
key_files:
created:
- src/client/hooks/useAdminTags.ts
- src/client/routes/admin/tags.tsx
- src/client/routes/admin/tags.$tagId.tsx
modified:
- src/client/routes/admin.tsx
decisions:
- "buildTree/flattenTree/filterTree co-located in tags.tsx — pure JS utilities, no separate lib file needed"
- "Dual query key invalidation on all tag mutations keeps public tags cache fresh alongside admin cache"
- "getDescendantIds used client-side for parent picker filtering — server validates cycles authoritatively"
metrics:
duration: "2m"
completed: "2026-04-19"
tasks_completed: 2
tasks_total: 2
files_changed: 4
---
# Phase 38 Plan 02: Admin Tag Management Client UI Summary
React Query hooks, collapsible tree list page, edit page with cycle-safe reparent and impact-aware delete confirmation, and Tags sidebar link activated in the admin panel.
## Tasks Completed
| # | Name | Commit | Files |
|---|------|--------|-------|
| 1 | Client hooks + tag list page with tree view and quick-add | 1f8b85d | useAdminTags.ts, admin/tags.tsx |
| 2 | Tag edit page with rename, reparent, delete + sidebar link activation | 0571ee4 | admin/tags.$tagId.tsx, admin.tsx |
## What Was Built
### `src/client/hooks/useAdminTags.ts`
Five React Query hooks: `useAdminTags` (list), `useAdminTag` (single with 404 retry suppression), `useCreateAdminTag`, `useUpdateAdminTag`, `useDeleteAdminTag`. All mutations invalidate both `["admin-tags"]` and `["tags"]` to keep the public tag cache fresh.
### `src/client/routes/admin/tags.tsx`
Tag list page at `/admin/tags` with:
- `buildTree` — builds hierarchical tree from flat array with self-referential parent links
- `flattenTree` — depth-first flatten respecting the `expanded` Set for show/hide
- `filterTree` — recursive filter that preserves parent rows when descendants match
- Collapsible chevron-based tree rows with 20px-per-depth indentation
- Quick-add inline form with name input, parent picker (`No parent (top-level)` default), and "Add Tag" button
- Search input filtering tree in-place
- Skeleton loading, error state, two empty states (no tags / no search results)
### `src/client/routes/admin/tags.$tagId.tsx`
Tag edit page at `/admin/tags/$tagId` with:
- `getDescendantIds` — recursively collects all descendant IDs to exclude from parent picker (client-side cycle prevention)
- `getDeleteConfirmText` — builds contextual confirmation: item count warning + child count warning + "This cannot be undone."
- Name rename field and cycle-safe parent picker (`parentOptions` excludes self + all descendants)
- Delete confirmation modal with impact-aware body text per D-13/D-14
- Actions row: Delete Tag (left, destructive) / Save Changes (right, primary)
### `src/client/routes/admin.tsx`
Replaced the disabled `<div cursor-not-allowed>` Tags entry with an active `<Link to="/admin/tags">` following the Items link pattern. "Soon" badge removed.
## Deviations from Plan
None — plan executed exactly as written.
## Threat Surface Scan
No new network endpoints, auth paths, or schema changes introduced (client-only plan). T-38-05 admin shell guard already present in admin.tsx. T-38-06 client-side cycle prevention implemented as UX layer; server validates authoritatively.
## Self-Check: PASSED
- src/client/hooks/useAdminTags.ts: FOUND
- src/client/routes/admin/tags.tsx: FOUND
- src/client/routes/admin/tags.$tagId.tsx: FOUND
- src/client/routes/admin.tsx: modified (contains `to="/admin/tags"`, no `cursor-not-allowed`)
- Commit 1f8b85d: FOUND
- Commit 0571ee4: FOUND
- Build: PASSED (✓ built in 964ms)
- Tests: PASSED (500 pass, 0 fail)