mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
564 lines
12 KiB
Markdown
564 lines
12 KiB
Markdown
# Tasks Controller Documentation
|
|
|
|
**File:** `controllers/admin/task.controller.js` + `controllers/admin/task_completion.controller.js`
|
|
**Base URL:** `/api/admin/task-lists`
|
|
**Guards:** `authenticate → requireAdmin() → adminLimiter`
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
- [Task Lists](#task-lists)
|
|
- [Get All Task Lists](#get-all-task-lists)
|
|
- [Get Single Task List](#get-single-task-list)
|
|
- [Create Task List](#create-task-list)
|
|
- [Update Task List](#update-task-list)
|
|
- [Archive Task List](#archive-task-list)
|
|
- [Restore Task List](#restore-task-list)
|
|
- [Bulk Archive Task Lists](#bulk-archive-task-lists)
|
|
- [Bulk Restore Task Lists](#bulk-restore-task-lists)
|
|
- [Get Archived Task Lists](#get-archived-task-lists)
|
|
- [Get Task List Field Values](#get-task-list-field-values)
|
|
- [Task List Groups](#task-list-groups)
|
|
- [Get Assigned Groups](#get-assigned-groups)
|
|
- [Assign Groups](#assign-groups)
|
|
- [Unassign Groups](#unassign-groups)
|
|
- [Tasks](#tasks)
|
|
- [Get All Tasks](#get-all-tasks)
|
|
- [Get Single Task](#get-single-task)
|
|
- [Create Task](#create-task)
|
|
- [Update Task](#update-task)
|
|
- [Archive Task](#archive-task)
|
|
- [Restore Task](#restore-task)
|
|
- [Bulk Archive Tasks](#bulk-archive-tasks)
|
|
- [Bulk Restore Tasks](#bulk-restore-tasks)
|
|
- [Get Archived Tasks](#get-archived-tasks)
|
|
- [Get Task Field Values](#get-task-field-values)
|
|
- [Completions](#completions)
|
|
- [Get All Completions](#get-all-completions)
|
|
- [Get Single Completion](#get-single-completion)
|
|
- [Get Completions by User](#get-completions-by-user)
|
|
- [Archive Completion](#archive-completion)
|
|
- [Restore Completion](#restore-completion)
|
|
- [Bulk Archive Completions](#bulk-archive-completions)
|
|
- [Bulk Restore Completions](#bulk-restore-completions)
|
|
|
|
---
|
|
|
|
## Data Model
|
|
|
|
```
|
|
TaskList ──< Task ──< TaskRequirement
|
|
│
|
|
└──< TaskListGroup >── UserGroup
|
|
```
|
|
|
|
- A **TaskList** is a named container of tasks, visible to assigned user groups.
|
|
- A **Task** belongs to one TaskList and has 0-N requirements.
|
|
- A **TaskRequirement** specifies what a user must do (visit a link, upload a file, or read a course/unit/lesson).
|
|
- Completions are submitted by **clients only** — admins can view and archive/restore them.
|
|
|
|
---
|
|
|
|
## Task Requirement Types
|
|
|
|
| `type` | Required Fields | Description |
|
|
|--------|----------------|-------------|
|
|
| `visit_link` | `link_url`, `link_label` | User must visit a URL |
|
|
| `upload_file` | `allowed_file_types`, `max_file_count` | User must upload files |
|
|
| `read_course` | `reference_id` (course UUID), `reference_label` | User must complete a course |
|
|
| `read_unit` | `reference_id` (unit UUID), `reference_label` | User must complete a unit |
|
|
| `read_lesson` | `reference_id` (lesson UUID), `reference_label` | User must complete a lesson |
|
|
|
|
---
|
|
|
|
## Task Lists
|
|
|
|
### Get All Task Lists
|
|
|
|
**`GET /api/admin/task-lists`**
|
|
|
|
Returns paginated active task lists.
|
|
|
|
### Query Parameters
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|--------|----------|-------------|
|
|
| `page` | number | No | Default: `1` |
|
|
| `limit` | number | No | Default: `10` |
|
|
| `filters` | array | No | JSON filter array |
|
|
| `sort` | array | No | JSON sort array |
|
|
|
|
### Response `200`
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "Task lists retrieved.",
|
|
"data": [...],
|
|
"pagination": { "page": 1, "limit": 10, "total": 5, "totalPages": 1 }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Get Single Task List
|
|
|
|
**`GET /api/admin/task-lists/:taskListId`**
|
|
|
|
Returns a task list with its full task tree (tasks → requirements) and assigned groups. Includes archived items (`paranoid: false`).
|
|
|
|
### Response `200`
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "Task list retrieved.",
|
|
"data": {
|
|
"task_list_id": "uuid-...",
|
|
"name": "Onboarding Q1",
|
|
"description": "...",
|
|
"group_count": 2,
|
|
"groups": [
|
|
{ "group_id": 1, "name": "Engineering" }
|
|
],
|
|
"tasks": [
|
|
{
|
|
"task_id": "uuid-...",
|
|
"name": "Read the handbook",
|
|
"deadline": "2026-07-01T00:00:00.000Z",
|
|
"status": "pending",
|
|
"requirements": [
|
|
{ "requirement_id": "uuid-...", "type": "read_lesson", "reference_id": "uuid-..." }
|
|
]
|
|
}
|
|
],
|
|
"createdAt": "...",
|
|
"updatedAt": "..."
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Create Task List
|
|
|
|
**`POST /api/admin/task-lists`**
|
|
|
|
Rate-limited.
|
|
|
|
### Request Body
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `name` | string | **Yes** | Unique list name |
|
|
| `description` | string | No | |
|
|
|
|
### Response `201`
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "Task list created successfully.",
|
|
"data": { ... }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Update Task List
|
|
|
|
**`PATCH /api/admin/task-lists/:taskListId`**
|
|
|
|
Rate-limited.
|
|
|
|
### Request Body
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `name` | string | No | |
|
|
| `description` | string | No | |
|
|
|
|
### Response `200`
|
|
```json
|
|
{ "status": "success", "message": "Task list updated successfully.", "data": { ... } }
|
|
```
|
|
|
|
---
|
|
|
|
### Archive Task List
|
|
|
|
**`DELETE /api/admin/task-lists/:taskListId`**
|
|
|
|
Rate-limited. Soft-deletes the task list.
|
|
|
|
### Response `200`
|
|
```json
|
|
{ "status": "success", "message": "Task list archived successfully." }
|
|
```
|
|
|
|
---
|
|
|
|
### Restore Task List
|
|
|
|
**`PATCH /api/admin/task-lists/:taskListId/restore`**
|
|
|
|
Rate-limited.
|
|
|
|
### Response `200`
|
|
```json
|
|
{ "status": "success", "message": "Task list restored successfully.", "data": { ... } }
|
|
```
|
|
|
|
---
|
|
|
|
### Bulk Archive Task Lists
|
|
|
|
**`POST /api/admin/task-lists/bulk-archive`**
|
|
|
|
Rate-limited.
|
|
|
|
### Request Body
|
|
```json
|
|
{ "ids": ["uuid-1", "uuid-2"] }
|
|
```
|
|
|
|
### Response `200`
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "2 task list(s) archived successfully.",
|
|
"archived_ids": [...],
|
|
"skipped_ids": []
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Bulk Restore Task Lists
|
|
|
|
**`POST /api/admin/task-lists/bulk-restore`**
|
|
|
|
Rate-limited. Same body shape as bulk archive.
|
|
|
|
---
|
|
|
|
### Get Archived Task Lists
|
|
|
|
**`GET /api/admin/task-lists/archived`**
|
|
|
|
Returns paginated soft-deleted task lists.
|
|
|
|
---
|
|
|
|
### Get Task List Field Values
|
|
|
|
**`GET /api/admin/task-lists/field-values`**
|
|
|
|
Returns distinct filterable field values for task lists.
|
|
|
|
---
|
|
|
|
## Task List Groups
|
|
|
|
### Get Assigned Groups
|
|
|
|
**`GET /api/admin/task-lists/:taskListId/groups`**
|
|
|
|
Returns all user groups currently assigned to the task list, including assignment metadata.
|
|
|
|
### Response `200`
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "Task list groups retrieved.",
|
|
"data": [
|
|
{
|
|
"id": "uuid-...",
|
|
"task_list_id": "uuid-...",
|
|
"group_id": 1,
|
|
"assignedAt": "2026-06-01T00:00:00.000Z",
|
|
"assignedBy": 1,
|
|
"group": { "group_id": 1, "name": "Engineering" }
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Assign Groups
|
|
|
|
**`POST /api/admin/task-lists/:taskListId/groups/assign`**
|
|
|
|
Rate-limited. Upsert-style — already-assigned groups are silently skipped.
|
|
|
|
### Request Body
|
|
```json
|
|
{ "group_ids": [1, 2, 3] }
|
|
```
|
|
|
|
### Response `201`
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "2 group(s) assigned.",
|
|
"assigned_ids": [2, 3],
|
|
"already_assigned_ids": [1],
|
|
"invalid_ids": []
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Unassign Groups
|
|
|
|
**`POST /api/admin/task-lists/:taskListId/groups/unassign`**
|
|
|
|
Rate-limited. Hard-deletes the junction rows (assignments are not soft-deleted).
|
|
|
|
### Request Body
|
|
```json
|
|
{ "group_ids": [2, 3] }
|
|
```
|
|
|
|
### Response `200`
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "2 group(s) unassigned.",
|
|
"unassigned_ids": [2, 3],
|
|
"skipped_ids": []
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Tasks
|
|
|
|
### Get All Tasks
|
|
|
|
**`GET /api/admin/task-lists/:taskListId/tasks`**
|
|
|
|
Returns paginated tasks under a task list.
|
|
|
|
### Query Parameters
|
|
Standard pagination + `filters` + `sort`.
|
|
|
|
---
|
|
|
|
### Get Single Task
|
|
|
|
**`GET /api/admin/task-lists/:taskListId/tasks/:taskId`**
|
|
|
|
Returns a task with its requirements and the parent task list (including assigned groups).
|
|
|
|
### Response `200`
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "Task retrieved.",
|
|
"data": {
|
|
"task_id": "uuid-...",
|
|
"task_list_id": "uuid-...",
|
|
"name": "Complete orientation",
|
|
"description": "...",
|
|
"deadline": "2026-07-01T00:00:00.000Z",
|
|
"status": "pending",
|
|
"requirements": [
|
|
{
|
|
"requirement_id": "uuid-...",
|
|
"type": "upload_file",
|
|
"allowed_file_types": ["application/pdf"],
|
|
"max_file_count": 1,
|
|
"order": 0
|
|
}
|
|
],
|
|
"taskList": { "task_list_id": "...", "name": "Onboarding Q1", "groups": [...] }
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Create Task
|
|
|
|
**`POST /api/admin/task-lists/:taskListId/tasks`**
|
|
|
|
Rate-limited. Creates a task and optionally its requirements in a single transaction.
|
|
|
|
### Request Body
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `name` | string | **Yes** | Task name |
|
|
| `description` | string | No | |
|
|
| `deadline` | date | No | ISO date string |
|
|
| `requirements` | array | No | Array of requirement objects (see Requirement Types above) |
|
|
|
|
### Response `201`
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "Task created successfully.",
|
|
"data": { "task_id": "uuid-...", "name": "...", "requirements": [...] }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Update Task
|
|
|
|
**`PATCH /api/admin/task-lists/:taskListId/tasks/:taskId`**
|
|
|
|
Rate-limited. When `requirements` is provided, the full set is replaced (soft-delete + re-insert).
|
|
|
|
> **Note:** Incoming requirement objects must **not** include `requirement_id` — the server always generates fresh IDs to avoid collisions with soft-deleted rows.
|
|
|
|
### Request Body
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `name` | string | No | |
|
|
| `description` | string | No | |
|
|
| `deadline` | date | No | |
|
|
| `status` | string | No | `pending`, `in_progress`, `completed`, `overdue` |
|
|
| `requirements` | array | No | Full replacement set |
|
|
|
|
---
|
|
|
|
### Archive Task
|
|
|
|
**`DELETE /api/admin/task-lists/:taskListId/tasks/:taskId`**
|
|
|
|
Rate-limited. Soft-deletes the task.
|
|
|
|
---
|
|
|
|
### Restore Task
|
|
|
|
**`PATCH /api/admin/task-lists/:taskListId/tasks/:taskId/restore`**
|
|
|
|
Rate-limited.
|
|
|
|
---
|
|
|
|
### Bulk Archive Tasks
|
|
|
|
**`POST /api/admin/task-lists/:taskListId/tasks/bulk-archive`**
|
|
|
|
Rate-limited.
|
|
|
|
### Request Body
|
|
```json
|
|
{ "ids": ["uuid-1", "uuid-2"] }
|
|
```
|
|
|
|
---
|
|
|
|
### Bulk Restore Tasks
|
|
|
|
**`POST /api/admin/task-lists/:taskListId/tasks/bulk-restore`**
|
|
|
|
Rate-limited.
|
|
|
|
---
|
|
|
|
### Get Archived Tasks
|
|
|
|
**`GET /api/admin/task-lists/:taskListId/tasks/archived`**
|
|
|
|
---
|
|
|
|
### Get Task Field Values
|
|
|
|
**`GET /api/admin/task-lists/:taskListId/tasks/field-values`**
|
|
|
|
---
|
|
|
|
## Completions
|
|
|
|
Completions are created by clients only. Admins can view and archive/restore them.
|
|
|
|
Each completion may have multiple attached files (`task_completion_files`).
|
|
|
|
---
|
|
|
|
### Get All Completions
|
|
|
|
**`GET /api/admin/task-lists/:taskListId/tasks/:taskId/completions`**
|
|
|
|
Returns paginated completions for a task, with submitting user info and files.
|
|
|
|
### Response `200`
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "Completions retrieved.",
|
|
"data": [
|
|
{
|
|
"completion_id": "uuid-...",
|
|
"task_id": "uuid-...",
|
|
"user_id": 42,
|
|
"note": "Attached the signed form.",
|
|
"submitted_at": "2026-06-15T10:00:00.000Z",
|
|
"user": { "user_id": 42, "email": "user@example.com", "name": "Jane Doe" },
|
|
"files": [
|
|
{
|
|
"file_id": "uuid-...",
|
|
"file_url": "https://...",
|
|
"file_name": "signed_form.pdf",
|
|
"file_size": 204800,
|
|
"mime_type": "application/pdf"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"pagination": { ... }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Get Single Completion
|
|
|
|
**`GET /api/admin/task-lists/:taskListId/tasks/:taskId/completions/:completionId`**
|
|
|
|
Returns a single completion with user and files.
|
|
|
|
---
|
|
|
|
### Get Completions by User
|
|
|
|
**`GET /api/admin/task-lists/:taskListId/tasks/:taskId/completions/user/:userId`**
|
|
|
|
Returns all completions for a specific user on a specific task.
|
|
|
|
---
|
|
|
|
### Archive Completion
|
|
|
|
**`DELETE /api/admin/task-lists/:taskListId/tasks/:taskId/completions/:completionId`**
|
|
|
|
Rate-limited. Soft-deletes a completion.
|
|
|
|
---
|
|
|
|
### Restore Completion
|
|
|
|
**`PATCH /api/admin/task-lists/:taskListId/tasks/:taskId/completions/:completionId/restore`**
|
|
|
|
Rate-limited.
|
|
|
|
---
|
|
|
|
### Bulk Archive Completions
|
|
|
|
**`POST /api/admin/task-lists/:taskListId/tasks/:taskId/completions/bulk-archive`**
|
|
|
|
Rate-limited.
|
|
|
|
### Request Body
|
|
```json
|
|
{ "ids": ["uuid-1", "uuid-2"] }
|
|
```
|
|
|
|
---
|
|
|
|
### Bulk Restore Completions
|
|
|
|
**`POST /api/admin/task-lists/:taskListId/tasks/:taskId/completions/bulk-restore`**
|
|
|
|
Rate-limited.
|