# Specialty API

> **Prefix:** `/api/v1/specialties`, `/api/v1/admin/specialty`

---

## GET `/api/v1/specialties`

List all medical specialties.

**Permission:** `PUBLIC`

### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `parent_id` | integer | ❌ | Filter to sub-specialties of a parent |

### Response `200`
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "name": "قلب و عروق",
      "slug": "ghalb-va-oroug",
      "parent_id": null,
      "status": "active",
      "weight": 10
    },
    {
      "id": 5,
      "name": "فوق تخصص قلب",
      "slug": "fowgh-takhassos-ghalb",
      "parent_id": 1,
      "status": "active",
      "weight": 5
    }
  ]
}
```

---

## GET `/api/v1/specialties/doctor-counts`

List active specialties together with the number of doctors in each — optionally scoped to a city. Used by the public `/specialties` page to show «N پزشک» under each specialty.

**Permission:** `PUBLIC`

### Query Parameters
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `city_id` | integer | ❌ | Count only doctors in this city (the `categories.id` of the city). Omit for a global count. |

### Response `200`
```json
{
  "success": true,
  "data": [
    {
      "id": 2,
      "name": "داخلی عمومی",
      "slug": "...",
      "parent_id": null,
      "status": "active",
      "weight": 10,
      "number_of_doctors": 10
    }
  ]
}
```
- Returns **all** active specialties; those with no doctors have `number_of_doctors: 0`.
- `number_of_doctors` counts distinct doctors joined through `doctor_specialties` (and `doctor_cities` when `city_id` is given), matching the public `GET /api/v1/doctors?specialty_id=&city_id=` filter.

---

## GET `/api/v1/admin/specialties`

List all specialties with pagination (admin view — includes inactive).

**Permission:** `ROLE_ADMIN`

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

### Response `200`
```json
{
  "success": true,
  "data": [ ... ],
  "meta": { "totalRecords": 50, "totalPages": 3, "currentPage": 1 }
}
```

### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_AUTH_001` | 401 | Missing token |
| `ERR_AUTH_006` | 403 | Not admin |

---

## POST `/api/v1/admin/specialty`

Create a new specialty.

**Permission:** `ROLE_ADMIN`

### Request Body (`application/json`)
```json
{
  "name": "قلب و عروق",
  "slug": "ghalb-va-oroug",
  "parent_id": null,
  "status": "active",
  "weight": 10
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | ✅ | Specialty name |
| `slug` | string | ❌ | Auto-generated from name if omitted |
| `parent_id` | integer | ❌ | Parent specialty ID (for sub-specialties) |
| `status` | string | ❌ | `"active"` (default) or `"inactive"` |
| `weight` | integer | ❌ | Sort weight |

### Response `201`
Specialty object.

### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_AUTH_001` | 401 | Missing token |
| `ERR_AUTH_006` | 403 | Not admin |
| `ERR_VALIDATION_002` | 422 | Missing name |

---

## PATCH `/api/v1/admin/specialty/{id}`

Update a specialty.

**Permission:** `ROLE_ADMIN`

### Path Parameters
| Param | Type | Description |
|-------|------|-------------|
| `id` | integer | Specialty ID |

### Request Body (all optional)
```json
{
  "name": "قلب و عروق ویرایش‌شده",
  "status": "inactive",
  "weight": 20,
  "parent_id": null,
  "slug": "new-slug"
}
```

### Response `200`
Updated specialty object.

### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_AUTH_001` | 401 | Missing token |
| `ERR_AUTH_006` | 403 | Not admin |
| `ERR_NOT_FOUND_001` | 404 | Specialty not found |

---

## DELETE `/api/v1/admin/specialty/{id}`

Delete a specialty.

**Permission:** `ROLE_ADMIN`

### Response `200`
```json
{ "success": true, "data": { "message": "تخصص حذف شد" } }
```

### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_AUTH_001` | 401 | Missing token |
| `ERR_AUTH_006` | 403 | Not admin |
| `ERR_NOT_FOUND_001` | 404 | Specialty not found |

---

## Bulk import / export

Full-table JSON export and strict wipe+replace import for this category live under
`/api/v1/admin/categories/{bundle}/{export|import}` — see [category-import.md](category-import.md).


### Sorting by id

The admin list endpoint accepts `sort=id&order=asc|desc` to order by `id`
(used by the admin «دسته‌بندی‌ها» page when clicking the «شناسه» column).
Without `sort`, the default ordering (weight/name) is unchanged.
