Hierarchical labels: model, CRUD API, and validation #43
Labels
No Label
area:auth
area:docs
area:export
area:ops
area:storage
area:supply-chain
auth
backend
blocked
collab
deployment
docs
effort:L
effort:M
effort:S
frontend
plugins
qa
vs-nfd
vs-nfd:blocker
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: stwaidele/dorfteich#43
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Labels organize pages within a pond and can be hierarchical (vision); they later scope permissions (M5), so their semantics must be solid now.
Scope
Prisma models
labels(withparent_id) andpage_labelsper data-model.md; endpoints: label CRUD under/ponds/:id/labels(create with optional parent, rename, recolor, move in hierarchy, delete with page-assignment handling — deletion detaches assignments after a confirmation flag), assign/unassign labels to pages. Validation: cycle prevention on move, unique name per (pond, parent), depth limit 6.Acceptance criteria
?force=trueand detaches themTechnical notes
packages/sharedor a service both can use).Dependencies
Depends on #23.
Size: ~1.5 days
Conventions: English code/comments, clear human-readable code, no hard-coded UI strings (ADR 0012, add
deanden), permission checks only via the shared guard (docs/architecture/permissions.md). Read the referenced ADRs before starting.Implemented in
a3a012c41dad642fb26377edb0776ba49d1e3a01(Claude Opus 4.8). Pipeline green (CI: lint/typecheck/test, auth-e2e, container build; CD: deploy Test → smoke → promote Int).Live-verified on Test (
test.dorfteich.cloud) end to end:GET /ponds/:id/labels) — root → child nested. ✓409 label_cycle. ✓409 label_has_pages(details.count);?force=true→204, and the delete cascades the subtree and detaches the page assignment (page's label list back to[]). ✓400 label_wrong_pond, covered by the DB test).Design notes
packages/shared/labels.ts(buildLabelTree,collectSubtreeIds,collectAncestorIds,labelDepth,subtreeHeight) — the same tree logic the M5 permission resolver will reuse (permissions.md: a grant on a label applies to all descendants).pg_advisory_xact_locktransaction, so root-label uniqueness holds despite Postgres treatingNULLparents as distinct in the unique index.page_labels; page purge also removes assignments.InterimAccessServiceon the owning pond (see = read labels, modify = manage) — M5 (#53) swaps this for real grants./ponds/:id/labels, mutations by id under/labels/:id.DB e2e (
labels.service.db.test.ts, runs in CI) covers all acceptance criteria plus depth limit, cascade, idempotent assign/unassign, and outsider access denial. Label UI (tree management, assignment, sidebar filter) is #44.