# ms-general API Documentation

## 1. Introduction

This document provides a comprehensive overview of the `ms-general` microservice API endpoints, designed for frontend integration. This microservice handles employee information operations including approvals, memos, inquiries, notifications, feedback, announcements, and system trails.

**Base URL:** `http: //your-domain/api/v1`

All API responses follow a consistent JSON envelope structure:

```json
{
    "success": true|false,
    "message": "Descriptive message",
    "data": { ... },
    "meta": {
        "current_page": 1,
        "per_page": 10,
        "total": 100,
        "last_page": 10
    }
}
```

*Note: Some endpoints may deviate from this envelope (e.g., return data directly or use a `pagination` key instead of `meta`). These are noted per endpoint.*

---

## 2. Authentication

### Service Token Endpoint

Generate a short-lived JWT for service-to-service communication.

- **Endpoint:** `POST /generate-token`
- **Authentication:** None required (this generates the token)
- **Description:** Creates a JWT token valid for 10 minutes with the `service: hris-general` claim.

#### Response

```json
{
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}
```

#### Error Response

```json
{
    "error": "Token generation failed"
}
```

### Using the Token

Include the token in the `Authorization` header:

```
Authorization: Bearer {your-token}
```

All other API endpoints require JWT authentication via the API Gateway. The `VerifyServiceToken` middleware validates the token and rejects requests where `service !== 'hris-general'`.

### Token Validation Endpoint

- **Endpoint:** `GET /check`
- **Authentication:** JWT token required
- **Description:** Validates the provided JWT token and returns its payload.

#### Response (valid)

```json
{
    "valid": true,
    "payload": { ... }
}
```

#### Response (invalid/expired)

```json
{
    "valid": false,
    "error": "token_expired"
}
```

---

## 3. Error Handling

All API errors return JSON responses with appropriate HTTP status codes. The error structure may vary by endpoint but generally follows the `success/message/data` pattern.

| Status Code | Description |
|---|---|
| `400 Bad Request` | Missing required parameters or invalid input |
| `401 Unauthorized` | Authentication is required or has failed |
| `403 Forbidden` | The requester is not authorized for this action |
| `404 Not Found` | The requested resource could not be found |
| `409 Conflict` | Conflict with current state (e.g., active approval requests prevent deletion) |
| `422 Unprocessable Entity` | Validation failed |
| `500 Internal Server Error` | Unexpected server error |

### Validation Error Example (422)

```json
{
    "success": false,
    "message": "Validation Error",
    "errors": {
        "field_name": [
            "The field_name field is required."
        ]
    }
}
```

### Server Error Example (500)

```json
{
    "success": false,
    "message": "Failed to retrieve approval settings",
    "error": "Detailed error message (development only)"
}
```

---

## 4. API Endpoints

---

### Approval Settings Module

Manage approval workflow configurations, including approval levels and approver assignments.

#### GET `api/v1/approval-settings`

List all approval settings with optional filtering, search, and pagination.

- **Description:** Retrieves a paginated list of approval settings with their approval levels.
- **Authentication:** Required (JWT Service Token)

**Query Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `search` | string | No | Search by `code` or `module_code` |
| `status` | string | No | Filter by status (e.g., "Active") |
| `module_code` | string | No | Filter by module code |
| `section_code` | string | No | Filter by section code |
| `per_page` | integer | No | Items per page (default: 10) |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Approval settings retrieved successfully",
    "data": [
        {
            "id": 1,
            "code": "APPROVAL-001",
            "module_code": "LEAVE",
            "section_code": "HR",
            "has_final_approver": true,
            "status": "Active",
            "created_by": 1,
            "modified_by": null,
            "created_at": "2025-01-01T00:00:00.000000Z",
            "updated_at": "2025-01-01T00:00:00.000000Z",
            "approval_levels": [
                {
                    "id": 1,
                    "approval_setting_id": 1,
                    "level": 1,
                    "approver_employee_id": 2,
                    "alternative_approver_employee_id": 3,
                    "is_final_approver": false
                }
            ]
        }
    ],
    "meta": {
        "current_page": 1,
        "per_page": 10,
        "total": 1,
        "last_page": 1
    }
}
```

---

#### POST `api/v1/approval-settings`

Create a new approval setting with approval levels.

- **Description:** Creates an approval setting configuration including its approval levels.
- **Authentication:** Required (JWT Service Token)

**Request Body:**

Content-Type: `application/json`

| Field | Type | Required | Validation |
|---|---|---|---|
| `code` | string | Yes | `required|string|max:255|unique:approval_settings,code` |
| `module_code` | string | Yes | `required|string|max:255` |
| `section_code` | string | Yes | `required|string|max:255` |
| `has_final_approver` | boolean | Yes | `required|boolean` |
| `status` | string | Yes | `required|string|max:40` |
| `created_by` | integer | No | `nullable|integer|exists:employees,id` |
| `modified_by` | integer | No | `nullable|integer|exists:employees,id` |
| `approval_levels` | array | Yes | `required|array|min:1` |
| `approval_levels.*.level` | integer | Yes | `required|integer|min:1` |
| `approval_levels.*.approver_employee_id` | integer | Yes | `required|integer|exists:employees,id` |
| `approval_levels.*.alternative_approver_employee_id` | integer | No | `nullable|integer|exists:employees,id` |
| `approval_levels.*.is_final_approver` | boolean | Yes | `required|boolean` |

**Additional Business Rules:**
- Main and alternative approver must be different in the same level
- No employee can appear in consecutive levels
- An employee cannot be both main and alternative approver across different levels

**Example:**

```json
{
    "code": "LEAVE-APPROVAL",
    "module_code": "LEAVE",
    "section_code": "HR",
    "has_final_approver": true,
    "status": "Active",
    "created_by": 1,
    "approval_levels": [
        {
            "level": 1,
            "approver_employee_id": 2,
            "alternative_approver_employee_id": 3,
            "is_final_approver": false
        },
        {
            "level": 2,
            "approver_employee_id": 4,
            "alternative_approver_employee_id": 5,
            "is_final_approver": true
        }
    ]
}
```

**Responses:**

- **201 Created:**

```json
{
    "success": true,
    "message": "Approval setting created successfully",
    "data": {
        "id": 1,
        "code": "LEAVE-APPROVAL",
        "module_code": "LEAVE",
        "section_code": "HR",
        "has_final_approver": true,
        "status": "Active",
        "approval_levels": [
            {
                "id": 1,
                "level": 1,
                "approver_employee_id": 2,
                "alternative_approver_employee_id": 3,
                "is_final_approver": false
            }
        ]
    }
}
```

---

#### GET `api/v1/approval-settings/{id}`

Get a specific approval setting.

- **Description:** Retrieves a single approval setting with its approval levels.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The approval setting ID |

**Responses:**

- **200 OK:** Same structure as single item in index response.

- **404 Not Found:**

```json
{
    "success": false,
    "message": "Approval setting not found"
}
```

---

#### PATCH `api/v1/approval-settings/{id}`

Update an existing approval setting.

- **Description:** Updates an approval setting and recreates its approval levels.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The approval setting ID |

**Request Body:** Same schema as `POST`, with `modified_by` instead of `created_by`.

| Field | Type | Required | Validation |
|---|---|---|---|
| `code` | string | Yes | `required|string|max:255|unique:approval_settings,code,{id}` |
| `module_code` | string | Yes | `required|string|max:255` |
| `section_code` | string | Yes | `required|string|max:255` |
| `has_final_approver` | boolean | Yes | `required|boolean` |
| `status` | string | Yes | `required|string|max:40` |
| `modified_by` | integer | No | `nullable|integer|exists:employees,id` |
| `approval_levels` | array | Yes | `required|array|min:1` |
| `approval_levels.*.level` | integer | Yes | `required|integer|min:1` |
| `approval_levels.*.approver_employee_id` | integer | Yes | `required|integer|exists:employees,id` |
| `approval_levels.*.alternative_approver_employee_id` | integer | No | `nullable|integer|exists:employees,id` |
| `approval_levels.*.is_final_approver` | boolean | Yes | `required|boolean` |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Approval setting updated successfully",
    "data": {
        "id": 1,
        "code": "LEAVE-APPROVAL-UPDATED",
        ... 
    }
}
```

---

#### DELETE `api/v1/approval-settings/{id}`

Soft delete an approval setting.

- **Description:** Soft deletes an approval setting. Cannot delete if it has active (pending) approval requests.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The approval setting ID |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Approval setting deleted successfully"
}
```

- **409 Conflict:**

```json
{
    "success": false,
    "message": "Cannot delete approval setting with active approval requests"
}
```

---

#### POST `api/v1/approval-settings/{id}/restore`

Restore a soft-deleted approval setting.

- **Description:** Restores a previously soft-deleted approval setting.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The approval setting ID |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Approval setting restored successfully",
    "data": { ... }
}
```

---

#### DELETE `api/v1/approval-settings/{id}/force-delete`

Permanently delete an approval setting.

- **Description:** Force deletes (permanently removes) a soft-deleted approval setting.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The approval setting ID (must be already soft-deleted) |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Approval setting permanently deleted"
}
```

---

#### GET `api/v1/approval-settings/trashed/list`

List soft-deleted approval settings.

- **Description:** Retrieves all soft-deleted approval settings.
- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "data": { ... }
}
```

---

### Module Settings Module

Manage module-to-approval-setting mappings.

#### GET `api/v1/module-settings`

List all module settings with optional filtering, search, and pagination.

- **Description:** Retrieves a paginated list of module settings with their linked approval setting.
- **Authentication:** Required (JWT Service Token)

**Query Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `search` | string | No | Search by `module_code`, `module_name`, or `section_code` |
| `status` | string | No | Filter by status |
| `module_code` | string | No | Filter by module code |
| `section_code` | string | No | Filter by section code |
| `is_default` | boolean | No | Filter by default flag |
| `per_page` | integer | No | Items per page (default: 10) |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Module settings retrieved successfully",
    "data": [
        {
            "id": 1,
            "module_code": "LEAVE",
            "module_name": "Leave Management",
            "section_code": "HR",
            "approval_setting_id": 1,
            "is_default": true,
            "status": "Active",
            "approval_setting": {
                "id": 1,
                "code": "LEAVE-APPROVAL",
                ...
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "per_page": 10,
        "total": 1,
        "last_page": 1
    }
}
```

---

#### POST `api/v1/module-settings`

Create a new module setting.

- **Description:** Creates a module-to-approval-setting mapping.
- **Authentication:** Required (JWT Service Token)

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `module_code` | string | Yes | `required|string|max:255` |
| `module_name` | string | Yes | `required|string|max:255` |
| `section_code` | string | Yes | `required|string|max:255` |
| `approval_setting_id` | integer | Yes | `required|integer|exists:approval_settings,id` |
| `is_default` | boolean | Yes | `required|boolean` |
| `status` | string | Yes | `required|string|max:40` |

**Additional Validation:** The combination of `module_code` + `section_code` must be unique.

**Responses:**

- **201 Created:**

```json
{
    "success": true,
    "message": "Module setting created successfully",
    "data": { ... }
}
```

---

#### GET `api/v1/module-settings/{id}`

Get a specific module setting.

- **Description:** Retrieves a module setting with its approval setting and approval levels.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The module setting ID |

**Responses:**

- **200 OK:** Module setting with nested `approval_setting.approval_levels`.

- **404 Not Found:**

```json
{
    "success": false,
    "message": "Module setting not found"
}
```

---

#### PATCH `api/v1/module-settings/{id}`

Update a module setting.

- **Description:** Updates a module setting.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The module setting ID |

**Request Body:** Same schema as `POST`.

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Module setting updated successfully",
    "data": { ... }
}
```

---

#### DELETE `api/v1/module-settings/{id}`

Soft delete a module setting.

- **Description:** Soft deletes a module setting.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The module setting ID |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Module setting deleted successfully"
}
```

---

#### POST `api/v1/module-settings/{id}/restore`

Restore a deleted module setting.

- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Module setting restored successfully",
    "data": { ... }
}
```

---

#### DELETE `api/v1/module-settings/{id}/force-delete`

Permanently delete a module setting.

- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Module setting permanently deleted"
}
```

---

#### GET `api/v1/module-settings/trashed/list`

List soft-deleted module settings.

- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "data": { ... }
}
```

---

#### GET `api/v1/module-settings/approval-setting`

Find the approval setting for a given module and section.

- **Description:** Helper endpoint that finds the appropriate approval setting for a module/section combination. Falls back to the default setting for the module if no specific match is found.
- **Authentication:** Required (JWT Service Token)

**Query Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `module_code` | string | Yes | The module code |
| `section_code` | string | Yes | The section code |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Approval setting retrieved successfully",
    "data": {
        "id": 1,
        "module_code": "LEAVE",
        "module_name": "Leave Management",
        "section_code": "HR",
        "is_default": true,
        "status": "Active",
        "approval_setting": {
            "id": 1,
            "code": "LEAVE-APPROVAL",
            "approval_levels": [ ... ]
        }
    }
}
```

- **404 Not Found:**

```json
{
    "success": false,
    "message": "No approval setting found for this module and section"
}
```

---

### Approval Requests Module

Create and manage approval workflows.

#### GET `api/v1/approval-requests`

List all approval requests with filtering and pagination.

- **Description:** Retrieves a paginated list of approval requests.
- **Authentication:** Required (JWT Service Token)

**Query Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `search` | string | No | Search by `request_reference_id` or `module_code` |
| `status` | string | No | Filter by status (e.g., "pending", "approved", "rejected") |
| `module_code` | string | No | Filter by module code |
| `filed_by` | integer | No | Filter by the employee who filed the request |
| `request_reference_id` | string | No | Filter by reference ID |
| `per_page` | integer | No | Items per page (default: 10) |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Approval requests retrieved successfully",
    "data": [ ... ],
    "meta": {
        "current_page": 1,
        "per_page": 10,
        "total": 1,
        "last_page": 1
    }
}
```

---

#### POST `api/v1/approval-requests`

Create a new approval request.

- **Description:** Creates an approval request with a snapshot of the approval chain, notifies the first-level approver.
- **Authentication:** Required (JWT Service Token)

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `module_code` | string | Yes | `required|string|max:255` |
| `section_code` | string | Yes | `required|string|max:255` |
| `filed_by` | integer | Yes | `required|integer|exists:employees,id` |
| `request_reference_id` | string | Yes | `required|string|max:255` |

**Behavior:** The system automatically:
1. Finds the matching module setting (or its default)
2. Snapshots the approval chain
3. Creates the request with status "pending" and `current_level = 1`
4. Notifies the first-level approver

**Responses:**

- **201 Created:**

```json
{
    "success": true,
    "message": "Approval request created successfully",
    "data": {
        "approval_request": {
            "id": 1,
            "approval_setting_id": 1,
            "approval_chain_snapshot": [ ... ],
            "module_code": "LEAVE",
            "section_code": "HR",
            "filed_by": 1,
            "request_reference_id": "LV-2025-001",
            "current_level": 1,
            "status": "pending"
        },
        "next_approver": {
            "employee_id": 2,
            "alternative_employee_id": 3,
            "level": 1
        }
    }
}
```

- **404 Not Found:**

```json
{
    "success": false,
    "message": "No approval setting found for this module and section"
}
```

---

#### GET `api/v1/approval-requests/{id}`

Get a specific approval request with history and notifications.

- **Description:** Retrieves a single approval request with its approval histories and notifications.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The approval request ID |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Approval request retrieved successfully",
    "data": {
        "id": 1,
        "approval_chain_snapshot": [ ... ],
        "status": "pending",
        "current_level": 1,
        "approval_histories": [ ... ],
        "approval_notifications": [ ... ]
    }
}
```

---

#### POST `api/v1/approval-requests/{id}/approve`

Approve an approval request.

- **Description:** Approves the current level of an approval request. If the current approver is the final approver, the request is fully approved.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The approval request ID |

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `approver_employee_id` | integer | Yes | `required|integer|exists:employees,id` |
| `comments` | string | No | `nullable|string` |

**Business Rules:**
- Only the current level's main or alternative approver can approve
- Request must be in "pending" status
- If current level is the final approver, the request becomes "approved"
- Otherwise, moves to the next level and notifies the next approver

**Responses:**

- **200 OK (approved at final level):**

```json
{
    "success": true,
    "message": "Request fully approved",
    "data": {
        "approval_request": { ... },
        "status": "completed"
    }
}
```

- **200 OK (moved to next level):**

```json
{
    "success": true,
    "message": "Request approved successfully",
    "data": {
        "approval_request": { ... },
        "next_approver": {
            "employee_id": 4,
            "alternative_employee_id": null,
            "level": 2
        }
    }
}
```

- **403 Forbidden:**

```json
{
    "success": false,
    "message": "You are not authorized to approve this request at this level"
}
```

- **409 Conflict:**

```json
{
    "success": false,
    "message": "This request has already been processed"
}
```

---

#### POST `api/v1/approval-requests/{id}/reject`

Reject an approval request.

- **Description:** Rejects the approval request at the current level.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The approval request ID |

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `approver_employee_id` | integer | Yes | `required|integer|exists:employees,id` |
| `comments` | string | **Yes** | `required|string` |

**Business Rules:**
- Only the current level's main or alternative approver can reject
- Comments are required when rejecting
- Request status becomes "rejected"
- Requester is notified

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Request rejected",
    "data": {
        "approval_request": { ... },
        "rejected_by": {
            "employee_id": 2,
            "level": 1
        }
    }
}
```

---

#### POST `api/v1/approval-requests/{id}/use-alternative`

Notify the alternative approver.

- **Description:** Used when the main approver is unavailable; notifies the alternative approver.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The approval request ID |

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `reason` | string | Yes | `required|string` |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Alternative approver notified successfully",
    "data": {
        "alternative_approver": {
            "employee_id": 3,
            "level": 1,
            "reason": "On leave"
        }
    }
}
```

- **404 Not Found:**

```json
{
    "success": false,
    "message": "No alternative approver available for this level"
}
```

---

#### GET `api/v1/approval-requests/pending`

Get pending approvals for an employee.

- **Description:** Retrieves all pending approval requests where the specified employee is the current level approver (main or alternative).
- **Authentication:** Required (JWT Service Token)

**Query Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `employee_id` | integer | **Yes** | Employee ID to find pending approvals for |
| `page` | integer | No | Page number (default: 1) |
| `per_page` | integer | No | Items per page (default: 10) |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Pending approvals retrieved successfully",
    "data": [ ... ],
    "meta": {
        "current_page": 1,
        "per_page": 10,
        "total": 5,
        "last_page": 1
    }
}
```

---

#### GET `api/v1/approval-requests/{id}/history`

Get approval history for a specific request.

- **Description:** Retrieves the approval history timeline for a single approval request.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The approval request ID |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Approval history retrieved successfully",
    "data": {
        "approval_request": {
            "id": 1,
            "request_reference_id": "LV-2025-001",
            "module_code": "LEAVE",
            "section_code": "HR",
            "filed_by": 1,
            "status": "approved",
            "current_level": 2,
            "created_at": "2025-01-01T00:00:00.000000Z",
            "approval_date": "2025-01-02T00:00:00.000000Z",
            "disapproval_remarks": null
        },
        "histories": [
            {
                "id": 1,
                "approval_level_id": 1,
                "approver_employee_id": 2,
                "action": "approved",
                "comments": "Looks good",
                "approved_at": "2025-01-02T00:00:00.000000Z",
                "created_at": "2025-01-02T00:00:00.000000Z"
            }
        ]
    }
}
```

---

#### GET `api/v1/approval-requests/employee-history`

Get all approval history for an employee as approver.

- **Description:** Retrieves all approval histories where the specified employee acted as approver, with optional filtering.
- **Authentication:** Required (JWT Service Token)

**Query Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `employee_id` | integer | **Yes** | Employee ID |
| `action` | string | No | Filter by action ("approved", "rejected") |
| `module_code` | string | No | Filter by module code |
| `date_from` | date | No | Filter histories created on or after this date (Y-m-d) |
| `date_to` | date | No | Filter histories created on or before this date (Y-m-d) |
| `per_page` | integer | No | Items per page (default: 10) |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Employee approval history retrieved successfully",
    "data": [
        {
            "id": 1,
            "approval_request_id": 1,
            "approver_employee_id": 2,
            "action": "approved",
            "comments": "Looks good",
            "approved_at": "2025-01-02T00:00:00.000000Z",
            "created_at": "2025-01-02T00:00:00.000000Z",
            "request_reference_id": "LV-2025-001",
            "module_code": "LEAVE",
            "section_code": "HR",
            "filed_by": 1,
            "status": "approved"
        }
    ],
    "meta": { ... }
}
```

---

#### GET `api/v1/approval-requests/employee-stats`

Get approval statistics for an employee.

- **Description:** Returns summary statistics about an employee's approval activities.
- **Authentication:** Required (JWT Service Token)

**Query Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `employee_id` | integer | **Yes** | Employee ID |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Employee statistics retrieved successfully",
    "data": {
        "employee_id": 2,
        "total_approved": 15,
        "total_rejected": 2,
        "total_pending": 3,
        "average_response_time_hours": 24.5,
        "total_processed": 17
    }
}
```

---

### Approval Mapping Sections Module

Manage section mappings for approval workflows.

#### GET `api/v1/approval-mapping-sections`

List approval mapping sections with filtering.

- **Authentication:** Required (JWT Service Token)

**Query Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `office_name` | string | No | Filter by office name (partial match) |
| `section_code` | string | No | Filter by section code (partial match) |
| `status` | string | No | Filter by status |
| `per_page` | integer | No | Items per page (default: 10, max: 100) |

**Responses:**

- **200 OK:**

```json
{
    "data": [
        {
            "id": 1,
            "office_name": "Human Resources",
            "approval_mapping_section": "HR Section",
            "section_code": "HR",
            "status": "Active",
            "created_at": "2025-01-01T00:00:00.000000Z",
            "updated_at": "2025-01-01T00:00:00.000000Z"
        }
    ],
    "pagination": { ... }
}
```

---

#### POST `api/v1/approval-mapping-sections`

Create an approval mapping section.

- **Authentication:** Required (JWT Service Token)

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `office_name` | string | Yes | `required|string|max:255` |
| `approval_mapping_section` | string | Yes | `required|string|max:255` |
| `section_code` | string | Yes | `required|string|max:100|unique:approval_mapping_sections,section_code` |
| `status` | string | Yes | `required|string|max:50` |

**Responses:**

- **201 Created:**

```json
{
    "message": "Approval Mapping Section created successfully.",
    "data": { ... }
}
```

---

#### GET `api/v1/approval-mapping-sections/{id}`

Get a specific approval mapping section.

- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:** Returns the record directly as JSON (not wrapped in success/data).

---

#### PUT `api/v1/approval-mapping-sections/{id}`

Update an approval mapping section.

- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The mapping section ID |

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `office_name` | string | No | `sometimes|required|string|max:255` |
| `approval_mapping_section` | string | No | `sometimes|required|string|max:255` |
| `section_code` | string | No | `sometimes|required|string|max:100|unique:approval_mapping_sections,section_code,{id}` |
| `status` | string | No | `sometimes|required|string|max:50` |

**Responses:**

- **200 OK:**

```json
{
    "message": "Approval Mapping Section updated successfully.",
    "data": { ... }
}
```

---

#### DELETE `api/v1/approval-mapping-sections/{id}`

Delete an approval mapping section.

- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "message": "Approval Mapping Section deleted successfully."
}
```

---

### Notifications Module

Manage employee notifications (approval-related and general).

#### GET `api/v1/notifications`

List notifications with filtering.

- **Description:** Retrieves notifications with optional filters.
- **Authentication:** Required (JWT Service Token)

**Query Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `employee_id` | integer | No | Filter by recipient employee ID |
| `is_read` | boolean | No | Filter by read status (true/false) |
| `notification_type` | string | No | Filter by type (e.g., "personal", "request_approved") |
| `module` | string | No | Filter by module |
| `per_page` | integer | No | Items per page (default: 10) |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Notifications retrieved successfully",
    "data": [
        {
            "id": 1,
            "approval_request_id": 1,
            "recipient_employee_id": 2,
            "notification_type": "personal",
            "message": "Request LV-2025-001 filed by Employee 1 is pending your approval",
            "url": null,
            "module": null,
            "request_reference_id": "LV-2025-001",
            "is_read": false,
            "read_at": null,
            "created_at": "2025-01-01T00:00:00.000000Z",
            "updated_at": "2025-01-01T00:00:00.000000Z"
        }
    ],
    "meta": { ... }
}
```

---

#### POST `api/v1/notifications`

Create a single generic notification.

- **Description:** Creates a notification not tied to an approval request. Broadcasts a `NotificationCreated` event via Reverb WebSocket.
- **Authentication:** Required (JWT Service Token)

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `recipient_employee_id` | integer | Yes | `required|integer|exists:employees,id` |
| `notification_type` | string | Yes | `required|string|max:255` |
| `message` | string | Yes | `required|string` |
| `url` | string | No | `nullable|string|max:500` |
| `module` | string | No | `nullable|string|max:255` |
| `reference_id` | string | No | `nullable|string|max:255` |

**WebSocket:** A `NotificationCreated` event is broadcast on the `notifications.{employeeId}` channel.

**Responses:**

- **201 Created:**

```json
{
    "success": true,
    "message": "Notification created successfully",
    "data": { ... }
}
```

---

#### POST `api/v1/notifications/bulk`

Create bulk notifications.

- **Description:** Sends the same notification to multiple employees.
- **Authentication:** Required (JWT Service Token)

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `recipient_employee_ids` | array | Yes | `required|array|min:1` |
| `recipient_employee_ids.*` | integer | Yes | `required|integer|exists:employees,id` |
| `notification_type` | string | Yes | `required|string|max:255` |
| `message` | string | Yes | `required|string` |
| `url` | string | No | `nullable|string|max:500` |
| `module` | string | No | `nullable|string|max:255` |
| `reference_id` | string | No | `nullable|string|max:255` |

**Responses:**

- **201 Created:**

```json
{
    "success": true,
    "message": "Notifications created successfully",
    "data": {
        "count": 5,
        "notifications": [ ... ]
    }
}
```

---

#### GET `api/v1/notifications/unread-count`

Get unread notification count.

- **Description:** Returns the count of unread notifications for an employee with optional type/module filters.
- **Authentication:** Required (JWT Service Token)

**Query Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `employee_id` | integer | No | Filter by employee ID |
| `notification_type` | string | No | Filter by type |
| `module` | string | No | Filter by module |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Unread count retrieved successfully",
    "data": {
        "unread_count": 3,
        "filters": {
            "employee_id": 2,
            "notification_type": null,
            "module": null
        }
    }
}
```

---

#### PATCH `api/v1/notifications/{id}/read`

Mark a single notification as read.

- **Description:** Marks a specific notification as read.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The notification ID |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Notification marked as read",
    "data": { ... }
}
```

---

#### PATCH `api/v1/notifications/read-all`

Mark all notifications as read for an employee (with filters).

- **Description:** Marks all unread notifications as read, optionally filtered by employee, type, or module.
- **Authentication:** Required (JWT Service Token)

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `employee_id` | integer | No | `nullable|integer|exists:employees,id` |
| `notification_type` | string | No | `nullable|string` |
| `module` | string | No | `nullable|string` |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Notifications marked as read",
    "data": {
        "updated_count": 5,
        "filters": {
            "employee_id": 2,
            "notification_type": null,
            "module": null
        }
    }
}
```

---

#### DELETE `api/v1/notifications/{id}`

Delete a notification.

- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Notification deleted successfully"
}
```

---

### Memo Module

Create and manage internal memos with employee assignments and attachments.

#### GET `api/v1/memo`

List memos with extensive filtering.

- **Description:** Retrieves memos with optional filters for type, urgency, number, subject, date range, and employee assignment.
- **Authentication:** Required (JWT Service Token)

**Query Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `type` | string | No | Filter by memo type or memo type name (partial match) |
| `level_of_urgency` / `urgency` | string | No | Filter by urgency level |
| `number` | string | No | Filter by memo number (partial match) |
| `subject` | string | No | Filter by title/subject (partial match) |
| `held_from` | date | No | Memos held on or after this date |
| `held_to` | date | No | Memos held on or before this date |
| `date_finalized` | date | No | Memos finalized on or after this date |
| `employee_id` | integer | No | Filter by employee assigned to the memo |
| `per_page` | integer | No | Items per page (default: 10, or "all") |

**Responses:**

- **200 OK:**

```json
{
    "data": [
        {
            "id": 1,
            "memo_type": "Regular",
            "level_of_urgency": "High",
            "memo_number": "M-2025-001",
            "title": "Staff Meeting",
            "held_from": "2025-01-15",
            "held_to": "2025-01-15",
            "place": "Conference Room A",
            "is_finalized": false,
            "date_finalized": null,
            "status": "Active",
            "employees": [
                {
                    "id": 1,
                    "employee_id": 2,
                    "employee_name": "Juan Dela Cruz",
                    "position": "HR Specialist",
                    "division": "Human Resources",
                    "section": "HR Operations",
                    "status": "Active"
                }
            ],
            "attachments": [
                {
                    "id": 1,
                    "date_of_attachment": "2025-01-10",
                    "name": "Agenda.pdf",
                    "file": "http://example.com/storage/uploads/memo/agenda.pdf",
                    "file_original_name": "Agenda.pdf",
                    "status": "Active"
                }
            ]
        }
    ],
    "version": "0.1.1",
    "pagination": {
        "current_page": 1,
        "per_page": 10,
        "total": 1,
        "last_page": 1,
        "from": 1,
        "to": 1,
        "next_page_url": null,
        "prev_page_url": null
    }
}
```

---

#### POST `api/v1/memo`

Create a new memo.

- **Description:** Creates a memo with optional employee assignments and file attachments.
- **Authentication:** Required (JWT Service Token)

**Request Body:**

Content-Type: `multipart/form-data` (supports file uploads)

| Field | Type | Required | Validation |
|---|---|---|---|
| `memo_type` | string | No | `nullable|string` |
| `level_of_urgency` | string | No | `nullable|string` |
| `number` | string | No | `nullable|string|unique:memos,memo_number` |
| `title` | string | No | `nullable|string` |
| `held_from` | date | No | `nullable|date` |
| `held_to` | date | No | `nullable|date` |
| `place` | string | No | `nullable|string` |
| `is_finalized` | boolean | No | `nullable|boolean` |
| `date_finalized` | date | No | `nullable|date` |
| `employees` | string (JSON) | No | `nullable|string` - JSON array of employee IDs |
| `attachments` | string (JSON) | No | `nullable|string` - JSON array of attachment metadata |
| `attachment_0`, `attachment_1`, ... | file | No | Uploaded files corresponding to attachment indices |
| `status` | string | No | `nullable|string` |

**Note:** The `employees` field is a JSON string like `[1, 2, 3]`. The `attachments` field is a JSON string like `[{"date_of_attachment": "2025-01-10", "name": "Agenda"}]`. Files are uploaded as `attachment_0`, `attachment_1`, etc. matching the index in the attachments array.

**Responses:**

- **201 Created:**

```json
{
    "success": true,
    "message": "Memo successfully created.",
    "data": {
        "id": 1,
        "memo_type": "Regular",
        "title": "Staff Meeting",
        "employees": [ ... ],
        "attachments": [ ... ]
    }
}
```

---

#### GET `api/v1/memo/{memo}`

Get a specific memo.

- **Description:** Retrieves a single memo with its employees and attachments.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `memo` | integer | Yes | The memo ID |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Memo successfully retrieved.",
    "data": {
        "id": 1,
        "memo_type": "Regular",
        ...
    }
}
```

- **404 Not Found:**

```json
{
    "success": true,
    "message": "No data found.",
    "data": []
}
```

---

#### PUT `api/v1/memo/{memo}`

Update a memo.

- **Description:** Updates a memo including employees and attachments (supports add/remove).
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `memo` | integer | Yes | The memo ID |

**Additional Fields for Update:**

| Field | Type | Required | Description |
|---|---|---|---|
| `deleted_employees` | string (JSON) | No | JSON array of employee IDs to remove |
| `deleted_attachments` | string (JSON) | No | JSON array of attachment IDs to remove |

**Request Body:** Same as `POST`, with additional `deleted_employees` and `deleted_attachments` fields.

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Memo successfully updated.",
    "data": { ... }
}
```

---

#### DELETE `api/v1/memo/{memo}`

Delete a memo.

- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Memo has been successfully deleted.",
    "data": null
}
```

---

#### PUT `api/v1/memo/{memo}/finalize`

Finalize a memo.

- **Description:** Marks a memo as finalized with the current date.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `memo` | integer | Yes | The memo ID |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Memo successfully finalized.",
    "data": { ... }
}
```

---

#### GET `api/v1/memo/list/dropdown`

Get memos for dropdown selection.

- **Description:** Returns a simple list of active memos with only `id` and `title` fields.
- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "data": [
        {
            "id": 1,
            "title": "Staff Meeting"
        },
        {
            "id": 2,
            "title": "Office Closure"
        }
    ]
}
```

---

### Inquiry Module

Manage employee inquiries and HR feedback.

#### GET `api/v1/inquiry`

List inquiries with extensive filtering.

- **Description:** Retrieves inquiries with filters for type, details, date range, feedback status, employee, and more.
- **Authentication:** Required (JWT Service Token)

**Query Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `type` | string/integer | No | Filter by inquiry type ID or name |
| `details` | string | No | Search by details (partial match) |
| `date_from` | date | No | Inquiries created on or after this date |
| `date_to` | date | No | Inquiries created on or before this date |
| `date` / `inquiry_date` | date | No | Exact date filter |
| `hr_feedback` | string | No | Search by HR feedback (partial match) |
| `feedback_by` | string | No | Search by feedback provider name |
| `is_read` | boolean | No | Filter by read status |
| `status` | string | No | Filter by status (partial match) |
| `employee_id` | integer | No | Filter by employee ID |
| `employee` | string | No | Filter by employee name (partial match) |
| `per_page` | integer | No | Items per page (default: 10, or "all") |

**Responses:**

- **200 OK:**

```json
{
    "data": [
        {
            "id": 1,
            "employee": "Juan Dela Cruz",
            "inquiry_type": "Leave Credit",
            "details": "How many leave credits do I have?",
            "inquiry_date": "2025-01-15",
            "inquiry_time": "10:30 AM",
            "hr_feedback": "You have 15 leave credits remaining.",
            "feedback_by": "Maria Santos",
            "is_read": true,
            "status": "Answered"
        }
    ],
    "version": "0.1.1",
    "pagination": { ... }
}
```

---

#### POST `api/v1/inquiry`

Create a new inquiry.

- **Description:** Creates a new employee inquiry.
- **Authentication:** Required (JWT Service Token)

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `employee_id` | integer | Yes | `required|integer` |
| `inquiry_type_id` | integer | No | `nullable|integer` |
| `inquiry_type` | string | No | `nullable|string` |
| `details` | string | No | `nullable|string` |
| `status` | string | No | `nullable|string` |

**Responses:**

- **201 Created:**

```json
{
    "success": true,
    "message": "Inquiry successfully created.",
    "data": { ... }
}
```

---

#### GET `api/v1/inquiry/{inquiry}`

Get a specific inquiry.

- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Inquiry successfully retrieved.",
    "data": { ... }
}
```

---

#### PUT `api/v1/inquiry/{inquiry}`

Update an inquiry.

- **Authentication:** Required (JWT Service Token)

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `inquiry_type_id` | integer | No | `nullable|integer` |
| `inquiry_type` | string | No | `nullable|string` |
| `details` | string | No | `nullable|string` |
| `hr_feedback` | string | No | `nullable|string` |
| `feedback_by` | integer | No | `nullable|integer` |
| `is_read` | boolean | No | `nullable|boolean` |
| `status` | string | No | `nullable|string` |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Inquiry successfully updated.",
    "data": { ... }
}
```

---

#### DELETE `api/v1/inquiry/{inquiry}`

Delete an inquiry.

- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Inquiry has been successfully deleted.",
    "data": null
}
```

---

#### PUT `api/v1/inquiry/{inquiry}/feedback`

Add HR feedback to an inquiry.

- **Description:** Adds HR feedback to an inquiry and marks it as read.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `inquiry` | integer | Yes | The inquiry ID |

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `hr_feedback` | string | No | `nullable|string` |
| `feedback_by` | integer | No | `nullable|integer` |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Inquiry HR feedback has been successfully added.",
    "data": { ... }
}
```

---

#### GET `api/v1/inquiry/list/dropdown`

Get inquiries for dropdown selection.

- **Description:** Returns a simple list of active inquiries with only `id` and `details` fields.
- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "data": [
        {
            "id": 1,
            "details": "How many leave credits do I have?"
        }
    ]
}
```

---

### Feedback Module

Manage general employee feedback forms (CSMF/Client Satisfaction).

#### GET `api/v1/feedback`

List feedback entries with filtering.

- **Authentication:** Required (JWT Service Token)

**Query Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `date_from` | date | No | Filter by creation date (on or after) |
| `date_to` | date | No | Filter by creation date (on or before) |
| `employee_name` | string | No | Search by employee name |
| `service_availed_of` | string | No | Search by service availed |
| `is_read` | boolean | No | Filter by read status |
| `employee_id` | integer | No | Filter by employee ID |
| `per_page` | integer | No | Items per page (default: 10, or "all") |

**Responses:**

- **200 OK:**

```json
{
    "data": [
        {
            "id": 1,
            "employee": "Juan Dela Cruz",
            "employee_id": 1,
            "date_created": "2025-01-15",
            "service_availed": "Leave Processing",
            "other": null,
            "hr_transacted_with": "Maria Santos",
            "service_timeliness": "5",
            "service_quality": "5",
            "service_attitude": "5",
            "overall_satisfaction": "5",
            "incident_details": null,
            "recommendation": "Keep up the good work!",
            "is_read": true,
            "marked_as_read_datetime": "2025-01-16 09:00 AM",
            "status": "Active"
        }
    ],
    "version": "0.1.1",
    "pagination": { ... }
}
```

---

#### POST `api/v1/feedback`

Create a new feedback entry.

- **Authentication:** Required (JWT Service Token)

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `employee_id` | integer | **Yes** | `required|integer` |
| `service_availed` | string | No | `nullable|string` |
| `other` | string | No | `nullable|string` |
| `hr_transacted_with` | integer | No | `nullable|integer` |
| `service_timeliness` | string | No | `nullable|string` |
| `service_quality` | string | No | `nullable|string` |
| `service_attitude` | string | No | `nullable|string` |
| `overall_satisfaction` | string | No | `nullable|string` |
| `incident_details` | string | No | `nullable|string` |
| `recommendation` | string | No | `nullable|string` |
| `status` | string | No | `nullable|string` |

**Responses:**

- **201 Created:**

```json
{
    "success": true,
    "message": "Feedback successfully created.",
    "data": { ... }
}
```

---

#### GET `api/v1/feedback/{general_feedback}`

Get a specific feedback entry.

- **Description:** Retrieves feedback with an additional `csmf_report` field containing a structured CSMF report.
- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Feedback successfully retrieved.",
    "data": { ... },
    "csmf_report": {
        "transaction": {
            "date": "15/01/2025",
            "service_name": "Leave Processing"
        },
        "client": {
            "first_name": "Juan",
            "middle_name": "Dela",
            "last_name": "Cruz",
            "age": 30,
            "sex": "Male",
            "contact": "09171234567",
            "email": "juan@example.com",
            "barangay": "Barangay 1",
            "municipality": "Manila",
            "province": "NCR"
        },
        "client_type": {
            "general_public": false,
            "ngo": false,
            "government_employee": false,
            "others": ""
        },
        "sector": {
            "indigenous_people": false,
            "senior_citizen": false,
            "pwd": false,
            "pregnant_women": false,
            "youth": false,
            "women": false,
            "others": ""
        },
        "citizens_charter": {
            "cc1": "",
            "cc2": "",
            "cc3": ""
        },
        "survey": {
            "SQD0": "N/A",
            "SQD1": "N/A",
            "SQD2": "N/A",
            "SQD3": "N/A",
            "SQD4": "N/A",
            "SQD5": "N/A",
            "SQD6": "N/A",
            "SQD7": "N/A",
            "SQD8": "N/A"
        },
        "service_staff": "Maria Santos",
        "feedback": "Keep up the good work!"
    }
}
```

---

#### PUT `api/v1/feedback/{general_feedback}`

Update a feedback entry.

- **Authentication:** Required (JWT Service Token)

**Request Body:** Same fields as `POST` (all optional).

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Feedback successfully updated.",
    "data": { ... }
}
```

---

#### DELETE `api/v1/feedback/{general_feedback}`

Delete a feedback entry.

- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Feedback has been successfully deleted.",
    "data": null
}
```

---

#### PUT `api/v1/feedback/{general_feedback}/marked`

Mark feedback as read.

- **Description:** Marks feedback as read with the current datetime.
- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Feedback successfully marked as read.",
    "data": { ... }
}
```

---

### Announcements Module

Manage company announcements with optional file attachments.

#### GET `api/v1/announcements`

List announcements with advanced search.

- **Description:** Retrieves announcements with optional column-based advanced search filters.
- **Authentication:** Required (JWT Service Token)

**Query Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `per_page` | integer | No | Items per page (default: 10) |
| `columnName` | array | No | Array of column names to search |
| `columnName.*` | string | - | Column name (e.g., "subject", "body") |
| `operator` | array | No | Array of operators ("contains", "equals") |
| `operator.*` | string | - | Operator corresponding to each column |
| `value` | array | No | Array of search values |
| `value.*` | string | - | Value corresponding to each column |

**Responses:**

- **200 OK:**

```json
{
    "data": [
        {
            "id": 1,
            "subject": "Office Closure",
            "date": "2025-01-15",
            "body": "The office will be closed on January 20...",
            "attachment_path": "announcements/closure.pdf",
            "created_at": "2025-01-10T00:00:00.000000Z",
            "updated_at": "2025-01-10T00:00:00.000000Z"
        }
    ],
    "pagination": { ... }
}
```

---

#### POST `api/v1/announcements`

Create a new announcement.

- **Authentication:** Required (JWT Service Token)

**Request Body:**

Content-Type: `multipart/form-data`

| Field | Type | Required | Validation |
|---|---|---|---|
| `subject` | string | **Yes** | `required|string|max:255` |
| `date` | date | **Yes** | `required|date` |
| `body` | string | **Yes** | `required|string` |
| `attachment` | file | No | `nullable|file|max:5120` (5MB max) |

**Responses:**

- **201 Created:**

```json
{
    "id": 1,
    "subject": "Office Closure",
    "date": "2025-01-15",
    "body": "The office will be closed...",
    "attachment_path": "announcements/closure.pdf",
    "created_at": "...",
    "updated_at": "..."
}
```

**Note:** Response is the resource directly; not wrapped in `success/data`.

---

#### GET `api/v1/announcements/{announcement}`

Get a specific announcement.

- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:** Returns announcement object directly.

---

#### PUT `api/v1/announcements/{announcement}`

Update an announcement.

- **Authentication:** Required (JWT Service Token)

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `subject` | string | No | `sometimes|required|string|max:255` |
| `date` | date | No | `sometimes|required|date` |
| `body` | string | No | `sometimes|required|string` |
| `attachment` | file | No | `nullable|file|max:5120` |

**Responses:**

- **200 OK:** Returns updated announcement object directly.

---

#### DELETE `api/v1/announcements/{announcement}`

Delete an announcement.

- **Description:** Deletes the announcement and removes the associated attachment file from storage.
- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "message": "Deleted successfully"
}
```

---

### Dashboard Carousels Module

Manage dashboard carousel images.

#### GET `api/v1/dashboard-carousels`

List all carousel items.

- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
[
    {
        "id": 1,
        "attachment_path": "dashboard/carousel/slide1.jpg",
        "created_at": "...",
        "updated_at": "..."
    }
]
```

**Note:** Returns an array of items directly, not wrapped.

---

#### POST `api/v1/dashboard-carousels`

Upload a carousel image.

- **Authentication:** Required (JWT Service Token)

**Request Body:**

Content-Type: `multipart/form-data`

| Field | Type | Required | Validation |
|---|---|---|---|
| `attachment` | file | **Yes** | `required|file|max:5120` (5MB max) |

**Responses:**

- **201 Created:** Returns created carousel object.

---

#### GET `api/v1/dashboard-carousels/{dashboard_carousel}`

Get a specific carousel item.

- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:** Returns carousel object directly.

---

#### PUT `api/v1/dashboard-carousels/{dashboard_carousel}`

Update a carousel image.

- **Authentication:** Required (JWT Service Token)

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `attachment` | file | No | `nullable|file|max:5120` |

**Responses:**

- **200 OK:** Returns updated carousel object. If a new attachment is uploaded, the old one is deleted from storage.

---

#### DELETE `api/v1/dashboard-carousels/{dashboard_carousel}`

Delete a carousel item.

- **Description:** Deletes the carousel item and removes the associated image from storage.
- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "message": "Deleted successfully"
}
```

---

### Taxation Payroll Module

Manage payroll data for taxation purposes.

#### GET `api/v1/taxation-payrolls`

List payroll records.

- **Authentication:** Required (JWT Service Token)

**Query Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `payroll_no` | string | No | Filter by payroll number |
| `per_page` | integer | No | Items per page (default: 10) |

**Responses:**

- **200 OK:**

```json
{
    "data": [
        {
            "id": 1,
            "payroll_no": "PR-2025-001",
            "employee_no": "EMP-001",
            "name": "Juan Dela Cruz",
            "monthly_basic": "25000.00",
            "net_amount_due": "22000.00",
            "gross_pay": "25000.00",
            "awop": "0.00",
            "net_awop": "25000.00",
            "total_deduction": "3000.00",
            "tax_10": "500.00",
            "tax_5": "250.00",
            "tax_3": "150.00",
            "philhealth": "500.00",
            "sss": "1000.00",
            "pagibig": "200.00",
            "created_at": "...",
            "updated_at": "..."
        }
    ],
    "pagination": { ... }
}
```

---

#### POST `api/v1/taxation-payrolls`

Create a single payroll record.

- **Authentication:** Required (JWT Service Token)

**Request Body:**

All fields are optional strings:

| Field | Type | Validation |
|---|---|---|
| `payroll_no` | string | `nullable|string` |
| `employee_no` | string | `nullable|string` |
| `name` | string | `nullable|string` |
| `monthly_basic` | string | `nullable|string` |
| `net_amount_due` | string | `nullable|string` |
| `gross_pay` | string | `nullable|string` |
| `awop` | string | `nullable|string` |
| `net_awop` | string | `nullable|string` |
| `total_deduction` | string | `nullable|string` |
| `tax_10` | string | `nullable|string` |
| `tax_5` | string | `nullable|string` |
| `tax_3` | string | `nullable|string` |
| `philhealth` | string | `nullable|string` |
| `sss` | string | `nullable|string` |
| `pagibig` | string | `nullable|string` |

**Responses:**

- **201 Created:**

```json
{
    "success": true,
    "data": { ... }
}
```

---

#### POST `api/v1/taxation-payrolls/bulk`

Bulk save payroll data.

- **Description:** Replaces all rows for a given `payroll_no` with the provided data (deletes existing rows first, then inserts).
- **Authentication:** Required (JWT Service Token)

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `payroll_no` | string | **Yes** | `required|string` |
| `rows` | array | **Yes** | `required|array` |

**Rows fields:** Same fields as single `POST` (all optional per row).

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Payroll saved successfully."
}
```

---

#### GET `api/v1/taxation-payrolls/{taxation_payroll}`

Get a specific payroll record.

- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:** Returns payroll object directly.

---

#### PUT `api/v1/taxation-payrolls/{taxation_payroll}`

Update a payroll record.

- **Authentication:** Required (JWT Service Token)

**Request Body:** Same fields as single `POST` (all optional).

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "data": { ... }
}
```

---

#### DELETE `api/v1/taxation-payrolls/{taxation_payroll}`

Delete a payroll record.

- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Deleted successfully"
}
```

---

### System Trails Module

Audit logging for all microservice activities.

#### POST `api/v1/system-trails`

Log a system trail entry.

- **Description:** Creates an audit log entry (rate-limited to 60 requests per minute).
- **Authentication:** Required (JWT Service Token)

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `module` | string | **Yes** | `required|string|max:100|in:identity,hris-general,payroll,reports` |
| `action` | string | No | `nullable|string|max:100` |
| `endpoint` | string | No | `nullable|string|max:255` |
| `performed_by` | string | No | `nullable|string|max:100` |
| `payload` | array | No | `nullable|array|max:50` |

**Rate Limit:** This endpoint is throttled to 60 requests per minute.

**Responses:**

- **201 Created:**

```json
{
    "status": "logged"
}
```

---

#### GET `api/v1/system-trails`

List system trails with advanced search.

- **Authentication:** Required (JWT Service Token)

**Query Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `per_page` | integer/string | No | Items per page (default: 10, max: 100, or "all") |
| `columnName` | array | No | Array of column names to filter (`module`, `action`, `endpoint`, `method`, `performed_by`, `ip_address`, `created_at`) |
| `columnName.*` | string | - | Column name |
| `operator` | array | No | Array of operators (`=`, `like`, `!=`, `>`, `>=`, `<`, `<=`) |
| `operator.*` | string | - | Operator |
| `value` | array | No | Array of values |
| `value.*` | string | - | Value |

**Responses:**

- **200 OK:**

```json
{
    "data": [
        {
            "id": 1,
            "module": "hris-general",
            "action": "store",
            "endpoint": "/api/v1/approval-settings",
            "method": "POST",
            "performed_by": "admin",
            "payload": "{\"code\": \"LEAVE-APPROVAL\", ...}",
            "ip_address": "192.168.1.1",
            "created_at": "2025-01-01T00:00:00.000000Z",
            "updated_at": "2025-01-01T00:00:00.000000Z"
        }
    ],
    "pagination": { ... }
}
```

---

### Employment Statuses Module

Manage employment status reference data. Supports status-field-based soft deletion — set `status` to `'Inactive'` to deactivate, `'Active'` to reactivate.

#### GET `api/v1/employment-statuses`

List employment statuses with optional filtering, search, and pagination.

- **Description:** Retrieves a paginated list of employment statuses. Use `?status=Active` or `?status=Inactive` to filter. All records are returned by default.
- **Authentication:** Required (JWT Service Token)

**Query Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `search` | string | No | Search by `name` (partial match) |
| `status` | string | No | Filter by status (`Active` or `Inactive`) |
| `per_page` | integer | No | Items per page (default: 10) |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Employment statuses retrieved successfully",
    "data": [
        {
            "id": 1,
            "name": "Regular",
            "status": "Active",
            "created_at": "2025-01-01T00:00:00.000000Z",
            "updated_at": "2025-01-01T00:00:00.000000Z"
        },
        {
            "id": 2,
            "name": "Probationary",
            "status": "Active",
            "created_at": "2025-01-01T00:00:00.000000Z",
            "updated_at": "2025-01-01T00:00:00.000000Z"
        }
    ],
    "meta": {
        "current_page": 1,
        "per_page": 10,
        "total": 2,
        "last_page": 1
    }
}
```

---

#### POST `api/v1/employment-statuses`

Create a new employment status.

- **Description:** Creates a new employment status record.
- **Authentication:** Required (JWT Service Token)

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `name` | string | Yes | `required\|string\|max:255\|unique:employment_statuses,name` |
| `status` | string | No | `sometimes\|string\|max:40\|in:Active,Inactive` (defaults to `"Active"`) |

**Example:**

```json
{
    "name": "Regular",
    "status": "Active"
}
```

**Responses:**

- **201 Created:**

```json
{
    "success": true,
    "message": "Employment status created successfully",
    "data": {
        "id": 1,
        "name": "Regular",
        "status": "Active",
        "created_at": "2025-01-01T00:00:00.000000Z",
        "updated_at": "2025-01-01T00:00:00.000000Z"
    }
}
```

- **422 Unprocessable Entity (validation error):**

```json
{
    "success": false,
    "message": "Validation Error",
    "errors": {
        "name": [
            "The name has already been taken."
        ]
    }
}
```

---

#### GET `api/v1/employment-statuses/{id}`

Get a specific employment status.

- **Description:** Retrieves a single employment status by ID.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The employment status ID |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Employment status retrieved successfully",
    "data": {
        "id": 1,
        "name": "Regular",
        "status": "Active",
        "created_at": "2025-01-01T00:00:00.000000Z",
        "updated_at": "2025-01-01T00:00:00.000000Z"
    }
}
```

- **404 Not Found:**

```json
{
    "success": false,
    "message": "Employment status not found"
}
```

---

#### PATCH `api/v1/employment-statuses/{id}`

Update an employment status.

- **Description:** Updates an existing employment status record.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The employment status ID |

**Request Body:**

| Field | Type | Required | Validation |
|---|---|---|---|
| `name` | string | Yes | `required\|string\|max:255\|unique:employment_statuses,name,{id}` |
| `status` | string | No | `sometimes\|string\|max:40\|in:Active,Inactive` |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Employment status updated successfully",
    "data": {
        "id": 1,
        "name": "Regular Employee",
        "status": "Active",
        "created_at": "2025-01-01T00:00:00.000000Z",
        "updated_at": "2025-01-02T00:00:00.000000Z"
    }
}
```

---

#### DELETE `api/v1/employment-statuses/{id}`

Deactivate an employment status (soft delete via status field).

- **Description:** Sets the employment status to `'Inactive'`. The record is not removed from the database.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The employment status ID |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Employment status deactivated successfully"
}
```

---

#### POST `api/v1/employment-statuses/{id}/restore`

Reactivate an employment status (restore from status-based soft delete).

- **Description:** Sets the employment status back to `'Active'`. The record must currently have `status = 'Inactive'`.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The employment status ID (must be currently inactive) |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Employment status activated successfully",
    "data": {
        "id": 1,
        "name": "Regular",
        "status": "Active",
        "created_at": "2025-01-01T00:00:00.000000Z",
        "updated_at": "2025-01-03T00:00:00.000000Z"
    }
}
```

- **404 Not Found:**
```json
{
    "success": false,
    "message": "Failed to activate employment status",
    "error": "No query results for model [App\\Models\\EmploymentStatus] 1"
}
```

---

#### DELETE `api/v1/employment-statuses/{id}/force-delete`

Permanently delete an inactive employment status.

- **Description:** Permanently removes the record from the database. The record must currently have `status = 'Inactive'`.
- **Authentication:** Required (JWT Service Token)

**Path Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `id` | integer | Yes | The employment status ID (must be inactive) |

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Employment status permanently deleted"
}
```

- **404 Not Found:**
```json
{
    "success": false,
    "message": "Failed to permanently delete employment status",
    "error": "No query results for model [App\\Models\\EmploymentStatus] 1"
}
```

---

#### GET `api/v1/employment-statuses/trashed/list`

List inactive (soft-deleted) employment statuses.

- **Description:** Retrieves all employment statuses where `status = 'Inactive'`.
- **Authentication:** Required (JWT Service Token)

**Responses:**

- **200 OK:**

```json
{
    "success": true,
    "message": "Inactive employment statuses retrieved successfully",
    "data": [
        {
            "id": 2,
            "name": "Contractual",
            "status": "Inactive",
            "created_at": "2025-01-01T00:00:00.000000Z",
            "updated_at": "2025-01-03T00:00:00.000000Z"
        }
    ],
    "meta": {
        "current_page": 1,
        "per_page": 10,
        "total": 1,
        "last_page": 1
    }
}
```

---

## 5. Data Models

### Standard Response Envelope

Most endpoints (except a few noted above) return responses in this envelope:

```json
{
    "success": true|false,
    "message": "Descriptive message string",
    "data": { ... } | [ ... ] | null,
    "meta": {  // Only for paginated index endpoints
        "current_page": 1,
        "per_page": 10,
        "total": 100,
        "last_page": 10
    }
}
```

### Resources with Pagination

The Memo, Inquiry, and General Feedback endpoints use a slightly different pagination structure via Resource Collections:

```json
{
    "data": [ ... ],
    "version": "0.1.1",
    "pagination": {
        "current_page": 1,
        "per_page": 10,
        "total": 100,
        "last_page": 10,
        "from": 1,
        "to": 10,
        "next_page_url": "http://...",
        "prev_page_url": null
    }
}
```

### Approval Level Object

```json
{
    "id": 1,
    "approval_setting_id": 1,
    "level": 1,
    "approver_employee_id": 2,
    "alternative_approver_employee_id": 3,
    "is_final_approver": false
}
```

### Approval Chain Snapshot Entry

```json
{
    "level": 1,
    "approval_level_id": 1,
    "approver_employee_id": 2,
    "approver_name": "Juan Dela Cruz",
    "alternative_approver_employee_id": 3,
    "alternative_approver_name": "Maria Santos",
    "is_final_approver": false
}
```

### Approval History Entry

```json
{
    "id": 1,
    "approval_level_id": 1,
    "approver_employee_id": 2,
    "action": "approved|rejected|switched_to_alternative",
    "comments": "Approved after review",
    "approved_at": "2025-01-02T00:00:00.000000Z",
    "created_at": "2025-01-02T00:00:00.000000Z"
}
```

### Notification Object

```json
{
    "id": 1,
    "approval_request_id": 1,
    "recipient_employee_id": 2,
    "notification_type": "personal|request_approved|request_rejected|moved_to_next_level",
    "message": "Notification text",
    "url": null,
    "module": null,
    "request_reference_id": "LV-2025-001",
    "is_read": false,
    "read_at": null,
    "created_at": "...",
    "updated_at": "..."
}
```

### Employment Status Object

```json
{
    "id": 1,
    "name": "Regular",
    "status": "Active|Inactive",
    "created_at": "2025-01-01T00:00:00.000000Z",
    "updated_at": "2025-01-01T00:00:00.000000Z"
}
```

| Field | Type | Description |
|---|---|---|
| `id` | integer | Auto-increment primary key |
| `name` | string | Unique employment status name (e.g., "Regular", "Probationary", "Contractual") |
| `status` | string | `"Active"` (live) or `"Inactive"` (soft-deleted). Use `DELETE` to set Inactive, `POST {id}/restore` to set Active |
| `created_at` | datetime | Timestamp when the record was created |
| `updated_at` | datetime | Timestamp when the record was last updated |
