# Contact Create Flow (Frontend Guide)

This document explains the full flow to create a contact, send an automatic invite email, and let the invited user set their first password.

## 1) Prerequisites

1. Admin user is already logged in and has an `access token`.
2. Admin user has already configured a Security PIN.
3. Frontend knows the target `role_id` (fetch from `GET /api/v1/roles/get-all`).

## 2) Endpoints Used

1. `POST /api/v1/auth/pin/verify` to get a PIN `action_token`.
2. `POST /api/v1/contacts/create` to create the contact (auto invite enabled).
3. `POST /api/v1/auth/set-password` to set the first password from invite token.

## 3) Detailed Flow

### Step A - Verify PIN for contact create action

Action ID for contact create:
- `2a59e8b4-5a72-4be3-b8fc-4f49941181c3`

Request:

```json
{
  "data": {
    "type": "auth_pin_verify",
    "attributes": {
      "pin": "123456",
      "action": "2a59e8b4-5a72-4be3-b8fc-4f49941181c3"
    }
  }
}
```

Success response:

```json
{
  "data": {
    "type": "auth_pin_verify",
    "attributes": {
      "verified": true,
      "action_token": "<PIN_ACTION_TOKEN>",
      "action_token_ttl_ms": 300000
    }
  }
}
```

Store `action_token`, then pass it to contact create in header:
- `X-PIN-Verification-Token: <PIN_ACTION_TOKEN>`

### Step B - Create Contact (auto invite)

Endpoint:
- `POST /api/v1/contacts/create`

Required headers:
- `Authorization: Bearer <ACCESS_TOKEN>`
- `X-PIN-Verification-Token: <PIN_ACTION_TOKEN>`
- `Content-Type: application/json`

Minimum required body:
- `data.type = contact_<role>_create`
- `attributes.role_id`
- `attributes.email`
- `attributes.first_name`
- `attributes.last_name`

Allowed create types:
- `contact_pilot_create`
- `contact_doctor_create`
- `contact_air_rescuer_create`
- `contact_technician_create`
- `contact_flight_assistant_create`
- `contact_staff_create`

Rules:
- `data.type` must match the role resolved from `attributes.role_id`.
- Only one role-specific profile object is allowed, and it must match `data.type`.

> Note: backend now **automatically sends an invite email** after successful contact creation.

If PIN token is missing/invalid, API returns `202` with PIN verification required error.

### Step C - User clicks invite link from email

Invite email contains a link like:
- `https://frontend-domain/set-password?token=<INVITE_TOKEN>`

This token already carries user identity (email + user id claims) and is single-use.

### Step D - Frontend submits set password

Endpoint:
- `POST /api/v1/auth/set-password`

Request:

```json
{
  "data": {
    "type": "auth_set_password",
    "attributes": {
      "token": "<INVITE_TOKEN>",
      "password": "StrongP@ssw0rd123"
    }
  }
}
```

If successful, user can directly log in using `POST /api/v1/auth/login`.

## 4) Contact Create Payloads by Role

## Pilot

```json
{
  "data": {
    "type": "contact_pilot_create",
    "attributes": {
      "role_id": "<ROLE_ID_PILOT>",
      "email": "pilot1@example.com",
      "username": "pilot1",
      "first_name": "Marco",
      "last_name": "Melandri",
      "mobile_phone": "+628123456789",
      "timezone": "Asia/Jakarta",
      "is_active": true,
      "pilot": {
        "pilot_category": "regular",
        "short_name": "Marco",
        "license_no": "PIL-001",
        "license_issued_at": "2025-01-01T00:00:00Z",
        "license_expired_at": "2028-01-01T00:00:00Z",
        "technician_license_no": "TECH-001",
        "has_ifr_qualification": true,
        "is_chief_pilot": false,
        "is_dul": false,
        "total_flight_minutes": 12000,
        "responsible_pilot_minutes": 5000,
        "second_pilot_minutes": 3000,
        "double_command_minutes": 1000,
        "flight_instructor_minutes": 500,
        "night_flight_minutes": 1200,
        "ifr_flight_minutes": 800,
        "location": "Jakarta",
        "postcode": "12950",
        "street_line": "Jl. Sudirman No. 1",
        "weight_kg": 72.5,
        "photo_file_id": "/uploads/contacts/pilot1.jpg"
      }
    }
  }
}
```

## Doctor

```json
{
  "data": {
    "type": "contact_doctor_create",
    "attributes": {
      "role_id": "<ROLE_ID_DOCTOR>",
      "email": "doctor1@example.com",
      "username": "doctor1",
      "first_name": "Alicia",
      "last_name": "Pratama",
      "mobile_phone": "+628123450001",
      "timezone": "Asia/Jakarta",
      "is_active": true,
      "doctor": {
        "short_name": "Dr. Alicia",
        "medical_license_no": "MED-DOCTOR-001",
        "license_issued_at": "2024-01-01T00:00:00Z",
        "license_expired_at": "2029-01-01T00:00:00Z",
        "specialization": "Emergency Medicine",
        "sub_specialization": "Trauma",
        "is_chief_physician": false,
        "location": "Jakarta",
        "postcode": "12950",
        "street_line": "Jl. Jenderal Sudirman No. 10",
        "photo_file_id": "/uploads/contacts/doctor1.jpg"
      }
    }
  }
}
```

## Air Rescuer

```json
{
  "data": {
    "type": "contact_air_rescuer_create",
    "attributes": {
      "role_id": "<ROLE_ID_AIR_RESCUER>",
      "email": "airrescuer1@example.com",
      "username": "airrescuer1",
      "first_name": "Raka",
      "last_name": "Wijaya",
      "mobile_phone": "+628123450002",
      "timezone": "Asia/Jakarta",
      "is_active": true,
      "air_rescuer": {
        "short_name": "Raka",
        "is_chief_physician_in_charge": false,
        "responsible_flight_rescuer": false,
        "location": "Bandung",
        "postcode": "40115",
        "street_line": "Jl. Merdeka No. 20",
        "photo_file_id": "/uploads/contacts/airrescuer1.jpg"
      }
    }
  }
}
```

## Technician

```json
{
  "data": {
    "type": "contact_technician_create",
    "attributes": {
      "role_id": "<ROLE_ID_TECHNICIAN>",
      "email": "tech1@example.com",
      "username": "tech1",
      "first_name": "Bima",
      "last_name": "Nugraha",
      "mobile_phone": "+628123450003",
      "timezone": "Asia/Jakarta",
      "is_active": true,
      "technician": {
        "short_name": "Bima",
        "license_no": "TECH-7788",
        "is_chief_technician": false,
        "is_responsible_complaints": true,
        "location": "Surabaya",
        "postcode": "60231",
        "street_line": "Jl. Diponegoro No. 30",
        "photo_file_id": "/uploads/contacts/tech1.jpg"
      }
    }
  }
}
```

## Flight Assistant

```json
{
  "data": {
    "type": "contact_flight_assistant_create",
    "attributes": {
      "role_id": "<ROLE_ID_FLIGHT_ASSISTANT>",
      "email": "fa1@example.com",
      "username": "fa1",
      "first_name": "Nadia",
      "last_name": "Putri",
      "mobile_phone": "+628123450004",
      "timezone": "Asia/Jakarta",
      "is_active": true,
      "flight_assistant": {
        "short_name": "Nadia",
        "location": "Yogyakarta",
        "postcode": "55281",
        "street_line": "Jl. Kaliurang No. 15",
        "photo_file_id": "/uploads/contacts/fa1.jpg"
      }
    }
  }
}
```

## Staff

```json
{
  "data": {
    "type": "contact_staff_create",
    "attributes": {
      "role_id": "<ROLE_ID_STAFF>",
      "email": "staff1@example.com",
      "username": "staff1",
      "first_name": "Dina",
      "last_name": "Maharani",
      "mobile_phone": "+628123450005",
      "timezone": "Asia/Jakarta",
      "is_active": true,
      "staff": {
        "short_name": "Dina",
        "role_label": "Operations Staff",
        "location": "Semarang",
        "postcode": "50132",
        "street_line": "Jl. Pandanaran No. 8",
        "photo_file_id": "/uploads/contacts/staff1.jpg"
      }
    }
  }
}
```

## 5) Example Create Contact Response

```json
{
  "data": {
    "type": "contact",
    "id": "019ce67e-9289-731d-ae4c-0156902aabbc",
    "attributes": {
      "role_code": "doctor",
      "role_name": "doctor",
      "email": "doctor1@example.com",
      "first_name": "Alicia",
      "last_name": "Pratama",
      "is_active": true,
      "doctor": {
        "short_name": "Dr. Alicia",
        "medical_license_no": "MED-DOCTOR-001"
      },
      "invite_sent": true,
      "invite_error": ""
    }
  }
}
```

If invite sending fails (for example SES/SQS config issue):
- contact create is still successful,
- `invite_sent = false`,
- `invite_error` contains the error message.

## 6) Error Cases Frontend Should Handle

1. `202 PIN verification required` on contact create:
   - call `/auth/pin/verify` again (Step A), then retry create with `X-PIN-Verification-Token`.
2. `422 Validation error`:
   - check payload fields (invalid role_id, invalid email, etc).
3. `400` on create:
   - typically business/constraint conflict.
4. `400` on set-password:
   - token invalid/expired/used or password does not meet rules.

## 7) Frontend Integration Summary

1. Admin logs in.
2. Fetch `role_id` from roles list.
3. Verify PIN (`/auth/pin/verify` with contact-create action ID).
4. Create contact (`/contacts/create` + `X-PIN-Verification-Token`).
5. Wait for invited user to open invite email.
6. Set-password page reads `token` from query param.
7. Submit `/auth/set-password` with `{ token, password }`.
8. Redirect user to login page.
