# User Groups Controller Documentation **File:** `controllers/admin/user_groups.controller.js` **Base URL:** `/api/admin/groups` **Guards:** `authenticate → requireAdmin() → adminLimiter` --- ## Table of Contents - [Get All Groups](#get-all-groups) - [Get Single Group](#get-single-group) - [Create Group](#create-group) - [Update Group](#update-group) - [Deactivate Group](#deactivate-group) - [Bulk Deactivate Groups](#bulk-deactivate-groups) - [Restore Group](#restore-group) - [Bulk Restore Groups](#bulk-restore-groups) - [Get Archived Groups](#get-archived-groups) - [Get Group Field Values](#get-group-field-values) - [Get Users In Group](#get-users-in-group) - [Get Users Not In Group](#get-users-not-in-group) - [Add Users To Group](#add-users-to-group) - [Remove Users From Group](#remove-users-from-group) --- ## Get All Groups **`GET /api/admin/groups`** Returns a paginated list of active groups. ### Query Parameters | Parameter | Type | Required | Description | |----------|--------|----------|--------------------------------------------------| | page | number | No | Page number. Default: `1` | | limit | number | No | Records per page. Default: `20` | | search | string | No | Search across group fields | | sort_by | string | No | Column to sort by. Default: `createdAt` | | sort_dir | string | No | Sort direction: `ASC` or `DESC`. Default: `DESC` | | filters | array | No | Column filters from DataTable | ### Response `200` ```json { "status": "success", "message": "Groups retrieved.", "data": { "rows": [ { "group_id": 1, "name": "Administrators", "description": "Full access group.", "is_active": true, "member_count": 5, "createdBy": 1, "updatedBy": null, "deletedBy": null, "createdAt": "2025-01-01T00:00:00.000Z", "updatedAt": "2025-01-01T00:00:00.000Z", "deletedAt": null } ], "pagination": { "total": 10, "page": 1, "limit": 20, "totalPages": 1 } } } ``` --- ## Get Single Group **`GET /api/admin/groups/:gid`** Returns a single group with a paginated list of its members. ### Path Parameters | Parameter | Type | Required | Description | |-----------|--------|----------|-------------| | gid | number | Yes | Group ID | ### Query Parameters Same pagination/filter params as [Get All Groups](#get-all-groups) — applied to the members list. ### Response `200` ```json { "status": "success", "message": "Group retrieved.", "data": { "group": { "group_id": 1, "name": "Administrators", "description": "Full access group.", "is_active": true, "createdAt": "2025-01-01T00:00:00.000Z", "updatedAt": "2025-01-01T00:00:00.000Z" }, "members": { "rows": [ ...users ], "pagination": { ... } } } } ``` ### Response `404` ```json { "status": "error", "message": "Group not found." } ``` --- ## Create Group **`POST /api/admin/groups`** Creates a new user group. ### Request Body `application/json` | Field | Type | Required | Description | |------------|--------|----------|--------------------| | name | string | Yes | Group name | | description | string | No | Group description | ### Response `201` ```json { "status": "success", "message": "Group created.", "data": { "group_id": 1, "name": "Administrators", "description": "Full access group.", "is_active": true, "createdBy": 1, "createdAt": "2025-01-01T00:00:00.000Z", "updatedAt": "2025-01-01T00:00:00.000Z" } } ``` ### Response `400` ```json { "status": "error", "message": "Group name is required." } ``` --- ## Update Group **`PUT /api/admin/groups/:gid`** Updates a group's name or description. ### Path Parameters | Parameter | Type | Required | Description | |-----------|--------|----------|-------------| | gid | number | Yes | Group ID | ### Request Body `application/json` | Field | Type | Required | Description | |------------|--------|----------|------------------------| | name | string | No | Updated group name | | description | string | No | Updated description | ### Response `200` ```json { "status": "success", "message": "Group updated.", "data": { ...group } } ``` --- ## Deactivate Group **`PATCH /api/admin/groups/:gid/deactivate`** Soft deletes a group by setting `deletedAt` and `is_active: false`. ### Path Parameters | Parameter | Type | Required | Description | |-----------|--------|----------|-------------| | gid | number | Yes | Group ID | ### Response `200` ```json { "status": "success", "message": "Group deactivated." } ``` ### Response `400` ```json { "status": "error", "message": "Group is already deactivated." } ``` --- ## Bulk Deactivate Groups **`DELETE /api/admin/groups/bulk`** Soft deletes multiple groups at once. Already-deactivated groups are skipped and reported. ### Request Body `application/json` | Field | Type | Required | Description | |-------|----------|----------|---------------------------| | ids | number[] | Yes | Array of group IDs | ### Response `200` ```json { "status": "success", "message": "3 group(s) deactivated successfully.", "data": { "deactivated_ids": [1, 2, 3], "skipped_ids": [4] } } ``` --- ## Restore Group **`PATCH /api/admin/groups/:gid/restore`** Restores a soft-deleted group by clearing `deletedAt` and setting `is_active: true`. ### Path Parameters | Parameter | Type | Required | Description | |-----------|--------|----------|-------------| | gid | number | Yes | Group ID | ### Response `200` ```json { "status": "success", "message": "Group restored." } ``` ### Response `400` ```json { "status": "error", "message": "Group is already active." } ``` --- ## Bulk Restore Groups **`POST /api/admin/groups/bulk/restore`** Restores multiple soft-deleted groups at once. Already-active groups are skipped and reported. ### Request Body `application/json` | Field | Type | Required | Description | |-------|----------|----------|---------------------------| | ids | number[] | Yes | Array of group IDs | ### Response `200` ```json { "status": "success", "message": "3 group(s) restored successfully.", "data": { "restored_ids": [1, 2, 3], "skipped_ids": [4] } } ``` --- ## Get Archived Groups **`GET /api/admin/groups/archived`** Returns a paginated list of soft-deleted groups. ### Query Parameters Same as [Get All Groups](#get-all-groups). ### Response `200` ```json { "status": "success", "message": "Archived groups retrieved.", "data": { "rows": [ ...soft-deleted groups ], "pagination": { ... } } } ``` --- ## Get Group Field Values **`GET /api/admin/groups/field-values`** Returns distinct values for a given column — used to populate filter dropdowns in the DataTable. Supports regular columns, date fields, and audit fields. JSONB fields are not supported for groups. ### Query Parameters | Parameter | Type | Required | Description | |----------|--------|----------|--------------------| | field | string | Yes | Column name | ### Supported Field Types | Type | Example | Returns | |----------|-------------|--------------------------------| | Regular | `is_active` | Distinct values | | Date | `createdAt` | Distinct dates (no time) | | Audit by | `createdBy` | Full names of referenced users | ### Response `200` ```json { "status": "success", "message": "Field values retrieved.", "data": ["true", "false"] } ``` --- ## Get Users In Group **`GET /api/admin/groups/:gid/users`** Returns all current members of a group with their `user_id` and `full_name`. ### Path Parameters | Parameter | Type | Required | Description | |-----------|--------|----------|-------------| | gid | number | Yes | Group ID | ### Response `200` ```json { "status": "success", "message": "Group members fetched.", "data": [ { "user_id": 1, "full_name": "John Doe" }, { "user_id": 2, "full_name": "Jane Smith" } ] } ``` --- ## Get Users Not In Group **`GET /api/admin/groups/:gid/users/add`** Returns all users who are **not** currently members of the group. Used to populate the Add Members sheet. ### Path Parameters | Parameter | Type | Required | Description | |-----------|--------|----------|-------------| | gid | number | Yes | Group ID | ### Response `200` ```json { "status": "success", "message": "Users fetched.", "data": [ { "user_id": 3, "full_name": "Alice Johnson" }, { "user_id": 4, "full_name": "Bob Williams" } ] } ``` --- ## Add Users To Group **`POST /api/admin/groups/:gid/users`** Adds one or more users to a group. If a user was previously removed (soft-deleted membership), their membership is restored instead of duplicated. ### Path Parameters | Parameter | Type | Required | Description | |-----------|--------|----------|-------------| | gid | number | Yes | Group ID | ### Request Body `application/json` | Field | Type | Required | Description | |---------|----------|----------|------------------------------| | user_ids | number[] | Yes | Array of user IDs to add | ### Response `200` ```json { "status": "success", "message": "Users added to group." } ``` ### Response `404` ```json { "status": "error", "message": "Users not found: 5, 6" } ``` --- ## Remove Users From Group **`DELETE /api/admin/groups/:gid/users`** Removes one or more users from a group via soft delete on the membership record. ### Path Parameters | Parameter | Type | Required | Description | |-----------|--------|----------|-------------| | gid | number | Yes | Group ID | ### Request Body `application/json` | Field | Type | Required | Description | |---------|----------|---------|---------------------------------| | user_ids | number[] | Yes | Array of user IDs to remove | ### Response `200` ```json { "status": "success", "message": "Users removed from group." } ``` ### Response `404` ```json { "status": "error", "message": "Memberships not found for users: 5, 6" } ``` --- ## Error Responses All endpoints return the following on server error: ```json { "status": "error", "message": "Internal server error." } ``` --- ## Notes - **Soft delete** — deactivation sets `deletedAt` + `is_active: false`. Groups are excluded from all queries unless explicitly queried with `paranoid: false`. - **Membership soft delete** — removing a user from a group soft-deletes the membership record. Re-adding the user restores the record rather than creating a duplicate. - **Audit fields** — `createdBy`, `updatedBy`, `deletedBy` store the `user_id` of the admin who performed the action. - **JSONB** — group fields do not support JSONB dot-notation filtering unlike users.