# Frontend API Updates: Addon Request Activity Log & Notifications

This document describes backend changes that affect the frontend: **Addon Request Activity Log** (replacing status history), **Notifications API**, and **breaking changes** to addon request detail responses.

---

## 1. Summary of Changes

| Area | Change |
|------|--------|
| **Addon Request detail** | `status_history` removed. Use **`activity_log`** for all change history (including status changes). |
| **New APIs** | Notifications: list, unread count, mark read (single / all). |
| **Assignee task detail** | Same: `status_history` → **`activity_log`**. |

All notification and addon-request endpoints require **`Authorization: Bearer <token>`** (Sanctum).

---

## 2. Addon Request: Activity Log (Replaces Status History)

### 2.1 What Changed

- **Removed:** `status_history` array and `statusHistory` relationship from addon request responses.
- **Added:** `activity_log` array. It includes **all** changes (status, assignment, field updates, etc.), not only status.

### 2.2 Where Activity Log Appears

- **GET** `/api/addon-requests/{id}` — Addon request detail (main CRUD show).
- **GET** `/api/assignee/my-tasks/{id}` — Assigned task detail.
- **PATCH** `/api/addon-requests/{id}/status` — Response includes refreshed addon request (no longer includes `statusHistory`; use activity log).
- **PATCH** `/api/assignee/my-tasks/{id}/accept` — Response `data` includes `activity_log`.
- **PATCH** `/api/assignee/my-tasks/{id}/complete` — Response `data` includes `activity_log`.
- **PATCH** `/api/assignee/my-tasks/{id}/status` — Response `data` includes `activity_log`.

### 2.3 Response Shape: `activity_log`

Each addon request (and assigned task) now has an **`activity_log`** array (ordered by newest first). Each entry:

| Field | Type | Description |
|-------|------|-------------|
| `id` | number | Activity log entry ID. |
| `addon_request_id` | number | Addon request ID. |
| `user_id` | number \| null | User who performed the action (null for system). |
| `action` | string | Action type (see table below). |
| `changes` | object \| null | For status/field changes: `{ "field_name": { "old": ..., "new": ... } }`. |
| `description` | string \| null | Human-readable note (e.g. status change reason). |
| `created_at` | string | ISO 8601 datetime. |
| `user` | object \| null | Eager-loaded: `{ id, name, display_name }` when present. |

**Action constants (for UI labels / filtering):**

| `action` | Suggested label (TW) |
|----------|----------------------|
| `created` | 建立需求 |
| `updated` | 更新資料 |
| `status_changed` | 狀態變更 |
| `assigned` | 指派人員 |
| `unassigned` | 取消指派 |
| `comment_added` | 新增留言 |
| `file_uploaded` | 上傳檔案 |
| `file_deleted` | 刪除檔案 |
| `item_added` | 新增項目 |
| `item_updated` | 更新項目 |
| `item_deleted` | 刪除項目 |
| `approval_approved` | 審核通過 |
| `approval_rejected` | 審核駁回 |
| `payment_added` | 新增付款 |
| `payment_removed` | 移除付款 |

**Example `changes` for status change:**

```json
{
  "status": {
    "old": "pending",
    "new": "in_progress"
  }
}
```

**Example `changes` for general update (e.g. estimated cost + title):**

```json
{
  "estimated_cost": { "old": 1000, "new": 1500 },
  "title": { "old": "舊標題", "new": "新標題" }
}
```

### 2.4 Frontend Action Items

1. **Replace any use of `status_history`** with **`activity_log`**.
2. **Status timeline:** Filter `activity_log` by `action === 'status_changed'` and use `changes.status.old` / `changes.status.new` plus `description` and `user`.
3. **General timeline:** Use full `activity_log` with `action` and `changes` to show a single “all changes” feed.
4. **Assignee task screens:** Use `activity_log` instead of `statusHistory` in task detail and after accept/complete/updateStatus.

---

## 3. Notifications API

New APIs for in-app notifications (e.g. addon request created, status changed, cost updated). Each notification is stored once; read state is per user (no duplicate rows per recipient).

**Base path:** `/api/notifications`  
**Auth:** Required (Sanctum).

### 3.1 List Notifications

**GET** `/api/notifications`

**Query parameters:**

| Parameter | Type | Default | Description |
|-----------|------|---------|--------------|
| `per_page` | number | 15 | Pagination size. |
| `type` | string | — | Filter by notification type (e.g. `addon_request.status_changed`). |
| `unread_only` | boolean | false | If `true`, return only unread notifications. |

**Response (200):**

```json
{
  "success": true,
  "data": {
    "current_page": 1,
    "data": [
      {
        "id": "uuid-string",
        "type": "addon_request.status_changed",
        "notifiable_type": "App\\Models\\AddonRequest",
        "notifiable_id": 123,
        "data": { ... },
        "created_by_user_id": 5,
        "created_at": "2026-03-11T10:00:00.000000Z",
        "pivot_read_at": "2026-03-11T11:00:00.000000Z"
      }
    ],
    "first_page_url": "...",
    "from": 1,
    "last_page": 3,
    "last_page_url": "...",
    "links": [...],
    "next_page_url": "...",
    "path": "...",
    "per_page": 15,
    "prev_page_url": null,
    "to": 15,
    "total": 42
  }
}
```

- **`pivot_read_at`:** `null` = unread; non-null ISO datetime = read at that time.
- **`notifiable_type` / `notifiable_id`:** For addon notifications, type is `App\Models\AddonRequest` and `notifiable_id` is the addon request ID. Use this to deep-link to `/addon-requests/{notifiable_id}`.

### 3.2 Unread Count

**GET** `/api/notifications/unread-count`

**Response (200):**

```json
{
  "success": true,
  "data": {
    "unread_count": 7
  }
}
```

Use for badge / “7 unread” in the header.

### 3.3 Mark One as Read

**PATCH** `/api/notifications/{notificationId}/read`

- **`notificationId`:** UUID of the notification (from list/detail).

**Response (200):**

```json
{
  "success": true,
  "message": "通知已標記為已讀"
}
```

### 3.4 Mark All as Read

**PATCH** `/api/notifications/all/read`

**Response (200):**

```json
{
  "success": true,
  "message": "已將 7 則通知標記為已讀"
}
```

### 3.5 Notification Types and `data` Payload

All addon-related notifications have `notifiable_type` = `App\Models\AddonRequest` and `notifiable_id` = addon request ID. The **`data`** object always includes at least:

| Field | Type | Description |
|-------|------|-------------|
| `addon_request_id` | number | Same as `notifiable_id`. |
| `request_number` | string | e.g. `AR-20260311-0001`. |
| `title` | string | Addon request title. |
| `message` | string | Display message (e.g. for list item). |

**By type:**

| `type` | When | Extra `data` fields |
|--------|------|----------------------|
| `addon_request.created` | New addon request created | `category`, `status` |
| `addon_request.status_changed` | Status changed | `old_status`, `new_status` |
| `addon_request.updated` | Field(s) updated (e.g. cost, title) | `changed_fields` (array of field names) |
| `addon_request.approval_required` | Approval needed | — |
| `addon_request.completed` | Request completed | `final_cost`, `cost_currency` |
| `addon_request.overdue` | Request overdue | — |
| `addon_request.communication_added` | New communication on request | `communication_id`, `sender_type`, `message_type` |
| `addon_request.customer_response_overdue` | Customer response overdue | `communication_id` |
| `addon_request.daily_digest` | Daily digest of pending requests | `category`, `count` |

Frontend can use `type` for icons/colors and `data` for secondary text and links (e.g. link to addon request, to communication).

---

## 4. Breaking Changes Checklist

| Before | After |
|--------|--------|
| Addon request / task detail: `status_history[]` with `previous_status`, `new_status`, `changed_by_user_id`, `notes` | Use **`activity_log[]`** with `action`, `changes`, `description`, `user_id`, `user`. |
| No notifications API | Use **GET/PATCH** `/api/notifications` and **GET** `/api/notifications/unread-count`. |

---

## 5. Quick Reference: Endpoints

| Method | Path | Description |
|--------|------|-------------|
| GET | `/api/addon-requests/{id}` | Addon request detail (includes `activity_log`). |
| GET | `/api/assignee/my-tasks/{id}` | Assigned task detail (includes `activity_log`). |
| GET | `/api/notifications` | Paginated notifications (query: `per_page`, `type`, `unread_only`). |
| GET | `/api/notifications/unread-count` | Unread count for current user. |
| PATCH | `/api/notifications/{id}/read` | Mark one notification read. |
| PATCH | `/api/notifications/all/read` | Mark all notifications read. |

---

## 6. Example: Addon Request Detail Response (excerpt)

```json
{
  "success": true,
  "data": {
    "id": 1,
    "request_number": "AR-20260311-0001",
    "booking_id": 10,
    "status": "in_progress",
    "title": "機票加購",
    "activity_log": [
      {
        "id": 3,
        "addon_request_id": 1,
        "user_id": 2,
        "action": "status_changed",
        "changes": {
          "status": { "old": "pending", "new": "in_progress" }
        },
        "description": "指派後自動更新狀態",
        "created_at": "2026-03-11T09:00:00.000000Z",
        "user": {
          "id": 2,
          "name": "user@example.com",
          "display_name": "王小明"
        }
      },
      {
        "id": 2,
        "addon_request_id": 1,
        "user_id": 1,
        "action": "assigned",
        "changes": {
          "assigned_to_user_id": { "old": null, "new": 2 }
        },
        "description": "指派給 王小明",
        "created_at": "2026-03-11T08:55:00.000000Z",
        "user": { "id": 1, "name": "admin@example.com", "display_name": "管理員" }
      },
      {
        "id": 1,
        "addon_request_id": 1,
        "user_id": 1,
        "action": "created",
        "changes": null,
        "description": "建立加購需求: 機票加購",
        "created_at": "2026-03-11T08:00:00.000000Z",
        "user": { "id": 1, "name": "admin@example.com", "display_name": "管理員" }
      }
    ]
  }
}
```

**Note:** `status_history` is no longer present. Use `activity_log` only.

---

*Document version: 2026-03-11. Backend: addon request activity log, notifications API, status history removed.*
