feat(admin): add Taxonomy Types management page#213
Conversation
Add a full CRUD admin UI for managing taxonomy definitions, similar to Content Types. Previously, custom taxonomies could only be created via the API but had no way to be listed, edited, or deleted from the admin interface. Changes: - Add GET/PUT/DELETE API endpoints for single taxonomy definitions - Add updateTaxonomy/deleteTaxonomy client functions - Add TaxonomyTypeList and TaxonomyTypeEditor components - Add /taxonomy-types, /taxonomy-types/new, /taxonomy-types/$name routes - Add "Taxonomy Types" entry in the Admin sidebar section - Make taxonomy sidebar entries dynamic (fetched from API) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
All contributors have signed the CLA ✍️ ✅ |
|
Can you
I created Custom Plugin for that. |
The confirm dialog remained open after successfully deleting a taxonomy, causing errors on subsequent clicks. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
I have read the CLA Document and I hereby sign the CLA |
- Add custom field definitions for taxonomy types using the same FieldEditor dialog UI from content types (14 field types with full configuration) - Add SEO metadata support for taxonomy terms (title, description, image) - Add features system (drafts, revisions, preview, search) mirroring content types feature toggles - Add content visibility system (public/members/private) across all content collections - Add PUT /api/auth/me endpoint for profile self-service - Migrations 033-036: content visibility, taxonomy fields, taxonomy SEO, taxonomy supports columns Addresses feedback from PR emdash-cms#213 review (tohaitrieu): - Custom field definitions on taxonomy types - SEO metadata for taxonomy terms Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The users table already has a JSON `data` column for extensible user metadata, but it was not exposed in any API endpoint. Now available in: - GET /api/auth/me — returns user.data - PUT /api/auth/me — accepts data (merge with existing keys) - PUT /api/admin/users/:id — accepts data (admin override) - GET /api/admin/users/:id — returns user.data - Response schemas updated to include data field No migration needed — the column has existed since migration 001. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend for custom role definitions with configurable permissions: - Migration 037: _emdash_role_defs table with 5 built-in roles seeded - RoleRegistry in-memory cache for custom role permission lookups - Extended hasPermission() to support custom roles via registry - Relaxed toRoleLevel() and roleLevel Zod schema for custom levels (1-99) - CRUD API: GET/POST /api/roles, GET/PUT/DELETE /api/roles/:name - Built-in roles are protected: cannot delete or change their permissions - Deleting a custom role reassigns affected users to subscriber - Admin API client with ALL_PERMISSIONS reference for UI - Custom metadata fields support (reuses FieldEditor field definitions) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- RoleTypeList: list all roles (built-in + custom) with CRUD actions - RoleTypeEditor: create/edit roles with permission picker and metadata fields - RoleBadge: dynamically fetches custom roles for labels and colors - InviteUserModal, UserDetail, UserList: use dynamic roles in dropdowns - Sidebar: add Role Types nav entry under Admin section - Router: add /role-types, /role-types/new, /role-types/$name routes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The /roles and /roles/[name] endpoints were returning 404 because they were not injected via injectCoreRoutes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
There was a problem hiding this comment.
Approach judgment
This PR bundles a large set of features: taxonomy type CRUD, custom role definitions, content visibility, taxonomy term SEO, and profile self-service. While taxonomy type management addresses real feedback, the PR is architecturally incomplete in two critical ways:
-
Content visibility is a UI-only placebo. The
visibilitycolumn is added to every content table and the admin UI lets editors change it, but nothing in the list/get handlers or the sitemap generator filters by it."Members-only" and "private" content is still returned publicly. -
Custom roles permissions are non-functional. The PR adds a
_emdash_role_defstable, aRoleRegistryclass, and a full permissions UI, but the API authorization layer (requirePerminpackages/core/src/api/authorize.ts) never instantiates or consults the registry. Custom roles fall back to numeric level comparison, making their explicit permission arrays a no-op.
These are not edge-case bugs; they are headline features that do not work as described.
Additionally, the PR modifies published packages (emdash, @emdash-cms/admin) with new user-facing behavior but includes no changeset, which violates the AGENTS.md release workflow.
Line-level findings
Content visibility stored but never enforced
handleContentListfilters bystatusandlocalebut nevervisibility, so private content is returned in admin lists.handleContentGetdoes not check visibility before returning an item.- The sitemap SQL query selects all published, non-deleted content without filtering out
membersorprivaterows.
Custom role permissions ignored
requirePermcallshasPermission(user, permission)without aRoleRegistry. The runtime never loads role definitions, so custom roles always use numeric comparison.
Taxonomy bulk delete leaves orphaned SEO rows
handleTaxonomyDeleteloops through terms and callsTaxonomyRepository.delete(), which removes junction rows and term rows but does NOT delete_emdash_seoentries. The individualhandleTermDeleteroute does clean up SEO, but the bulk path does not.
Field type mismatch between taxonomy schema and FieldEditor
- The server-side
TaxonomyFieldDeftype only covers 6 types (and includes"textarea"which isn't in the Zod schema). The client schema and PR description claim 14 types, but the sharedFieldEditorcomponent only supportsFieldTypevalues and does not list"url"or"color". Users can't create url/color taxonomy/role fields through the admin UI, and unsafe casts inTaxonomyTypeEditorandRoleTypeEditorhide the mismatch from TypeScript.
Recommendation
Fix the visibility enforcement, wire up the RoleRegistry in authorization middleware, add SEO cleanup to handleTaxonomyDelete, align the field types with what FieldEditor actually supports, and add a changeset before merge.
Summary
Changes
Server-side (packages/core)
GET/PUT/DELETE /_emdash/api/taxonomies/:namefor single taxonomy definition operationshandleTaxonomyGet,handleTaxonomyUpdate,handleTaxonomyDeletein taxonomies handlerupdateTaxonomyDefBodyfor PUT validationtaxonomy:{name}collection keyec_*content tablesAdmin UI (packages/admin)
/taxonomy-types,/taxonomy-types/new,/taxonomy-types/$nameAddresses PR review feedback
Test plan
🤖 Generated with Claude Code