Skip to main content

Content Subcategory

Overview

Content Subcategory sits beneath Content Category and can nest several levels deep as a tree. Depth is capped by the MAX_SUBCATEGORY_LEVEL constant, which counts the category itself as level one and permits four further levels of subcategories.

Because it models a tree, this module exposes considerably more endpoints than a flat category would: retrieving the full tree, retrieving an indented hierarchical dropdown, resolving the path from root to node for breadcrumbs, and reordering how items are displayed.

Soft deletes use a plain deleted_date column rather than gorm.DeletedAt, so every read must add deleted_date IS NULL itself and the delete is issued as a manual UPDATE.

Business Flow

  1. GET /api/content-subcategories lists every subcategory per QueryContentSubcategoryDto.
  2. GET /api/content-subcategories/dropdown returns a flat dropdown.
  3. Several endpoints operate within a single parent category.
    • GET /api/content-subcategories/by-category/:categoryId lists that category's children.
    • GET /api/content-subcategories/by-category/:categoryId/dropdown returns a dropdown scoped to that category.
    • GET /api/content-subcategories/by-category/:categoryId/tree returns the full tree for tree-style UIs.
    • GET /api/content-subcategories/by-category/:categoryId/hierarchical-dropdown returns a dropdown indented by depth.
  4. GET /api/content-subcategories/:id/path returns the path from the root category to the current node, for rendering breadcrumbs.
  5. POST /api/content-subcategories creates a subcategory, verifying the depth cap is not exceeded.
  6. GET /api/content-subcategories/:id returns details and PATCH /api/content-subcategories/:id updates them.
  7. PATCH /api/content-subcategories/reorder/sort-order accepts a {items: [{id, sortOrder}]} body to reorder many entries in a single request.
  8. DELETE /api/content-subcategories/:id with an optional force parameter deletes a subcategory. The request is normally rejected if child subcategories or linked content still exist; force overrides that check.

Key Files & Functions

Core code lives in internal/modules/contentsubcategory/, comprising controller.go, service.go, and dto.go, registered on the authed.Group("/content-subcategories") group.

MethodRouteHandlerPolicy (metadata)
GET/api/content-subcategoriesct.findAllreadAll line-oa
GET/api/content-subcategories/dropdownct.getDropdownreadAll line-oa
GET/api/content-subcategories/by-category/:categoryIdct.findByCategoryIDreadAll line-oa
GET/api/content-subcategories/by-category/:categoryId/dropdownct.getDropdownByCategoryIDreadAll line-oa
GET/api/content-subcategories/by-category/:categoryId/treect.getTreeByCategoryIDreadAll line-oa
GET/api/content-subcategories/by-category/:categoryId/hierarchical-dropdownct.getHierarchicalDropdownByCategoryIDreadAll line-oa
GET/api/content-subcategories/:id/pathct.getPathread line-oa
GET/api/content-subcategories/:idct.findOneread line-oa
POST/api/content-subcategoriesct.createcreate line-oa
PATCH/api/content-subcategories/reorder/sort-orderct.updateSortOrderupdate line-oa
PATCH/api/content-subcategories/:idct.updateupdate line-oa
DELETE/api/content-subcategories/:idct.removedelete line-oa

The depth limit is held in the maxSubcategoryLevel constant, ported from MAX_SUBCATEGORY_LEVEL.

Connections to Other Services

  • Access control — requests must pass global JwtAuth. The policy metadata is PolicyModuleLineOa and is not yet enforced; there is no ModuleGate.
  • Tablescontent_subcategory, content_category, content_page, line_oa
  • Context — reads lineOaId and organizationId from CLS to scope queries.
  • Related modules — Content Category, Content Page, and Public API.