# Categories Controller Documentation **File:** `controllers/admin/categories.controller.js` **Base URL:** `/api/admin/categories` **Guards:** `authenticate → requireAdmin() → adminLimiter` --- ## Table of Contents - [Get All Categories](#get-all-categories) - [Get Single Category](#get-single-category) - [Create Category](#create-category) - [Update Category](#update-category) - [Archive Category](#archive-category) - [Restore Category](#restore-category) --- ## Notes - `slug` is auto-generated from `name` on create and update: lowercased, trimmed, non-alphanumeric runs replaced with `-`. - `slug` and `name` must be **unique** across all categories (including archived ones). - `paranoid: false` is used on GET All and GET One, so archived categories are visible. --- ## Get All Categories **`GET /api/admin/categories`** Returns all categories ordered alphabetically by name. Includes archived rows. ### Response `200` ```json { "status": "success", "message": "Categories retrieved.", "data": [ { "id": 1, "name": "Business", "slug": "business", "description": "Business courses", "is_active": true, "createdAt": "2026-01-01T00:00:00.000Z", "updatedAt": "2026-01-01T00:00:00.000Z", "deletedAt": null } ] } ``` --- ## Get Single Category **`GET /api/admin/categories/:id`** Returns one category. Includes archived. ### Response `200` ```json { "status": "success", "message": "Category retrieved.", "data": { "id": 1, "name": "Business", "slug": "business", ... } } ``` ### Error Responses | Status | Message | |--------|---------| | `404` | `Category not found.` | --- ## Create Category **`POST /api/admin/categories`** ### Request Body | Field | Type | Required | Description | |-------|------|----------|-------------| | `name` | string | **Yes** | Display name. Must be unique. | | `description` | string | No | Optional description. | | `is_active` | boolean | No | Default: `true` | ### Response `201` ```json { "status": "success", "message": "Category created.", "data": { "id": 2, "name": "Design", "slug": "design", "is_active": true, ... } } ``` ### Error Responses | Status | Message | |--------|---------| | `400` | `name is required.` | | `409` | `A category with that name already exists.` | --- ## Update Category **`PUT /api/admin/categories/:id`** Full update. Only non-`null`/`undefined` fields are changed. `slug` is re-generated if `name` changes. ### Request Body | Field | Type | Required | Description | |-------|------|----------|-------------| | `name` | string | No | New display name. | | `description` | string | No | | | `is_active` | boolean | No | | ### Response `200` ```json { "status": "success", "message": "Category updated.", "data": { ... } } ``` ### Error Responses | Status | Message | |--------|---------| | `404` | `Category not found.` | | `409` | `A category with that name already exists.` | --- ## Archive Category **`DELETE /api/admin/categories/:id`** Soft-deletes the category (`deletedAt` set). ### Response `200` ```json { "status": "success", "message": "Category archived." } ``` ### Error Responses | Status | Message | |--------|---------| | `404` | `Category not found.` | --- ## Restore Category **`POST /api/admin/categories/:id/restore`** Restores a soft-deleted category. ### Response `200` ```json { "status": "success", "message": "Category restored.", "data": { ... } } ``` ### Error Responses | Status | Message | |--------|---------| | `404` | `Category not found.` |