# Admin API

> **Prefix:** `/api/v1/admin`  
> **Permission:** ALL endpoints in this file require `ROLE_ADMIN`  
> **Headers:** `Authorization: Bearer <admin_jwt_token>`

---

## Dashboard

### GET `/api/v1/admin/dashboard/stats`

Get key performance indicators (KPIs) for the dashboard.

**Permission:** `ROLE_ADMIN`

### Response `200`
```json
{
  "success": true,
  "data": {
    "total_users": 1200,
    "active_doctors": 85,
    "total_doctors": 92,
    "total_clinics": 34,
    "today_appointments": 47,
    "total_appointments": 8540,
    "today_payments_count": 30,
    "today_payments_amount": 15000000,
    "total_payments_amount": 425000000,
    "pending_comments": 12,
    "pending_settlements": 5,
    "this_month_revenue": 52000000,
    "this_month_appointments": 620
  }
}
```

---

### GET `/api/v1/admin/dashboard/charts`

Get chart data for the last 30 days.

**Permission:** `ROLE_ADMIN`

### Response `200`
```json
{
  "success": true,
  "data": {
    "appointments_30d": [
      { "date": "2024-06-01", "count": 42 }
    ],
    "revenue_30d": [
      { "date": "2024-06-01", "amount_rials": 21000000 }
    ],
    "appointment_status": {
      "confirmed": 350,
      "completed": 180,
      "cancelled": 45,
      "pending": 20,
      "no_show": 25
    },
    "top_specialties": [
      { "name": "قلب و عروق", "count": 120 }
    ]
  }
}
```

---

### GET `/api/v1/admin/dashboard/recent`

Get recent activity (last 10 of each type).

**Permission:** `ROLE_ADMIN`

### Response `200`
```json
{
  "success": true,
  "data": {
    "appointments": [
      {
        "uuid": "...",
        "doctor_title": "دکتر علی احمدی",
        "patient_name": "محمد رضایی",
        "slot_start": 1718438400,
        "status": "confirmed"
      }
    ],
    "payments": [
      {
        "uuid": "...",
        "amount_rials": 500000,
        "gateway": "mellat",
        "status": "paid",
        "created_at": 1717000000
      }
    ],
    "users": [
      {
        "uuid": "...",
        "real_name": "محمد رضایی",
        "mobile_number": "09...",
        "roles": ["ROLE_USER"],
        "created_at": 1717000000
      }
    ]
  }
}
```

---

## User Management

### GET `/api/v1/admin/users`

List all users with pagination and filters.

**Permission:** `ROLE_ADMIN`

### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `search` | string | ❌ | Search by name or mobile |
| `role` | string | ❌ | Filter: `ROLE_USER`, `ROLE_DOCTOR`, `ROLE_ADMIN`, etc. |
| `status` | string | ❌ | `"active"` or `"inactive"` |
| `sort` | string | ❌ | `"created_at"` (default desc) |

### Response `200`
```json
{
  "success": true,
  "data": [
    {
      "uuid": "...",
      "real_name": "علی احمدی",
      "mobile_number": "09123456789",
      "roles": ["ROLE_USER"],
      "status": "active",
      "created_at": 1717000000
    }
  ],
  "meta": { "totalRecords": 1200, "totalPages": 60, "currentPage": 1 }
}
```

---

### GET `/api/v1/admin/users/{uuid}`

Get detailed user info.

**Permission:** `ROLE_ADMIN`

### Response `200`
```json
{
  "success": true,
  "data": {
    "uuid": "...",
    "real_name": "علی احمدی",
    "mobile_number": "09123456789",
    "roles": ["ROLE_USER"],
    "status": "active",
    "wallet_balance_rials": 500000,
    "appointments_count": 5,
    "created_at": 1717000000
  }
}
```

### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_NOT_FOUND_001` | 404 | User not found |

---

### GET `/api/v1/admin/users/stats`

Get user statistics.

**Permission:** `ROLE_ADMIN`

### Response `200`
```json
{
  "success": true,
  "data": {
    "total": 1200,
    "active": 1150,
    "inactive": 50,
    "admins": 3,
    "doctors": 92,
    "patients": 1100
  }
}
```

---

### PUT `/api/v1/admin/users/{uuid}`

Update user info (name, email, password).

**Permission:** `ROLE_ADMIN`

### Request Body (`application/json`)
```json
{
  "real_name": "علی احمدی جدید",
  "password": "newPassword123"
}
```

### Response `200`
Updated user object.

---

### PUT `/api/v1/admin/users/{uuid}/role`

Change a user's role.

**Permission:** `ROLE_ADMIN`

### Request Body (`application/json`)
```json
{
  "role": "ROLE_DOCTOR"
}
```

| Field | Type | Required | Allowed Values |
|-------|------|----------|----------------|
| `role` | string | ✅ | `ROLE_USER`, `ROLE_DOCTOR`, `ROLE_CLINIC`, `ROLE_SECRETARY`, `ROLE_ADMIN` |

### Response `200`
```json
{ "success": true, "data": { "message": "نقش کاربر تغییر کرد", "roles": ["ROLE_DOCTOR"] } }
```

---

### POST `/api/v1/admin/users/{uuid}/status`

Toggle user active/inactive status.

**Permission:** `ROLE_ADMIN`

### Response `200`
```json
{ "success": true, "data": { "status": "inactive" } }
```

---

### DELETE `/api/v1/admin/users/{uuid}`

Delete a user.

**Permission:** `ROLE_ADMIN`

### Response `200`
```json
{ "success": true, "data": { "message": "کاربر حذف شد" } }
```

### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_NOT_FOUND_001` | 404 | User not found |

---

## Doctor Management

### GET `/api/v1/admin/doctors`

List all doctors with pagination.

**Permission:** `ROLE_ADMIN`

### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `search` | string | ❌ | Search in title |
| `status` | string | ❌ | `"active"` or `"inactive"` |
| `gender` | string | ❌ | `"male"` or `"female"` |
| `specialty_id` | integer | ❌ | Filter by specialty |
| `sort` | string | ❌ | Sort field |

### Response `200`
```json
{
  "success": true,
  "data": [
    {
      "uuid": "...",
      "title": "دکتر علی احمدی",
      "degree": "متخصص",
      "gender": "male",
      "doctor_rate": 4.5,
      "active_doctor_appointment": true
    }
  ],
  "meta": { "totalRecords": 92, "totalPages": 5, "currentPage": 1 }
}
```

---

### GET `/api/v1/admin/doctors/stats`

Get doctor statistics.

**Permission:** `ROLE_ADMIN`

### Response `200`
```json
{
  "success": true,
  "data": {
    "total": 92,
    "active": 85,
    "inactive": 7,
    "male": 60,
    "female": 32,
    "top_specialty": "قلب و عروق"
  }
}
```

---

### POST `/api/v1/admin/doctors/{uuid}/status`

Toggle doctor active status.

**Permission:** `ROLE_ADMIN`

### Response `200`
```json
{ "success": true, "data": { "active": false } }
```

---

## Clinic Management

### GET `/api/v1/admin/clinics`

List all clinics with pagination.

**Permission:** `ROLE_ADMIN`

### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `search` | string | ❌ | Search by clinic name |
| `status` | string | ❌ | `"active"` or `"inactive"` |

### Response `200`
```json
{
  "success": true,
  "data": [
    {
      "uuid": "...",
      "name": "کلینیک الوند",
      "city": "تهران",
      "telephone": "02112345678",
      "is_active": true,
      "created_at": 1717000000
    }
  ],
  "meta": { "totalRecords": 34, "totalPages": 2, "currentPage": 1 }
}
```

---

### PATCH `/api/v1/admin/clinic/{uuid}/status`

Toggle clinic active/inactive.

**Permission:** `ROLE_ADMIN`

### Response `200`
```json
{ "success": true, "data": { "is_active": false } }
```

### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_NOT_FOUND_001` | 404 | Clinic not found |

---

### DELETE `/api/v1/admin/clinic/{uuid}`

Delete a clinic.

**Permission:** `ROLE_ADMIN`

### Response `200`
```json
{ "success": true, "data": { "message": "کلینیک حذف شد" } }
```

---

## Appointment Management

### GET `/api/v1/admin/appointments/today-stats`

Get appointment statistics for a specific date (defaults to today).

**Permission:** `ROLE_ADMIN`

### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `date` | string (YYYY-MM-DD) | ❌ | Default: today |

### Response `200`
```json
{
  "success": true,
  "data": {
    "total": 47,
    "completed": 20,
    "waiting": 18,
    "cancelled": 9
  }
}
```

---

### GET `/api/v1/admin/appointments`

List appointments filtered by date and/or doctor. Sorted by `slot_start ASC`.

**Permission:** `ROLE_ADMIN`

### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 15, max: 500 |
| `search` | string | ❌ | Search by patient name/mobile or doctor name |
| `status` | string | ❌ | Filter by status |
| `date` | string (YYYY-MM-DD) | ❌ | Filter by slot date |
| `doctor_uuid` | string | ❌ | Filter by doctor UUID |

### Response `200`
```json
{
  "success": true,
  "data": [
    {
      "uuid": "appt-uuid",
      "patient_name": "محمد رضایی",
      "patient_mobile": "09123456789",
      "doctor_uuid": "doctor-uuid",
      "doctor_name": "دکتر علی احمدی",
      "slot_start": 1718438400,
      "slot_end": 1718439600,
      "appointment_date": "2025-06-15",
      "appointment_time": "09:00",
      "end_time": "09:20",
      "status": "confirmed",
      "version": 1,
      "created_at": "2025-06-14T10:30:00+03:30"
    }
  ],
  "meta": { "totalRecords": 47, "totalPages": 1, "currentPage": 1 }
}
```

**Status values:** `pending` | `confirmed` | `completed` | `cancelled_by_doctor` | `cancelled_by_user` | `no_show` | `expired`

---

### POST `/api/v1/admin/appointment`

Create a new appointment for a patient. If no user exists with the given mobile, a new user account is created automatically.

**Permission:** `ROLE_ADMIN`

### Request Body
```json
{
  "doctor_uuid": "doctor-uuid",
  "slot_start": 1718438400,
  "slot_end": 1718439600,
  "patient_mobile": "09123456789",
  "patient_name": "علی محمدی",
  "note": "optional note"
}
```

> `patient_mobile` و `patient_name` هر دو اجباری هستند. اگر کاربری با این شماره موبایل نداشته باشیم، یک کاربر جدید با نقش `ROLE_USER` ساخته می‌شود.

### Response `201`
```json
{
  "success": true,
  "data": {
    "uuid": "appt-uuid",
    "slot_start": 1718438400,
    "slot_end": 1718439600,
    "status": "pending"
  }
}
```

### Error Responses
| Code | HTTP | Description |
|------|------|-------------|
| `VALIDATION` | 422 | Missing required fields (doctor_uuid, slot_start, slot_end, patient_mobile, patient_name) |
| `DOCTOR_NOT_FOUND` | 404 | Doctor UUID not found |
| `SLOT_TAKEN` | 409 | Slot already booked |

---

## Payment Management

### GET `/api/v1/admin/payments`

List all payments.

**Permission:** `ROLE_ADMIN`

### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `status` | string | ❌ | `"pending"`, `"paid"`, `"failed"`, `"cancelled"` |

### Response `200`
```json
{
  "success": true,
  "data": [
    {
      "uuid": "...",
      "order_id": "CLINICPRO-...",
      "amount_rials": 500000,
      "status": "paid",
      "gateway": "mellat",
      "created_at": 1717000000
    }
  ],
  "meta": { "totalRecords": 7800, "totalPages": 390, "currentPage": 1 }
}
```

---

## Settlement Management

### GET `/api/v1/admin/settlements`

List all settlement requests.

**Permission:** `ROLE_ADMIN`

### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `status` | string | ❌ | `"pending"`, `"approved"`, `"rejected"` |

### Response `200`
```json
{
  "success": true,
  "data": [
    {
      "uuid": "...",
      "user": { "uuid": "...", "real_name": "دکتر علی احمدی" },
      "amount_rials": 1000000,
      "status": "pending",
      "bank_account": { "bank_name": "بانک ملت", "owner_name": "..." },
      "created_at": 1717000000
    }
  ],
  "meta": { "totalRecords": 45, "totalPages": 3, "currentPage": 1 }
}
```

> To approve or reject, use the Settlement API: `POST /api/v1/settlement/{uuid}/approve` or `/reject`

---

## Representation Management

### GET `/api/v1/admin/representations`

List all representations.

**Permission:** `ROLE_ADMIN`

### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `search` | string | ❌ | Search by name |
| `city_id` | integer | ❌ | Filter by city |

### Response `200`
Paginated representation list.

---

## Secretary Management

### GET `/api/v1/admin/secretaries`

List all secretaries.

**Permission:** `ROLE_ADMIN`

### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `search` | string | ❌ | Search by mobile |

### Response `200`
Paginated secretary list with linked doctor info.

---

## Rating & Comment Management

### GET `/api/v1/admin/rates`

List all ratings.

**Permission:** `ROLE_ADMIN`

### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `search` | string | ❌ | Search by doctor/patient |

---

### GET `/api/v1/admin/comments`

List all comments (all statuses).

**Permission:** `ROLE_ADMIN`

### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |
| `search` | string | ❌ | Search in body |
| `status` | string | ❌ | `"pending"`, `"approved"`, `"rejected"` |

> To approve/reject comments, use the Rating API: `POST /api/v1/admin/comment/{uuid}/approve` or `/reject`

---

## SMS Management (Admin)

### GET `/api/v1/admin/sms/logs`

List SMS send logs.

**Permission:** `ROLE_ADMIN`

### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `page` | integer | ❌ | Default: 1 |
| `limit` | integer | ❌ | Default: 20 |

### Response `200`
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "mobile": "09123456789",
      "message": "کد تأیید: 123456",
      "provider": "kavenegar",
      "success": true,
      "created_at": 1717000000
    }
  ],
  "meta": { "totalRecords": 5000, "totalPages": 250, "currentPage": 1 }
}
```

---

### GET `/api/v1/admin/sms/templates`

List all SMS templates.

**Permission:** `ROLE_ADMIN`

### Response `200`
```json
{
  "success": true,
  "data": [
    {
      "uuid": "...",
      "name": "تأیید نوبت",
      "status": "approved",
      "provider_code": "verify_appointment",
      "created_at": 1717000000
    }
  ]
}
```

> To create/approve/reject templates, see [sms.md](sms.md)

---

## Clinic Invitation Management

> See [clinic-invitation.md](clinic-invitation.md) for full endpoint details.

| Endpoint | Description |
|----------|-------------|
| `POST /api/v1/admin/clinic/{uuid}/invite-doctor` | Send invitation |
| `GET /api/v1/admin/clinic/{uuid}/invitations` | List invitations |
| `POST /api/v1/admin/clinic/invitation/{invUuid}/resend` | Resend SMS |
| `PATCH /api/v1/admin/clinic/invitation/{invUuid}/status` | Change status |
| `DELETE /api/v1/admin/clinic/invitation/{invUuid}` | Delete |

---

## Settings

### GET /api/v1/admin/settings

Returns all site configuration values.

**Response `200`**
```json
{
  "success": true,
  "data": {
    "commission_enabled": "0",
    "commission_percent": "0",
    "site_name": "ClinicPro",
    "support_phone": "",
    "max_cancel_hours_before": "24",
    "appointment_reminder_hours": "2",
    "payment_test_mode": "0",
    "mellat_terminal_id": "",
    "mellat_username": "",
    "mellat_password": "",
    "sep_terminal_id": "",
    "sms_provider": "kavenegar",
    "kavenegar_api_key": "",
    "kavenegar_sender": "",
    "sms_price_rials": "500"
  }
}
```

All values are strings. Missing keys return their default values.

### PATCH /api/v1/admin/settings

Update one or more settings. Unknown keys are silently ignored.

**Request body** (partial update — send only keys to change):
```json
{
  "commission_enabled": "1",
  "commission_percent": "5",
  "site_name": "کلینیک‌پرو",
  "payment_test_mode": "1",
  "mellat_terminal_id": "12345678",
  "mellat_username": "user",
  "mellat_password": "pass",
  "sep_terminal_id": "87654321",
  "sms_provider": "kavenegar",
  "kavenegar_api_key": "your-api-key",
  "kavenegar_sender": "10008664",
  "sms_price_rials": "500"
}
```

**Response `200`** — same shape as GET, returns all settings after save.

**Commission rules:**
- `commission_enabled` — `"1"` = active, `"0"` = inactive
- `commission_percent` — integer string, `0`–`100`
- Commission applies only to regular users (`booked_by = user`); secretaries are exempt

**Payment gateway rules:**
- `payment_test_mode` — `"1"` = all payments use MockGateway (no real bank calls), `"0"` = real gateways
- Gateway credentials (mellat/sep) read from DB first, fallback to env vars if DB value is empty
- MockGateway callback: same URL pattern + `&mock=1&ResCode=0&RefId=MOCK-{orderId}`

**SMS provider rules:**
- `sms_provider` — `"kavenegar"` or `"rangineh"`
- Kavenegar API key and sender read from DB first, fallback to env vars `KAVENEGAR_API_KEY`, `KAVENEGAR_SENDER`

---

## Pre-Registration Management

### GET `/api/v1/admin/pre-registrations`

List pre-registration requests. **Permission:** `ROLE_ADMIN`

**Query params:**

| Param | Default | Notes |
|-------|---------|-------|
| `page` | 1 | |
| `limit` | 20 | max 50 |
| `status` | `pending` | `pending` \| `approved` \| `rejected` \| `all` |

**Response `200`** (paginated):
```json
{
  "success": true,
  "data": [
    {
      "uuid": "...",
      "type": "independent_doctor",
      "name": "دکتر احمدی",
      "mobile": "09121234567",
      "info": "متخصص داخلی",
      "status": "pending",
      "admin_note": null,
      "created_at": 1718000000
    }
  ],
  "meta": { "totalRecords": 5, "totalPages": 1, "currentPage": 1 }
}
```

---

### POST `/api/v1/admin/pre-registrations/{uuid}/approve`

Approve a pending request. Creates User + Doctor/Clinic entity based on `type`, resets password, sends SMS. **Permission:** `ROLE_ADMIN`

**Response `200`:**
```json
{ "success": true, "data": { "message": "تأیید شد و اطلاعات ورود ارسال گردید" } }
```

**Error Codes:**

| Code | HTTP | Meaning |
|------|------|---------|
| `NOT_FOUND` | 404 | UUID not found |
| `ALREADY_PROCESSED` | 409 | Status is not pending |

---

### POST `/api/v1/admin/pre-registrations/{uuid}/reject`

Reject a pending request. **Permission:** `ROLE_ADMIN`

**Request body** (optional):
```json
{ "note": "مدارک ناقص است" }
```

**Response `200`:**
```json
{ "success": true, "data": { "message": "درخواست رد شد" } }
```
