# Tag API

> **Prefix:** `/api/v1/tags`, `/api/v1/admin/tag`

Tags are used for categorizing blog posts.

---

## GET `/api/v1/tags`

List all active tags.

**Permission:** `PUBLIC`

### Response `200`
```json
{
  "success": true,
  "data": [
    { "id": 1, "name": "دیابت", "slug": "diabat", "status": "active" },
    { "id": 2, "name": "قلب", "slug": "ghalb", "status": "active" }
  ]
}
```

---

## GET `/api/v1/admin/tags`

List all tags 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": 10, "totalPages": 1, "currentPage": 1 }
}
```

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

---

## POST `/api/v1/admin/tag`

Create a new tag.

**Permission:** `ROLE_ADMIN`

### Request Body (`application/json`)
```json
{
  "name": "دیابت",
  "slug": "diabat",
  "status": "active"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | ✅ | Tag name |
| `slug` | string | ❌ | Auto-generated from name if omitted |
| `status` | string | ❌ | `"active"` (default) or `"inactive"` |

### Response `201`
Tag 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/tag/{id}`

Update a tag.

**Permission:** `ROLE_ADMIN`

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

All fields optional.

### Response `200`
Updated tag object.

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

---

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

Delete a tag.

**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 | Tag 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.

---

## برچسب‌های Tenant (doctor/clinic)

برچسب‌های اختصاصیِ هر tenant با رنگ نمایش — جدا از taxonomy سراسری بالا. همه به entity کاربر (`doctor`/`clinic`) scope می‌شوند؛ هر tenant فقط برچسب‌های خودش را می‌بیند/تغییر می‌دهد.

**Permission:** `IS_AUTHENTICATED_FULLY` (doctor/clinic/secretary)

### GET `/api/v1/tenant-tags`
لیست برچسب‌های tenant جاری. Response: `{ success, data: [{ uuid, name, color, active }] }`

### POST `/api/v1/tenant-tag`
```json
{ "name": "فوری", "color": "#FF0000" }
```
| Field | Type | Required | Validation |
|-------|------|----------|------------|
| `name` | string | ✅ | غیرخالی، حداکثر ۶۰ |
| `color` | string | ❌ | هگز `#RRGGBB` یا `#RRGGBBAA` (پیش‌فرض `#5559CE`) |

Response `201`: TenantTag object.

### PATCH `/api/v1/tenant-tag/{uuid}`
فیلدهای اختیاری `name` / `color` / `active`. فقط مالک؛ در غیر این صورت `404`.

### DELETE `/api/v1/tenant-tag/{uuid}`
حذف برچسب. فقط مالک؛ در غیر این صورت `404`.

### Errors
| HTTP | Code | field | Description |
|------|------|-------|-------------|
| 422 | `ERR_VALIDATION_001` | `name` | نام خالی |
| 422 | `ERR_VALIDATION_001` | `color` | رنگ نامعتبر |
| 404 | `ERR_NOT_FOUND_001` | — | برچسب یافت نشد یا متعلق به tenant دیگر |
| 403 | `ERR_FORBIDDEN_001` | — | پروفایل tenant یافت نشد |
