# Resident Beds Management API Documentation

Dành cho Frontend Team - Tài liệu API Quản lý Giường cho Cư dân

---

## Table of Contents

- [Overview](#overview)
- [Authentication](#authentication)
- [Response Format](#response-format)
- [API Endpoints](#api-endpoints)
  - [Get Resident with Residence Info](#0-get-resident-with-residence-info)
  - [Add Beds to Resident](#1-add-beds-to-resident)
  - [Update Beds for Resident](#2-update-beds-for-resident)
  - [Remove Beds from Resident](#3-remove-beds-from-resident)
- [Complete Workflows](#complete-workflows)
- [Error Handling](#error-handling)

---

## Overview

Resident Beds Management API cho phép quản lý việc gán/cập nhật/xóa giường cho cư dân. Mỗi cư dân có thể được gán vào một hoặc nhiều giường trong các phòng khác nhau.

**Features**:
- Thêm mới giường cho cư dân với ngày chuyển vào và loại ở (permanent/temporary)
- Cập nhật danh sách giường: tự động đánh dấu giường cũ là đã chuyển ra, thêm giường mới
- Xóa giường khỏi danh sách với lý do chuyển ra và ghi chú

**Base URL**: `https://api.example.com/api/v1`

---

## Authentication

Tất cả API đều yêu cầu Bearer token trong header:

```http
Authorization: Bearer <access_token>
```

**Roles Required**:
- `admin`: Quản trị viên - full access
- `system_admin`: Quản trị viên hệ thống - full access

---

## Response Format

### Success Response

```json
{
  "success": true,
  "trace_id": null,
  "timestamp": "2024-01-15T08:30:00.000Z",
  "errors": null,
  "data": { ... }
}
```

### Error Response

```json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": [
      {
        "field": "bed_ids",
        "code": "INVALID_UUID",
        "messages": {
          "vi": "ID không hợp lệ",
          "en": "Invalid ID format"
        }
      }
    ]
  }
}
```

---

## API Endpoints

### 0. Get Resident with Residence Info

Lấy thông tin chi tiết của cư dân bao gồm danh sách nơi ở hiện tại.

```http
GET /api/v1/residents/{id}
```

**Middleware**: `verify`, `requireAdmin`, `validateId`

**Path Parameters**:

| Parameter | Type   | Required | Description             |
| --------- | ------ | -------- | ----------------------- |
| id        | string | Yes      | UUID của cư dân         |

**Example Request**:

```bash
curl -X GET https://api.example.com/api/v1/residents/550e8400-e29b-41d4-a716-446655440001 \
  -H "Authorization: Bearer <access_token>"
```

**Success Response**:

```json
{
  "success": true,
  "trace_id": null,
  "timestamp": "2024-01-15T08:30:00.000Z",
  "errors": null,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "user_id": "550e8400-e29b-41d4-a716-446655440000",
    "full_name": "Nguyễn Văn A",
    "email": "nguyenvana@example.com",
    "phone": "+84 901 234 567",
    "id_card": "001234567890",
    "date_of_birth": "1990-05-15",
    "emergency_contact_name": "Nguyễn Thị B",
    "emergency_contact_phone": "+84 902 345 678",
    "emergency_contact_relationship": "Vợ",
    "status": "active",
    "created_at": "2024-01-15T08:30:00.000Z",
    "updated_at": "2024-01-20T10:00:00.000Z",
    "residences": [
      {
        "id": "stay-001",
        "resident_id": "550e8400-e29b-41d4-a716-446655440001",
        "bed_id": "00000001-0001-0001-0001-000000000014",
        "building_id": "880e8400-e29b-41d4-a716-446655440001",
        "building_name": "Tòa nhà A",
        "building_code": "TNA-001",
        "apartment_id": "990e8400-e29b-41d4-a716-446655440001",
        "apartment_name": "Căn hộ 101",
        "apartment_code": "CH-101",
        "apartment_floor": 1,
        "room_id": "aa0e8400-e29b-41d4-a716-446655440001",
        "room_name": "Phòng 101A",
        "room_code": "P-101A",
        "bed_name": "Giường 1",
        "bed_code": "G-001",
        "move_in_at": "2024-01-15T08:30:00.000Z",
        "move_out_at": null,
        "stay_type": "permanent",
        "status": "active"
      }
    ]
  }
}
```

**Response Fields**:

| Field        | Type   | Description                                                    |
| ------------ | ------ | -------------------------------------------------------------- |
| id           | string | UUID của cư dân                                                |
| user_id      | string | UUID của user account liên kết (nếu có)                        |
| full_name    | string | Họ tên đầy đủ của cư dân                                       |
| email        | string | Email của cư dân                                               |
| phone        | string | Số điện thoại                                                  |
| id_card      | string | Số CCCD/CMND                                                   |
| date_of_birth| string | Ngày sinh (YYYY-MM-DD)                                         |
| status       | string | Trạng thái: `active`, `inactive`                               |
| residences   | array  | Mảng các nơi ở hiện tại của cư dân (xem chi tiết bên dưới)     |

**Residence Object Fields**:

| Field               | Type    | Description                                                    |
| ------------------- | ------- | -------------------------------------------------------------- |
| id                  | string  | UUID của record residence (resident_stay)                      |
| resident_id         | string  | UUID của cư dân                                                |
| bed_id              | string  | UUID của giường                                                 |
| building_id         | string  | UUID của tòa nhà                                               |
| building_name       | string  | Tên tòa nhà                                                    |
| building_code       | string  | Mã tòa nhà                                                     |
| apartment_id        | string  | UUID của căn hộ                                                |
| apartment_name      | string  | Tên căn hộ                                                     |
| apartment_code      | string  | Mã căn hộ                                                      |
| apartment_floor     | number  | Tầng của căn hộ                                                |
| room_id             | string  | UUID của phòng                                                 |
| room_name           | string  | Tên phòng                                                      |
| room_code           | string  | Mã phòng                                                       |
| bed_name            | string  | Tên giường                                                      |
| bed_code            | string  | Mã giường                                                       |
| move_in_at          | string  | Ngày giờ chuyển vào (ISO 8601)                                 |
| move_out_at         | string  | Ngày giờ chuyển ra (null nếu đang ở)                           |
| stay_type           | string  | Loại ở: `permanent` hoặc `temporary`                           |
| status              | string  | Trạng thái: `active` (đang ở), `inactive` (đã chuyển ra)      |

**Behavior**:
- `residences` là mảng chứa tất cả nơi ở hiện tại của cư dân (status = 'active')
- Nếu cư dân không có nơi ở nào, `residences` sẽ là mảng rỗng `[]`
- Mỗi residence object chứa đầy đủ thông tin về building, apartment, room, và bed
- `move_out_at` = null cho các nơi đang ở, có giá trị cho các nơi đã chuyển ra

**Permissions**: `admin`, `system_admin` only

**Errors**:

- `UNAUTHORIZED`: Token không hợp lệ hoặc hết hạn
- `FORBIDDEN`: User không có quyền admin
- `NOT_FOUND`: Cư dân không tồn tại

---

### 1. Add Beds to Resident

Thêm một hoặc nhiều giường mới cho cư dân.

```http
POST /api/v1/residents/{id}/beds
```

**Middleware**: `verify`, `requireAdmin`, `validateId`, `validateZod(ResidentAddBedsBodySchema)`

**Path Parameters**:

| Parameter | Type   | Required | Description             |
| --------- | ------ | -------- | ----------------------- |
| id        | string | Yes      | UUID của cư dân         |

**Request Body**:

```json
{
  "bed_ids": [
    "00000001-0001-0001-0001-000000000014",
    "00000001-0001-0001-0001-000000000015"
  ],
  "move_in_at": "2024-01-15T08:30:00Z",
  "stay_type": "permanent"
}
```

| Field      | Type   | Required | Default    | Description                                                                 |
| ---------- | ------ | -------- | ---------- | --------------------------------------------------------------------------- |
| bed_ids    | array  | Yes      | -          | Mảng UUID của các giường muốn thêm. Tối thiểu 1 giường                       |
| move_in_at | string | No       | current time | Ngày giờ chuyển vào theo ISO 8601 (YYYY-MM-DDTHH:mm:ssZ)                     |
| stay_type  | enum   | No       | permanent  | Loại ở: `permanent` (thường trú) hoặc `temporary` (tạm trú)                 |

**Example Request**:

```bash
curl -X POST https://api.example.com/api/v1/residents/550e8400-e29b-41d4-a716-446655440001/beds \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "bed_ids": ["00000001-0001-0001-0001-000000000014"],
    "move_in_at": "2024-01-15T08:30:00Z",
    "stay_type": "permanent"
  }'
```

**Success Response**:

```json
{
  "success": true,
  "trace_id": null,
  "timestamp": "2024-01-15T08:30:00.000Z",
  "errors": null,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "user_id": "550e8400-e29b-41d4-a716-446655440000",
    "full_name": "Nguyễn Văn A",
    "email": "nguyenvana@example.com",
    "phone": "+84 901 234 567",
    "status": "active",
    "residences": [
      {
        "id": "stay-001",
        "resident_id": "550e8400-e29b-41d4-a716-446655440001",
        "bed_id": "00000001-0001-0001-0001-000000000014",
        "building_id": "880e8400-e29b-41d4-a716-446655440001",
        "building_name": "Tòa nhà A",
        "building_code": "TNA-001",
        "apartment_id": "990e8400-e29b-41d4-a716-446655440001",
        "apartment_name": "Căn hộ 101",
        "apartment_code": "CH-101",
        "apartment_floor": 1,
        "room_id": "aa0e8400-e29b-41d4-a716-446655440001",
        "room_name": "Phòng 101A",
        "room_code": "P-101A",
        "bed_name": "Giường 1",
        "bed_code": "G-001",
        "move_in_at": "2024-01-15T08:30:00.000Z",
        "move_out_at": null,
        "stay_type": "permanent",
        "status": "active"
      }
    ]
  }
}
```

**Permissions**: `admin`, `system_admin` only

**Errors**:

- `UNAUTHORIZED`: Token không hợp lệ hoặc hết hạn
- `FORBIDDEN`: User không có quyền admin
- `NOT_FOUND`: Cư dân không tồn tại
- `VALIDATION_ERROR`: Dữ liệu không hợp lệ (bed_ids rỗng, UUID sai format, v.v.)

---

### 2. Update Beds for Resident

Cập nhật danh sách giường cho cư dân. Giường không có trong danh sách mới sẽ được đánh dấu là đã chuyển ra, giường mới sẽ được thêm vào.

```http
PUT /api/v1/residents/{id}/beds
```

**Middleware**: `verify`, `requireAdmin`, `validateId`, `validateZod(ResidentUpdateBedsBodySchema)`

**Path Parameters**:

| Parameter | Type   | Required | Description             |
| --------- | ------ | -------- | ----------------------- |
| id        | string | Yes      | UUID của cư dân         |

**Request Body**:

```json
{
  "bed_ids": [
    "00000001-0001-0001-0001-000000000015"
  ],
  "move_out_at": "2024-12-15T10:00:00Z",
  "move_out_reason": "Chuyển phòng",
  "move_out_notes": "Yêu cầu chuyển sang phòng khác"
}
```

| Field           | Type   | Required | Description                                                                 |
| --------------- | ------ | -------- | --------------------------------------------------------------------------- |
| bed_ids         | array  | Yes      | Mảng UUID của các giường mới. Tối thiểu 1 giường                             |
| move_out_at     | string | No       | Ngày giờ chuyển ra cho các giường bị loại bỏ khỏi danh sách (ISO 8601)      |
| move_out_reason | string | No       | Lý do chuyển ra                                                              |
| move_out_notes  | string | No       | Ghi chú chi tiết về việc chuyển ra                                          |

**Example Request**:

```bash
curl -X PUT https://api.example.com/api/v1/residents/550e8400-e29b-41d4-a716-446655440001/beds \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "bed_ids": ["00000001-0001-0001-0001-000000000015"],
    "move_out_at": "2024-12-15T10:00:00Z",
    "move_out_reason": "Chuyển phòng",
    "move_out_notes": "Yêu cầu chuyển sang phòng khác"
  }'
```

**Success Response**:

```json
{
  "success": true,
  "trace_id": null,
  "timestamp": "2024-01-15T08:30:00.000Z",
  "errors": null,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "full_name": "Nguyễn Văn A",
    "email": "nguyenvana@example.com",
    "residences": [
      {
        "id": "stay-002",
        "resident_id": "550e8400-e29b-41d4-a716-446655440001",
        "bed_id": "00000001-0001-0001-0001-000000000015",
        "building_name": "Tòa nhà A",
        "apartment_name": "Căn hộ 102",
        "room_name": "Phòng 102A",
        "bed_name": "Giường 2",
        "move_in_at": "2024-12-15T10:00:00.000Z",
        "move_out_at": null,
        "stay_type": "permanent",
        "status": "active"
      }
    ]
  }
}
```

**Behavior**:
- Giường không có trong `bed_ids` mới sẽ được cập nhật `move_out_at` và `move_out_reason`
- Giường mới trong `bed_ids` sẽ được thêm với `move_in_at` = hiện tại và `stay_type` = `permanent`
- Trả về thông tin chi tiết về số giường được thêm và xóa trong audit log

**Permissions**: `admin`, `system_admin` only

**Errors**:

- `UNAUTHORIZED`: Token không hợp lệ hoặc hết hạn
- `FORBIDDEN`: User không có quyền admin
- `NOT_FOUND`: Cư dân không tồn tại
- `VALIDATION_ERROR`: Dữ liệu không hợp lệ

---

### 3. Remove Beds from Resident

Xóa một hoặc nhiều giường khỏi danh sách của cư dân.

```http
DELETE /api/v1/residents/{id}/beds
```

**Middleware**: `verify`, `requireAdmin`, `validateId`

**Path Parameters**:

| Parameter | Type   | Required | Description             |
| --------- | ------ | -------- | ----------------------- |
| id        | string | Yes      | UUID của cư dân         |

**Request Body**:

```json
{
  "bed_ids": [
    "00000001-0001-0001-0001-000000000014"
  ],
  "move_out_at": "2024-12-15T10:00:00Z",
  "move_out_reason": "Ra viện",
  "move_out_notes": "Đã hoàn thành điều trị"
}
```

| Field           | Type   | Required | Description                                                                 |
| --------------- | ------ | -------- | --------------------------------------------------------------------------- |
| bed_ids         | array  | Yes      | Mảng UUID của các giường muốn xóa. Tối thiểu 1 giường                        |
| move_out_at     | string | No       | Ngày giờ chuyển ra (ISO 8601)                                               |
| move_out_reason | string | No       | Lý do chuyển ra                                                              |
| move_out_notes  | string | No       | Ghi chú chi tiết                                                            |

**Example Request**:

```bash
curl -X DELETE https://api.example.com/api/v1/residents/550e8400-e29b-41d4-a716-446655440001/beds \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "bed_ids": ["00000001-0001-0001-0001-000000000014"],
    "move_out_at": "2024-12-15T10:00:00Z",
    "move_out_reason": "Ra viện",
    "move_out_notes": "Đã hoàn thành điều trị"
  }'
```

**Success Response**:

```json
{
  "success": true,
  "trace_id": null,
  "timestamp": "2024-01-15T08:30:00.000Z",
  "errors": null,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "full_name": "Nguyễn Văn A",
    "email": "nguyenvana@example.com",
    "residences": []
  }
}
```

**Behavior**:
- Các giường được đánh dấu `move_out_at` và cập nhật thông tin lý do chuyển ra
- Nếu tất cả giường bị xóa, `residences` sẽ là mảng rỗng
- Audit log được ghi lại với thông tin chi tiết

**Permissions**: `admin`, `system_admin` only

**Errors**:

- `UNAUTHORIZED`: Token không hợp lệ hoặc hết hạn
- `FORBIDDEN`: User không có quyền admin
- `NOT_FOUND`: Cư dân không tồn tại
- `VALIDATION_ERROR`: `bed_ids` không được rỗng hoặc không phải là mảng

---

## Complete Workflows

### Workflow 1: Thêm cư dân mới vào giường

1. Tạo cư dân mới: `POST /api/v1/residents`
2. Thêm giường cho cư dân: `POST /api/v1/residents/{id}/beds`

```javascript
// Frontend example
const createResidentAndAssignBed = async (residentData, bedId) => {
  // Step 1: Create resident
  const residentResponse = await fetch('/api/v1/residents', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(residentData)
  });
  const resident = await residentResponse.json();
  
  // Step 2: Assign bed
  const bedResponse = await fetch(`/api/v1/residents/${resident.data.id}/beds`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      bed_ids: [bedId],
      move_in_at: new Date().toISOString(),
      stay_type: 'permanent'
    })
  });
  
  return await bedResponse.json();
};
```

### Workflow 2: Chuyển cư dân sang phòng khác

1. Cập nhật danh sách giường: `PUT /api/v1/residents/{id}/beds`
2. Xác nhận thông tin đã cập nhật: `GET /api/v1/residents/{id}`

```javascript
const transferResidentToNewRoom = async (residentId, newBedIds, reason, notes) => {
  const response = await fetch(`/api/v1/residents/${residentId}/beds`, {
    method: 'PUT',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      bed_ids: newBedIds,
      move_out_at: new Date().toISOString(),
      move_out_reason: reason,
      move_out_notes: notes
    })
  });
  
  return await response.json();
};
```

### Workflow 3: Xóa cư dân khỏi giường (ra viện/điều chuyển)

1. Xóa tất cả giường: `DELETE /api/v1/residents/{id}/beds`
2. Cập nhật trạng thái cư dân: `PUT /api/v1/residents/{id}`

```javascript
const dischargeResident = async (residentId, reason, notes) => {
  // Get current beds first
  const residentResponse = await fetch(`/api/v1/residents/${residentId}`);
  const resident = await residentResponse.json();
  const currentBedIds = resident.data.residences.map(r => r.bed_id);
  
  // Remove all beds
  const response = await fetch(`/api/v1/residents/${residentId}/beds`, {
    method: 'DELETE',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      bed_ids: currentBedIds,
      move_out_at: new Date().toISOString(),
      move_out_reason: reason,
      move_out_notes: notes
    })
  });
  
  return await response.json();
};
```

---

## Error Handling

### Common Error Codes

| Code                | Description                                             | HTTP Status |
| ------------------- | ------------------------------------------------------- | ----------- |
| UNAUTHORIZED        | Token không hợp lệ hoặc hết hạn                          | 401         |
| FORBIDDEN           | User không có quyền thực hiện hành động                  | 403         |
| NOT_FOUND           | Cư dân không tồn tại                                    | 404         |
| VALIDATION_ERROR    | Dữ liệu không hợp lệ                                    | 400         |
| INVALID_UUID_FORMAT | UUID không đúng format                                   | 400         |

### Validation Error Examples

**Empty bed_ids**:
```json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "bed_ids is required and must be a non-empty array",
    "details": {
      "message": "bed_ids is required and must be a non-empty array"
    }
  }
}
```

**Invalid UUID**:
```json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": [
      {
        "field": "bed_ids.0",
        "code": "INVALID_UUID",
        "messages": {
          "vi": "ID không hợp lệ",
          "en": "Invalid ID format"
        }
      }
    ]
  }
}
```

### Frontend Error Handling Example

```javascript
const handleBedsAPI = async (residentId, bedData, method = 'POST') => {
  try {
    const response = await fetch(`/api/v1/residents/${residentId}/beds`, {
      method,
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(bedData)
    });
    
    const result = await response.json();
    
    if (!response.ok) {
      // Handle specific errors
      if (result.error?.code === 'UNAUTHORIZED') {
        // Redirect to login
        window.location.href = '/login';
        return;
      }
      
      if (result.error?.code === 'FORBIDDEN') {
        showToast('Bạn không có quyền thực hiện hành động này', 'error');
        return;
      }
      
      if (result.error?.code === 'NOT_FOUND') {
        showToast('Cư dân không tồn tại', 'error');
        return;
      }
      
      if (result.error?.code === 'VALIDATION_ERROR') {
        // Show validation errors
        result.error.details?.forEach(detail => {
          showToast(detail.messages.vi, 'error');
        });
        return;
      }
      
      throw new Error(result.error?.message || 'Unknown error');
    }
    
    return result.data;
  } catch (error) {
    console.error('API Error:', error);
    showToast('Có lỗi xảy ra. Vui lòng thử lại sau.', 'error');
    throw error;
  }
};
```

---

## Notes

1. **Audit Logging**: Tất cả thao tác đều được ghi log audit với thông tin người thực hiện, thời gian, và chi tiết thay đổi
2. **Date Format**: Tất cả ngày giờ phải theo format ISO 8601 (YYYY-MM-DDTHH:mm:ssZ)
3. **UUID Format**: Tất cả ID phải là UUID v4 format
4. **Permissions**: Chỉ admin và system_admin mới có quyền thực hiện các thao tác này
5. **Response Data**: Tất cả API trả về thông tin cư dân với `residences` (mảng các chỗ ở hiện tại)

---

## Swagger Documentation

Xem tài liệu Swagger đầy đủ tại: `http://localhost:3001/swagger/index`

Tags: `Residents`
- `addResidentBeds` - POST /api/v1/residents/{id}/beds
- `updateResidentBeds` - PUT /api/v1/residents/{id}/beds
- `removeResidentBeds` - DELETE /api/v1/residents/{id}/beds
