# Blog API

> **Prefix:** `/api/v1/blog`, `/api/v1/blogs`

---

## GET `/api/v1/blogs`

List published blog posts.

**Permission:** `PUBLIC`

### Query Parameters
| Param | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `page` | integer | ❌ | 1 | Page number |
| `limit` | integer | ❌ | 20 | Items per page |
| `tag` | string | ❌ | — | Filter by exact tag **name** (e.g. `?tag=دیابت`). Blog tags are stored as a JSON array of names; only blogs whose `tags` array contains this exact name are returned. |

### Response `200`
```json
{
  "success": true,
  "data": [
    {
      "uuid": "...",
      "title": "آشنایی با بیماری دیابت",
      "slug": "ashnayi-ba-bimari-diabat",
      "summary": "خلاصه مطلب...",
      "image": "https://...",
      "author": { "uuid": "...", "real_name": "دکتر احمدی" },
      "tags": [{ "id": 1, "name": "دیابت" }],
      "status": "published",
      "created_at": 1717000000
    }
  ],
  "meta": {
    "totalRecords": 25,
    "totalPages": 2,
    "currentPage": 1
  }
}
```

---

## GET `/api/v1/blog/{slug}`

Get a single blog post by slug.

**Permission:** `PUBLIC`

### Path Parameters
| Param | Type | Description |
|-------|------|-------------|
| `slug` | string | URL slug (e.g. `ashnayi-ba-bimari-diabat`) |

### Response `200`
```json
{
  "success": true,
  "data": {
    "uuid": "...",
    "title": "آشنایی با بیماری دیابت",
    "slug": "ashnayi-ba-bimari-diabat",
    "summary": "خلاصه...",
    "body": "<p>محتوای کامل...</p>",
    "image": "https://...",
    "author": { "uuid": "...", "real_name": "دکتر احمدی" },
    "tags": [{ "id": 1, "name": "دیابت" }],
    "status": "published",
    "created_at": 1717000000,
    "updated_at": 1717100000
  }
}
```

### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_NOT_FOUND_001` | 404 | Blog not found or not published |

---

## POST `/api/v1/blog`

Create a new blog post.

**Permission:** `ROLE_ADMIN`

### Request Body (`application/json`)
```json
{
  "title": "آشنایی با بیماری دیابت",
  "body": "<p>محتوای کامل مقاله...</p>",
  "summary": "خلاصه کوتاه از مقاله",
  "tags": [1, 2],
  "status": "draft",
  "image_url": "/uploads/blogs/blog_abc.jpg"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `title` | string | ✅ | Post title (slug auto-generated) |
| `body` | string | ✅ | Full HTML body (from the admin CKEditor) |
| `summary` | string | ❌ | Short excerpt |
| `tags` | integer[] | ❌ | Array of tag IDs |
| `status` | string | ❌ | `"draft"` (default) or `"published"` |
| `image_url` | string | ❌ | Cover image path returned by the upload endpoint |

### Response `201`
```json
{
  "success": true,
  "data": {
    "uuid": "blog-uuid-...",
    "title": "آشنایی با بیماری دیابت",
    "slug": "ashnayi-ba-bimari-diabat",
    "summary": "...",
    "body": "...",
    "image": null,
    "tags": [],
    "status": "draft",
    "created_at": 1717000000
  }
}
```

**Blog Status Values:**
| Value | Description |
|-------|-------------|
| `draft` | Not visible to public |
| `published` | Visible in public listing |
| `archived` | Hidden from listing |

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

---

## PATCH `/api/v1/blog/{uuid}`

Update a blog post.

**Permission:** `ROLE_ADMIN`

### Path Parameters
| Param | Type | Description |
|-------|------|-------------|
| `uuid` | string (UUID) | Blog UUID |

### Request Body (`application/json`)
```json
{
  "title": "عنوان جدید",
  "body": "<p>محتوای جدید</p>",
  "summary": "خلاصه جدید",
  "tags": [1, 3],
  "status": "published",
  "image_url": "/uploads/blogs/blog_abc.jpg"
}
```

All fields optional. Send `image_url: ""` to clear the cover image.

### Response `200`
Updated blog object.

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

---

## DELETE `/api/v1/blog/{uuid}`

Delete a blog post.

**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 | Blog not found |

---

## POST `/file/upload/clinic_pro/blog/field_image`

Upload blog post header image.

**Permission:** `ROLE_ADMIN`

### Request
`Content-Type: multipart/form-data`

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `file` | binary | ✅ | Image (max 5MB) |
| `blog_uuid` | string (UUID) | ❌ | Auto-associate with blog post |

### Response `200`
```json
{
  "success": true,
  "data": {
    "url": "https://clinic-pro.ddev.site/uploads/blog/post_abc.jpg",
    "uuid": "...",
    "filename": "post_abc.jpg",
    "filemime": "image/jpeg",
    "filesize": 204800
  }
}
```

### Errors
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_AUTH_001` | 401 | Missing token |
| `ERR_AUTH_006` | 403 | Not admin |
| `ERR_FILE_001` | 422 | Invalid file type |
