From 9e49e52bc0439f00737b96227608b4cbcf6d287d Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Sun, 19 Apr 2026 21:50:37 +0200 Subject: [PATCH] docs(38): capture phase context --- .../38-admin-tag-management/38-CONTEXT.md | 132 ++++++++++++++++ .../38-DISCUSSION-LOG.md | 149 ++++++++++++++++++ 2 files changed, 281 insertions(+) create mode 100644 .planning/phases/38-admin-tag-management/38-CONTEXT.md create mode 100644 .planning/phases/38-admin-tag-management/38-DISCUSSION-LOG.md diff --git a/.planning/phases/38-admin-tag-management/38-CONTEXT.md b/.planning/phases/38-admin-tag-management/38-CONTEXT.md new file mode 100644 index 0000000..a719879 --- /dev/null +++ b/.planning/phases/38-admin-tag-management/38-CONTEXT.md @@ -0,0 +1,132 @@ +# Phase 38: Admin — Tag Management - Context + +**Gathered:** 2026-04-19 +**Status:** Ready for planning + + +## Phase Boundary + +Build the `/admin/tags` list and `/admin/tags/$tagId` edit page, wired into the Phase 36 admin shell. Admins can browse all tags in a collapsible tree view, create new tags via a quick-add form, rename/reparent tags on a dedicated edit page, and delete tags with an impact-aware confirmation. Adds `parentId` to the tags table to enable arbitrary-depth parent-child hierarchy. + +No new capabilities beyond create/rename/reparent/delete and hierarchy visualization. + + + + +## Implementation Decisions + +### Schema Migration +- **D-01:** Add `parentId integer REFERENCES tags(id) ON DELETE SET NULL NULLABLE` to the `tags` table via Drizzle migration. Self-referential FK — no depth limit at the schema level. +- **D-02:** On parent deletion, `ON DELETE SET NULL` orphans children (they become top-level). No cascading child deletion. + +### List View — Collapsible Tree +- **D-03:** Collapsible tree view (not a flat table). Parent tags render rows; children are indented below. All nodes start expanded on page load. +- **D-04:** Columns: Name (with indent level visual) | Item Count | Actions. +- **D-05:** Search/filter mode: filter in-tree — non-matching rows are hidden in place. Parents with matching children remain visible; non-matching leaf nodes are hidden. +- **D-06:** No separate "Children Count" column — children are visible in the tree structure below each parent. + +### Create UX +- **D-07:** Quick-add form at the top of the tag list (not a separate page). Fields: name + optional parent picker. Submits inline without navigation. + +### Edit UX +- **D-08:** Dedicated edit page at `/admin/tags/$tagId` — consistent with Phase 37 item edit pattern. Fields: name + parent picker. +- **D-09:** Delete lives on the edit page (not the list), following Phase 37 D-05. + +### Hierarchy Depth +- **D-10:** Arbitrary depth — any tag can be a parent of any other (no 1-level limit). Future-proofed for deep taxonomies. +- **D-11:** Cycle prevention is dual-layer: + - **Client**: Parent picker filters out the tag's own descendants from the dropdown options. + - **Server**: API validates that the new parent is not a descendant of the tag being updated. Returns 400 with a clear error message if a cycle is detected. + +### Delete Behavior +- **D-12:** Deleting a tag orphans its children — they become top-level tags (`parentId` SET NULL via FK cascade). +- **D-13:** Delete confirmation dialog shows: item count + child count warning. Example: "Delete 'sleeping-bag'? 12 items use this tag. Its 3 child tags will become top-level. This cannot be undone." +- **D-14:** If a tag has 0 items and 0 children, the confirmation is simplified: "Delete 'sleeping-bag'? This cannot be undone." + +### Claude's Discretion +- Exact visual styling of tree indentation (border-left line, chevron icon, or indent padding) +- Whether to use a chevron toggle button or click-to-collapse on the row +- Implementation of the collapsible tree (local component state vs. Zustand) +- Exact error message copy for cycle detection rejection +- Whether to add a "Move to top-level" shortcut on the edit page in addition to the parent picker + + + + +## Canonical References + +**Downstream agents MUST read these before planning or implementing.** + +### Existing Tag Infrastructure +- `src/server/services/tag.service.ts` — `getAllTags`; extend with CRUD functions (createTag, updateTag, deleteTag, getTagWithCounts) +- `src/server/routes/tags.ts` — existing `GET /api/tags`; admin CRUD routes go under `/api/admin/tags` +- `src/db/schema.ts` — `tags` table (currently `id`, `name`, `createdAt`); add `parentId` here + +### Admin Infrastructure (Phase 36/37) +- `src/server/routes/admin-items.ts` — admin item routes pattern; follow same structure for admin tag routes +- `src/server/middleware/auth.ts` — `requireAdmin` middleware +- `src/client/routes/admin.tsx` — admin shell layout with ``; "Tags" nav item needs to be enabled (remove cursor-not-allowed, add active Link) +- `src/client/routes/admin/index.tsx` — admin index placeholder (unchanged) +- `src/client/routes/admin/items.tsx` — list page pattern to follow +- `src/client/routes/admin/items.$itemId.tsx` — edit page pattern to follow + +### Client Hooks +- `src/client/hooks/useTags.ts` — existing hook; extend or create `useAdminTags` following `useAdminGlobalItems` pattern +- `src/client/hooks/useAdminGlobalItems.ts` — pattern to follow for admin tag hooks +- `src/client/lib/api.ts` — `apiGet`, `apiPost`, `apiPut`, `apiDelete` fetch wrappers + +### Requirements +- `.planning/REQUIREMENTS.md` — ADMN-05, ADMN-06, ADMN-07, ADMN-08, ADMN-09, ADMN-10 + + + + +## Existing Code Insights + +### Reusable Assets +- `getAllTags` service function: returns `id` + `name` — extend to include `parentId`, `itemCount`, `childCount` +- `apiGet`, `apiPost`, `apiPut`, `apiDelete` from `src/client/lib/api.ts` — same fetch wrappers as Phase 37 +- Admin shell sidebar: "Tags" entry already exists (Phase 36) but is disabled — just enable the Link + +### Established Patterns +- Admin list page: See `src/client/routes/admin/items.tsx` for the search + table + infinite scroll pattern +- Admin edit page: See `src/client/routes/admin/items.$itemId.tsx` for the form + delete-at-bottom pattern +- React Query hooks: `useAdminGlobalItems` is the pattern for admin data hooks +- Delete confirmation: Destructive modal pattern already used in Phase 37 item delete + +### Integration Points +- `src/client/routes/admin.tsx`: Change "Tags" sidebar entry from disabled `
` to `` +- `src/server/routes/admin.ts` (or `src/server/index.ts`): Register admin tag routes under `/api/admin/tags` +- `src/db/schema.ts` + Drizzle migration: Add `parentId` column to `tags` table + +### Key Absence +- No tree component exists in the codebase — this must be built from scratch. Keep it simple: Tailwind indentation + local expand/collapse state. + + + + +## Specific Ideas + +- Tree row indent: 16-24px per level, visual hierarchy via a subtle left border or padding (consistent with app's minimal aesthetic) +- Chevron/triangle icon (▶/▼) on parent rows to toggle expand/collapse +- Quick-add form at top of list: name input + parent picker dropdown + "Add" button +- Edit page back link: "← Tags" to return to list (same as Phase 37's "← Items") +- Delete button at bottom of edit form, styled destructive red +- Parent picker on edit page: searchable dropdown that excludes the tag itself and all its descendants + + + + +## Deferred Ideas + +- Drag-to-reparent: drag a tag row onto a parent to reassign hierarchy — complex UX, out of scope for Phase 38 +- Bulk operations (bulk delete, bulk reparent) — single-item workflow only in this phase +- Tag merge (merge two tags into one, reassigning all items) — separate capability, future milestone +- Tag usage analytics (which tags are most used, fastest growing) — deferred to v2.5 engagement stats + + + +--- + +*Phase: 38-admin-tag-management* +*Context gathered: 2026-04-19* diff --git a/.planning/phases/38-admin-tag-management/38-DISCUSSION-LOG.md b/.planning/phases/38-admin-tag-management/38-DISCUSSION-LOG.md new file mode 100644 index 0000000..b8a76a7 --- /dev/null +++ b/.planning/phases/38-admin-tag-management/38-DISCUSSION-LOG.md @@ -0,0 +1,149 @@ +# Phase 38: Admin — Tag Management - Discussion Log + +> **Audit trail only.** Do not use as input to planning, research, or execution agents. +> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered. + +**Date:** 2026-04-19 +**Phase:** 38-admin-tag-management +**Areas discussed:** Create/Edit UX, Hierarchy display in list, Delete scope for parent tags, Hierarchy depth + +--- + +## Create / Edit UX + +| Option | Description | Selected | +|--------|-------------|----------| +| Inline modal for both | Single modal handles create AND edit. No separate route. | | +| Dedicated edit page (like Phase 37) | Consistent with items pattern at /admin/tags/$tagId. | ✓ | +| Inline table editing | Click-to-edit in table rows. | | + +**User's choice:** Dedicated edit page for editing (consistent with Phase 37 pattern) + +--- + +## Create UX (follow-up) + +| Option | Description | Selected | +|--------|-------------|----------| +| Quick-add row / form at top of list | Name input + parent picker inline at list top. | ✓ | +| New tag via /admin/tags/new page | Dedicated page for creation. | | + +**User's choice:** Quick-add form at the top of the tag list + +--- + +## Hierarchy display in list + +| Option | Description | Selected | +|--------|-------------|----------| +| Flat table with Parent column | Each row shows parent name, consistent with Phase 37. | | +| Indented tree view | Children indented below parents, hierarchical visualization. | ✓ | + +**User's choice:** Indented tree view + +--- + +## Tree + Filter behavior + +| Option | Description | Selected | +|--------|-------------|----------| +| Flatten on search | Switch to flat list when searching. | | +| Filter in-tree | Hide non-matching rows in place, keep tree structure. | ✓ | + +**User's choice:** Filter in-tree (non-matching rows hidden, matching stay in place) + +--- + +## Tree columns + +| Option | Description | Selected | +|--------|-------------|----------| +| Name + Item Count + Actions | Clean, minimal. | ✓ | +| Name + Item Count + Children Count + Actions | Explicit child count. | | + +**User's choice:** Name + Item Count + Actions + +--- + +## Delete scope for parent tags + +| Option | Description | Selected | +|--------|-------------|----------| +| Orphan children (become top-level) | Children lose parent, become top-level. | ✓ | +| Block deletion until reparented | Admin must reparent children first. | (initially selected, then pivoted) | +| Cascade delete children | Children deleted with parent. | | + +**User's choice:** Initially selected "Block deletion until reparented", then pivoted to "Orphan children (become top-level)" — user said "the moving up ain't too bad, i think we should pivot to that" + +--- + +## Delete confirmation dialog + +| Option | Description | Selected | +|--------|-------------|----------| +| Show item count + child count warning | "12 items use this tag. Its 3 child tags will become top-level." | ✓ | +| Show item count only | Children silently become top-level with no warning. | | + +**User's choice:** Show item count + child count warning + +--- + +## Hierarchy depth + +| Option | Description | Selected | +|--------|-------------|----------| +| Strictly 1 level deep | Parent/child only. Simpler schema and rendering. | | +| Arbitrary depth | Any tag can be a parent. Cycle detection needed. | ✓ | + +**User's choice:** Arbitrary depth — user said "if we don't do this right now we could hurt ourselves at some point, build it so it can handle however deep we want" + +--- + +## Cycle prevention + +| Option | Description | Selected | +|--------|-------------|----------| +| Server-side validation only | API rejects cycles. | | +| Filter parent picker in UI too | Dropdown excludes descendants. | | +| Both | UI filters + server validates. | ✓ | + +**User's choice:** Both — "to prevent api mishaps" + +--- + +## Tree expand/collapse + +| Option | Description | Selected | +|--------|-------------|----------| +| All expanded, no collapse | Simple. | | +| Collapsible nodes | Parents can be expanded/collapsed. | ✓ | + +**User's choice:** Collapsible nodes + +--- + +## Initial expand state + +| Option | Description | Selected | +|--------|-------------|----------| +| All expanded | Everything visible on load. | ✓ | +| Top-level only (children collapsed) | Admin expands on demand. | | + +**User's choice:** All expanded on page load + +--- + +## Claude's Discretion + +- Exact visual styling of tree indentation +- Whether chevron or click-on-row to collapse +- Collapsible tree implementation (local state vs. Zustand) +- Exact error message copy for cycle detection +- "Move to top-level" shortcut on edit page + +## Deferred Ideas + +- Drag-to-reparent — complex UX, out of scope +- Bulk operations — single-item workflow for Phase 38 +- Tag merge — future milestone +- Tag analytics — v2.5