# Flow tổng quan


Source: https://docs.fleetwork.vn/sdk/optimize-summary

> Tài liệu mô tả luồng sử dụng API Optimize: từ danh sách task cần làm của một nhân viên đến kết quả lộ trình tối ưu để hiển thị trên bản đồ.

---

## Mục tiêu

Khi ứng dụng đã có:

- một nhân viên cần đi làm việc trong ngày
- danh sách các điểm cần ghé qua
- vị trí bắt đầu và kết thúc hành trình

thì có thể gửi dữ liệu đó vào API Optimize để nhận về:

- thứ tự các điểm nên đi
- thời gian đến dự kiến tại từng điểm
- tổng thời gian di chuyển dự kiến
- tổng quãng đường dự kiến
- dữ liệu route để vẽ lên map

---

## Endpoint sử dụng

```http
POST https://live.fleetwork.vn/api/v1/optimize
Content-Type: application/json
X-API-Key: <your_api_key>
```

Sai hoặc thiếu `X-API-Key` sẽ trả về:

```json
{
  "error": "UNAUTHORIZED",
  "message": "Missing or invalid X-API-Key",
  "code": 401
}
```

---

## Flow end-to-end

```text
1. Người dùng chọn 1 nhân viên
2. Hệ thống có danh sách task cần làm của nhân viên đó
3. Ứng dụng map danh sách task thành payload Optimize
4. Gọi POST /api/v1/optimize
5. API trả về route tối ưu
6. Ứng dụng đọc các steps trong route
7. Vẽ thứ tự điểm đi lên map
8. Hiển thị ETA từng điểm, tổng thời gian đi và tổng km dự kiến
```

---

## 1. Dữ liệu đầu vào từ nghiệp vụ

Thông thường phía ứng dụng sẽ có dữ liệu như sau:

| Nhóm dữ liệu      | Ví dụ                                           |
| ----------------- | ----------------------------------------------- |
| Nhân viên         | `userId`, tên nhân viên                         |
| Điểm xuất phát    | văn phòng, kho, chi nhánh, hoặc vị trí hiện tại |
| Danh sách task    | danh sách khách hàng / điểm giao dịch cần ghé   |
| Thời gian phục vụ | mỗi điểm cần ở lại bao lâu                      |
| Khung giờ         | điểm nào có giờ hẹn cụ thể                      |

Trong bài toán đơn giản “1 nhân viên đi nhiều điểm”, có thể xem:

- `1 nhân viên = 1 vehicle`
- mỗi điểm cần làm = `1 job`

---

## 2. Map sang payload Optimize

Ví dụ: một nhân viên có 3 task cần làm trong ngày.

```json
{
  "jobs": [
    {
      "id": 101,
      "description": "Điểm A",
      "location": [106.70098, 10.77689],
      "service": 600,
      "priority": 90
    },
    {
      "id": 102,
      "description": "Điểm B",
      "location": [106.68411, 10.78021],
      "service": 900,
      "priority": 80,
      "time_windows": [[1713402000, 1713405600]]
    },
    {
      "id": 103,
      "description": "Điểm C",
      "location": [106.6751, 10.76543],
      "service": 300,
      "priority": 70
    }
  ],
  "vehicles": [
    {
      "id": 1,
      "description": "Nhân viên user-001",
      "profile": "car",
      "start": [106.66017, 10.76262],
      "end": [106.66017, 10.76262],
      "time_window": [1713398400, 1713430800]
    }
  ]
}
```

### Cách hiểu payload

| Thành phần                | Ý nghĩa                                  |
| ------------------------- | ---------------------------------------- |
| `jobs`                    | Danh sách điểm nhân viên cần ghé         |
| `location`                | Tọa độ điểm đến theo `[lon, lat]`        |
| `service`                 | Thời gian làm việc tại điểm, đơn vị giây |
| `time_windows`            | Khung giờ được phép đến điểm             |
| `vehicles[0]`             | Nhân viên thực hiện route                |
| `start`                   | Điểm bắt đầu                             |
| `end`                     | Điểm kết thúc                            |
| `time_window` của vehicle | Khung giờ làm việc trong ngày            |

---

## 3. API trả về gì

Khi tối ưu thành công, API trả về:

- `summary`: chỉ số tổng quan toàn route
- `routes`: danh sách route được tối ưu
- `steps`: từng điểm bắt đầu, từng task, và điểm kết thúc

Ví dụ rút gọn:

```json
{
  "code": 0,
  "summary": {
    "routes": 1,
    "duration": 4310,
    "service": 1800,
    "distance": 24500,
    "unassigned": 0
  },
  "routes": [
    {
      "vehicle": 1,
      "duration": 4310,
      "distance": 24500,
      "steps": [
        {
          "type": "start",
          "arrival": 1713398400,
          "location": [106.66017, 10.76262]
        },
        {
          "type": "job",
          "id": 101,
          "arrival": 1713402100,
          "service": 600,
          "location": [106.70098, 10.77689]
        },
        {
          "type": "job",
          "id": 102,
          "arrival": 1713403400,
          "service": 900,
          "location": [106.68411, 10.78021]
        },
        {
          "type": "job",
          "id": 103,
          "arrival": 1713405200,
          "service": 300,
          "location": [106.6751, 10.76543]
        },
        {
          "type": "end",
          "arrival": 1713406900,
          "location": [106.66017, 10.76262]
        }
      ]
    }
  ]
}
```

---

## 4. Ứng dụng dùng response như thế nào

### 4.1 Hiển thị thứ tự lộ trình

Ứng dụng đọc `routes[0].steps` theo thứ tự để biết:

1. điểm bắt đầu
2. điểm ghé thứ nhất
3. điểm ghé thứ hai
4. ...
5. điểm kết thúc

Đây chính là thứ tự tối ưu mà API đề xuất.

### 4.2 Hiển thị thời gian đến từng điểm (ETA)

Field dùng để hiển thị ETA là:

- `steps[].arrival`

Ví dụ:

| Điểm   | Arrival      | Ý nghĩa                      |
| ------ | ------------ | ---------------------------- |
| Điểm A | `1713402100` | Thời gian đến dự kiến điểm A |
| Điểm B | `1713403400` | Thời gian đến dự kiến điểm B |
| Điểm C | `1713405200` | Thời gian đến dự kiến điểm C |

> Lưu ý: trong Optimize, thời gian mặc định đang theo **seconds**.

### 4.3 Hiển thị tổng thời gian đi dự kiến

Field dùng:

- `summary.duration`
  hoặc
- `routes[0].duration`

Đơn vị: giây.

Ví dụ:

```text
routes[0].duration = 4310 giây ≈ 71 phút 50 giây
```

### 4.4 Hiển thị tổng km đi dự kiến

Field dùng:

- `summary.distance`
  hoặc
- `routes[0].distance`

Đơn vị: mét.

Ví dụ:

```text
routes[0].distance = 24500 mét = 24.5 km
```

### 4.5 Vẽ lên map

Ứng dụng có thể vẽ route theo 2 mức:

| Cách vẽ                   | Dữ liệu dùng                                        |
| ------------------------- | --------------------------------------------------- |
| Vẽ marker theo thứ tự ghé | `routes[0].steps[].location`                        |
| Vẽ polyline route         | `geometry` nếu backend có bật trả về route geometry |

Nếu response chưa có `geometry`, ứng dụng vẫn có thể:

- vẽ marker theo thứ tự
- nối các điểm bằng polyline đơn giản
- hoặc gọi thêm routing engine để dựng đường đi chi tiết

---

## 5. Luồng hiển thị trên giao diện

```text
Danh sách task của nhân viên
        ↓
Map sang payload Optimize
        ↓
POST /api/v1/optimize
        ↓
Nhận response tối ưu
        ↓
Đọc routes[0].steps
        ↓
Hiển thị:
  - Thứ tự các điểm cần đi
  - ETA từng điểm
  - Tổng thời gian di chuyển
  - Tổng km dự kiến
  - Lộ trình trên bản đồ
```

---

## 6. Các field thường quan tâm nhất

| Mục đích hiển thị               | Field nên dùng                              |
| ------------------------------- | ------------------------------------------- |
| Có tối ưu thành công không      | `code == 0`                                 |
| Có bao nhiêu route              | `summary.routes`                            |
| Có task nào chưa gán được không | `summary.unassigned`, `unassigned[]`        |
| Tổng thời gian đi dự kiến       | `summary.duration` hoặc `routes[].duration` |
| Tổng km đi dự kiến              | `summary.distance` hoặc `routes[].distance` |
| ETA tại từng điểm               | `routes[].steps[].arrival`                  |
| Thứ tự ghé điểm                 | `routes[].steps[]` theo thứ tự mảng         |
| Tọa độ để vẽ map                | `routes[].steps[].location`                 |

---

## 7. Khi nào nên gọi lại API Optimize

Nên gọi lại tối ưu route khi có thay đổi như:

- thêm task mới
- bỏ một task khỏi danh sách
- đổi vị trí bắt đầu / kết thúc
- đổi khung giờ hẹn của task
- đổi nhân viên thực hiện route
