# Tour leader: 國籍 & 護照資料 (frontend integration)

This document describes how the frontend should read and write **`nationality`** and **`passport_data`** on tour leader resources. All tour-leader routes require **Sanctum** authentication (`Authorization: Bearer <token>`) unless your deployment wraps them differently.

**Base path (typical Laravel setup):** `GET|POST|PUT|PATCH|DELETE /api/tour-leaders`  
(Confirm the `/api` prefix in your environment; it comes from `routes/api.php`.)

---

## Summary

| Field | Type in API | Meaning |
|--------|-------------|---------|
| `nationality` | `string \| null` | 國籍 (free text, max 100 characters). |
| `passport_data` | `object \| null` | Structured passport fields (stored as JSON in a `longText` column). |
| `passport_file_path` | `string \| null` | **Separate** from `passport_data`: uploaded scan/PDF of the passport (existing feature). |

Do **not** use a flat `passport_number` field on tour leaders; use `passport_data.number` instead.

---

## `passport_data` shape

The backend validates these **optional** nested keys:

| Key | Type | Notes |
|-----|------|--------|
| `number` | `string` | 護照號碼 (max 50 characters). |
| `issue_date` | `string` (date) | 發證日期; use **`YYYY-MM-DD`**. |
| `expiry_date` | `string` (date) | 到期日; use **`YYYY-MM-DD`**. |

The database stores arbitrary JSON; you may add extra keys for UI-only use, but only the keys above are validated. Prefer sending dates in ISO format so validation passes reliably.

### Example value

```json
{
  "number": "123456789",
  "issue_date": "2020-01-15",
  "expiry_date": "2030-01-14"
}
```

---

## TypeScript types (suggested)

```ts
export type TourLeaderPassportData = {
  number?: string | null;
  issue_date?: string | null; // YYYY-MM-DD
  expiry_date?: string | null; // YYYY-MM-DD
  // optional: extra keys if you need them client-side
};

export type TourLeader = {
  id: number;
  user_id: number;
  nationality: string | null;
  passport_data: TourLeaderPassportData | null;
  passport_file_path: string | null;
  // ...other tour leader fields
};
```

---

## Reading data (GET)

Any endpoint that returns a full tour leader record includes these fields when present:

- `GET /api/tour-leaders` (paginated list)
- `GET /api/tour-leaders/{id}`
- `GET /api/tour-leaders/list/options`
- `GET /api/tour-leaders/schedule/list`

**Response:** `passport_data` is a **JSON object** (or `null` if never set). Example:

```json
{
  "id": 1,
  "nationality": "中華民國",
  "passport_data": {
    "number": "123456789",
    "issue_date": "2020-01-15",
    "expiry_date": "2030-01-14"
  },
  "passport_file_path": "passports/uuid.pdf"
}
```

Bind form fields to `nationality`, `passport_data.number`, `passport_data.issue_date`, and `passport_data.expiry_date`. Normalize date inputs to `YYYY-MM-DD` before sending updates.

---

## Creating a tour leader (POST)

**Endpoint:** `POST /api/tour-leaders`

- **Content-Type:** `application/json` **or** `multipart/form-data` (if you upload `license_file` / `passport_file`).

### JSON body (no files)

```json
{
  "user_name": "leader01",
  "password": "secret123",
  "password_confirmation": "secret123",
  "english_alias": "John Smith",
  "chinese_name": "張三",
  "english_last_name": "Smith",
  "english_first_name": "John",
  "gender": "M",
  "nationality": "中華民國",
  "passport_data": {
    "number": "123456789",
    "issue_date": "2020-01-15",
    "expiry_date": "2030-01-14"
  }
}
```

### Multipart form (with files)

Use nested fields so Laravel maps them to an array:

- `passport_data[number]`
- `passport_data[issue_date]`
- `passport_data[expiry_date]`
- `nationality`

Alternatively, send a single JSON string field only if your client library supports it and the backend is extended to decode it (not required if you use nested keys above).

---

## Updating a tour leader (PUT / PATCH)

**Endpoint:** `PUT /api/tour-leaders/{id}` or `PATCH /api/tour-leaders/{id}`

### Partial update (merge behaviour)

When you send **`passport_data`**, the server **merges** your object with the existing stored `passport_data`. You can update only one field (e.g. `expiry_date`) without resending `number` and `issue_date`; omitted keys keep their previous values.

Example: only updating the expiry date:

```json
{
  "passport_data": {
    "expiry_date": "2031-12-31"
  }
}
```

### Clearing passport data

Send **`passport_data` as `null`** to remove the entire stored object:

```json
{
  "passport_data": null
}
```

### Clearing a single nested field

To clear e.g. `number` while keeping dates, send that key as `null` if your client sends JSON:

```json
{
  "passport_data": {
    "number": null
  }
}
```

(Behaviour follows PHP `array_replace` on the merged object.)

### Updating only `nationality`

```json
{
  "nationality": "日本"
}
```

The update request still requires **at least one** recognized field overall (existing validation rule).

---

## Validation errors

Typical rules:

- `nationality`: optional string, max 100.
- `passport_data`: optional array/object.
- `passport_data.number`: optional string, max 50.
- `passport_data.issue_date` / `expiry_date`: optional, must be valid dates (use `YYYY-MM-DD`).

If validation fails, the API returns **422** with Laravel-style error bags keyed by field names (e.g. `passport_data.issue_date`).

---

## Permissions

Creating/updating tour leaders is restricted to **admin/sales** role in the controller layer, in addition to request authorization (`manage_tour_leader` or `admin`). Align your UI with the same roles so users do not see edit actions they cannot complete.

---

## Relation to `passport_file` upload

- **`passport_data`**: structured text fields (number + dates).
- **`passport_file`**: multipart file upload for a passport **image/PDF** (stored as `passport_file_path`).

You can use both on the same leader: one for machine-readable form fields, one for the document scan.

---

## Database / migrations (ops)

Migrations add `nationality` and `passport_data` (`longText` JSON). If an older environment had a legacy `passport_number` column, a follow-up migration migrates it into `passport_data.number`. Run `php artisan migrate` on deploy.

---

## Quick checklist for frontend

1. Display `nationality` and `passport_data.*` from GET responses.
2. On save, send `nationality` and/or nested `passport_data` with ISO dates.
3. On PATCH, send only changed keys inside `passport_data` when you rely on merge behaviour.
4. Use `passport_data: null` to clear all structured passport fields.
5. Keep passport **file** uploads separate via `passport_file` when needed.
