# Client Patrol Login API

## Overview

Authenticates a client account for the client app and returns a Laravel
Sanctum bearer token. Login is allowed only when the account has the `Client`
role and is linked to at least one active client service. The active service
and its client and branch details are included in the response when available.

This is the client API login endpoint. Employee mobile login is documented
separately in [Employee_Patrol_Login_API.md](./Employee_Patrol_Login_API.md).

## Endpoint

```http
POST /api/v1/client/auth/login
Content-Type: application/json
Accept: application/json
```

No token is required to call this endpoint. Use the returned token for
subsequent protected API requests:

```http
Authorization: Bearer <sanctum-token>
```

## Request body

Send a JSON object with:

| Field | Type | Required | Description |
|---|---|---:|---|
| `login` | string | One identifier is required | Client email or phone number. |
| `username` | string | Fallback | Legacy alternative when `login` is omitted. |
| `email` | string | Fallback | Legacy alternative when `login` and `username` are omitted. |
| `password` | string | Yes | Client account password. |

The identifier precedence is `login`, then `username`, then `email`.
Whitespace around the selected identifier is trimmed. Phone numbers may match
the user's profile phone, the linked client service phone, or the linked
client's phone.

### Example

```bash
curl -X POST "http://localhost:8000/api/v1/client/auth/login" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "login": "client@example.com",
    "password": "your-password"
  }'
```

## Successful response

**HTTP 200**

```json
{
  "success": true,
  "message": "Login successful.",
  "data": {
    "token": "<sanctum-token>",
    "token_type": "Bearer",
    "user": {
      "id": 17,
      "name": "Example Client",
      "email": "client@example.com",
      "role": "Client"
    },
    "client": {
      "id": 8,
      "name": "Example Client",
      "code": "CLIENT-008"
    },
    "service": {
      "id": 25,
      "name": "Example Patrol Site",
      "type": "patrol"
    },
    "branch": {
      "code": "FWG007-KLG",
      "name": "KLG"
    }
  }
}
```

The IDs, names, and other client fields are examples. `client` is the linked
client record and may be `null` if the active service has no linked client.
`branch.code` and `branch.name` may also be `null` when no current active
employee assignment provides a branch. If the branch name is missing but a
branch code exists, the code is returned as the branch name.

The token is issued with the `client` ability. Its expiry is controlled by
`sanctum.token_expiry_days` and defaults to 30 days.

## Error responses

### Validation failed

**HTTP 422** — the identifier or password is missing or is not a string.

```json
{
  "success": false,
  "message": "Validation failed",
  "errors": {
    "login": [
      "The login field is required."
    ]
  }
}
```

The `errors` object contains the fields that failed validation.

### Invalid credentials or account role

**HTTP 401** — no account matched the identifier and password, or the matched
account does not have the `Client` role.

```json
{
  "success": false,
  "message": "The provided credentials do not match our client records."
}
```

### Inactive account

**HTTP 403** — the account has a status other than `active`.

```json
{
  "success": false,
  "message": "Your account is not active. Please contact administrator."
}
```

### Patrol Setup required

**HTTP 403** — credentials are valid, but the account is not linked to an
active client service.

```json
{
  "success": false,
  "message": "Please complete the Patrol Setup before logging in."
}
```

## Notes

- A client service is considered complete for this login gate when an active
  service has `client_user_id` set to the client account's user ID.
- The login response selects the first active service linked to the account.
- Employee assignment is not required to pass the client login gate; it is
  only used to populate branch details when a current active assignment exists.
- This API login is separate from the web client login at `POST /client/login`.

## Client break details

The authenticated client mobile app can load break configuration for the
active client service:

```http
GET /api/v1/client/breaks
Authorization: Bearer <token>
Accept: application/json
```

The API derives the client code from the authenticated account's active service
and fetches the current configuration from the .NET
`GetClientBreakList` endpoint. The upstream response is ordered by
`SortOrder` and currently supplies `BreakHours`, but no break names.

```json
{
  "success": true,
  "data": {
    "client_code": "FwgC000013",
    "breaks": [
      {
        "sort_order": 1,
      "name": "Break 1",
        "break_hours": 0.5,
        "duration_minutes": 30,
        "duration_hours": 0,
        "duration_remainder_minutes": 30
      }
    ]
  }
}
```

Only configured breaks are returned. The upstream response provides
`SortOrder` and `BreakHours`, not break names, so `name` is generated as
`Break {SortOrder}` (or uses a name if the upstream API starts providing one).
A client with no active service receives
HTTP 403, a missing client code receives HTTP 422, and an unavailable or
invalid .NET response receives HTTP 502.

The .NET response currently provides `BreakHours` and `SortOrder`, but no
start/end clock times. The dashboard therefore displays each configured
duration in hours and minutes; clock-time ranges require the .NET API to
provide those fields.
