# Patient Records & Sessions API

## Overview

Patient records track patients per entity (doctor or clinic). Each record holds multiple sessions (visits). Access requires an active subscription with the `patient_records` feature.

**Base path:** `/api/v1`  
**Auth:** Bearer JWT (doctor, clinic, or secretary with `appointments.view` permission required)

---

## Endpoints

### List Patients

```
GET /api/v1/patients
```

Returns a paginated list of patient records belonging to the authenticated entity.

**Query params:**

| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `page` | int | 1 | Page number |
| `limit` | int | 20 | Items per page (10–50) |
| `search` | string | — | Search by patient name or phone |

**Response 200:**

```json
{
  "success": true,
  "data": [
    {
      "uuid": "...",
      "entity_type": "doctor",
      "entity_id": 5,
      "user": { "uuid": "...", "fullName": "علی رضایی", "phone": "09123456789" },
      "created_by_type": "doctor",
      "created_by_id": 5,
      "created_at": 1718375000
    }
  ],
  "meta": {
    "totalRecords": 42,
    "totalPages": 3,
    "currentPage": 1
  }
}
```

**Errors:**

| Code | HTTP | Description |
|------|------|-------------|
| `ERR_SUBSCRIPTION_REQUIRED` | 403 | No active plan with `patient_records` feature |

---

### Create Patient Record

```
POST /api/v1/patient
```

Creates a patient record for a user under the current entity. If the record already exists, returns the existing record (idempotent).

**Request body:**

```json
{
  "user_uuid": "string (required)"
}
```

**Response 201:**

```json
{
  "success": true,
  "data": {
    "uuid": "...",
    "entity_type": "doctor",
    "entity_id": 5,
    "user": { "uuid": "...", "fullName": "...", "phone": "..." },
    "created_by_type": "doctor",
    "created_by_id": 5,
    "created_at": 1718375000
  }
}
```

**Errors:**

| Code | HTTP | Description |
|------|------|-------------|
| `ERR_VALIDATION_001` | 422 | `user_uuid` missing |
| `ERR_NOT_FOUND_001` | 404 | User not found |
| `ERR_SUBSCRIPTION_REQUIRED` | 403 | No `patient_records` feature |

---

### Get Patient Record

```
GET /api/v1/patient/{uuid}
```

Returns a single patient record.

**Response 200:**

```json
{
  "success": true,
  "data": {
    "uuid": "...",
    "entity_type": "doctor",
    "entity_id": 5,
    "user": { "uuid": "...", "fullName": "...", "phone": "..." },
    "created_by_type": "doctor",
    "created_by_id": 5,
    "created_at": 1718375000
  }
}
```

**Errors:**

| Code | HTTP | Description |
|------|------|-------------|
| `ERR_PATIENT_NOT_FOUND` | 404 | Record not found or not owned by caller |
| `ERR_SUBSCRIPTION_REQUIRED` | 403 | No `patient_records` feature |

---

### List Patient Sessions

```
GET /api/v1/patient/{uuid}/sessions
```

Returns paginated sessions for a patient record.

**Query params:** `page`, `limit` (same as list)

**Response 200:**

```json
{
  "success": true,
  "data": [
    {
      "uuid": "...",
      "record_uuid": "...",
      "appointment_uuid": null,
      "insurance_base_id": null,
      "insurance_supplementary_id": null,
      "visit_price_rials": 200000,
      "base_insurance_discount_percent": "10.00",
      "supplementary_discount_percent": "5.00",
      "services_total_rials": 50000,
      "final_price_rials": 230000,
      "payment_method": "cash",
      "notes": "...",
      "created_at": 1718375000,
      "updated_at": 1718375000
    }
  ],
  "meta": { "totalRecords": 8, "totalPages": 1, "currentPage": 1 }
}
```

**Errors:**

| Code | HTTP | Description |
|------|------|-------------|
| `ERR_PATIENT_NOT_FOUND` | 404 | Record not found or not owned by caller |
| `ERR_SUBSCRIPTION_REQUIRED` | 403 | No `patient_records` feature |

---

### Create Session

```
POST /api/v1/patient/{uuid}/session
```

Creates a new visit session for a patient record.

**Request body:**

```json
{
  "visit_price_rials": 200000,
  "base_insurance_discount_percent": 10,
  "supplementary_discount_percent": 5,
  "insurance_base_id": null,
  "insurance_supplementary_id": null,
  "payment_method": "cash",
  "notes": "...",
  "services": [
    {
      "service_item_uuid": "...",
      "staff_uuid": null
    }
  ]
}
```

**Field notes:**

- `payment_method`: `cash` | `card` | `insurance` | `online` | `pending`
- `services`: array of service items to attach; `price_rials` is snapshot-copied from ServiceItem
- `final_price_rials` is computed: `(visit_price × (1 - base%) × (1 - supp%)) + services_total`

**Response 201:**

```json
{
  "success": true,
  "data": { ...session object... }
}
```

**Errors:**

| Code | HTTP | Description |
|------|------|-------------|
| `ERR_PATIENT_NOT_FOUND` | 404 | Record not found or not owned |
| `ERR_SUBSCRIPTION_REQUIRED` | 403 | No `patient_records` feature |

---

### Update Session

```
PATCH /api/v1/session/{uuid}
```

Updates mutable fields on a session.

**Request body (all optional):**

```json
{
  "notes": "...",
  "payment_method": "card"
}
```

**Response 200:**

```json
{
  "success": true,
  "data": { ...session object... }
}
```

**Errors:**

| Code | HTTP | Description |
|------|------|-------------|
| `ERR_SESSION_NOT_FOUND` | 404 | Session not found or not owned |

---

## Auto-Creation on Appointment Confirm

When an appointment's status changes to `confirmed` via `PATCH /api/v1/appointment/{uuid}/status`, the system automatically:

1. Creates a `PatientRecord` for the appointment's user (if not already existing) under the doctor entity
2. Creates a blank `PatientSession` linked to the appointment

This only runs if the doctor has the `patient_records` subscription feature active.
