{
    "openapi": "3.0.3",
    "info": {
        "title": "Blogware RESTful API",
        "description": "RESTful API for Blogware content management system.\n\nThis API provides programmatic access to blog posts, categories, comments, and archives.\nIt follows OpenAPI 3.0 specification and supports both public and authenticated operations.\n\n## Authentication\n\nThe API supports three authentication methods:\n- **API Key**: Pass your API key in the `X-API-Key` header\n- **Bearer Token**: Pass a bearer token in the `Authorization` header\n- **Session/Cookie**: Admin panel session (used by `POST /media/upload`)\n\nExample:\n```\nX-API-Key: your-api-key-here\n```\nor\n```\nAuthorization: Bearer your-token-here\n```\n\nSession-authenticated write requests (cookie, no API key/Bearer header)\nmust include the CSRF token from `GET /csrf-token` as the\n`X-CSRF-Token` header. Requests authenticated with an API key or\nBearer token are exempt.\n\nWrite requests (`POST`/`PUT`/`PATCH`/`DELETE`) must send\n`Content-Type: application/json` (form-encoded is also accepted);\nany other content type returns `415 Unsupported Media Type`.\n`POST /media/upload` is the multipart/form-data exception.\n\n## Rate Limiting\n\nAPI requests are rate limited to ensure fair usage and prevent abuse:\n\n| Endpoint Type | Limit | Window |\n|--------------|-------|--------|\n| **Read (GET)** | 60 requests | 60 seconds |\n| **Write (POST/PUT/DELETE/PATCH)** | 20 requests | 60 seconds |\n\nRate limits are tracked per client using API key, Bearer token, or IP address.\n\nThe following headers are included in all responses:\n- `X-RateLimit-Limit`: Maximum requests allowed per window\n- `X-RateLimit-Remaining`: Remaining requests in current window\n- `X-RateLimit-Reset`: Unix timestamp when the rate limit resets\n- `Retry-After`: Seconds to wait before retrying (only on 429 responses)\n\nExceeding the rate limit returns `429 Too Many Requests`.\n\nThe search endpoints (`GET /search`, `/search/posts`, `/search/pages`)\napply an additional endpoint-local limit of 30 requests per minute.\n`QUERY` requests are counted under the read limit.\n\n## QUERY Method (RFC 10008)\n\n`QUERY /query`, `QUERY /query/posts` and `QUERY /query/pages` accept a\nJSON request body (`{\"q\": \"keyword\", \"type\": \"all|posts|pages\"}`) instead\nof URI query parameters. QUERY is safe and idempotent like GET, so it\nis rate-limited as a read. OpenAPI 3.0 has no `query` operation type,\nso these paths are documented under the `x-query` extension field\nbelow with an identical operation shape.\n\n## HATEOAS (Hypermedia as the Engine of Application State)\n\nAll API responses include HATEOAS links following [RFC 5988 (Web Linking)](https://tools.ietf.org/html/rfc5988).\nEach response contains a `_links` object with discoverable navigation:\n\n```json\n{\n  \"success\": true,\n  \"status\": 200,\n  \"data\": { ... },\n  \"_links\": {\n    \"self\": { \"href\": \"...\", \"rel\": \"self\", \"type\": \"GET\" },\n    \"collection\": { \"href\": \"...\", \"rel\": \"collection\", \"type\": \"GET\" }\n  }\n}\n```\n\nCommon link relations: `self`, `collection`, `first`, `prev`, `next`, `last`, `canonical`, `comments`, `post`, `posts`, `year`, `search`, `service-desc`.\n\n## Caching and Conditional Requests\n\nGET responses are cacheable with ETag and Last-Modified headers:\n- **ETag**: Entity tag for cache validation\n- **Last-Modified**: Timestamp of last resource modification\n- **If-None-Match**: Client sends cached ETag to check for changes\n- **If-Modified-Since**: Client sends cached timestamp\n- **304 Not Modified**: Response when resource hasn't changed\n\nCache-Control headers vary by HTTP method:\n- **GET**: `public, max-age=300` (cacheable for 5 minutes)\n- **POST/PUT/DELETE/PATCH**: `no-store` (never cache)\n- **4xx errors**: `no-cache, no-store, must-revalidate`\n\n## Content Negotiation\n\nThe API supports `Accept` header validation. Requests with unsupported media types receive `406 Not Acceptable`. Currently only `application/json` is supported.\n\n## Response Format\n\nAll responses are returned in JSON format with the following structure:\n\n### Success Response\n```json\n{\n  \"success\": true,\n  \"status\": 200,\n  \"message\": \"Operation description\",\n  \"data\": { ... }\n}\n```\n\n### Paginated Response\n```json\n{\n  \"success\": true,\n  \"status\": 200,\n  \"data\": [...],\n  \"pagination\": {\n    \"current_page\": 1,\n    \"per_page\": 10,\n    \"total_items\": 50,\n    \"total_pages\": 5,\n    \"has_next_page\": true,\n    \"has_previous_page\": false\n  }\n}\n```\n\n### Error Response\n```json\n{\n  \"success\": false,\n  \"status\": 400,\n  \"error\": {\n    \"code\": \"BAD_REQUEST\",\n    \"message\": \"Error description\"\n  }\n}\n```\n\n## Filtering and Sorting\n\nQuery parameters for filtering and sorting:\n- `page`: Page number (default: 1)\n- `per_page`: Items per page (default: 10, max: 100)\n- `sort_by`: Field to sort by\n- `sort_order`: Sort direction (ASC or DESC)\n\n## CORS and Preflight\n\nEvery path answers `OPTIONS` with an `Allow` header listing the\nmethods registered for that path plus `OPTIONS` itself\n(`204 No Content`, empty body).\n",
        "version": "1.1.2",
        "contact": {
            "name": "Blogware Support",
            "email": "alanmoehammad@gmail.com"
        },
        "license": {
            "name": "MIT",
            "url": "https://opensource.org/licenses/MIT"
        },
        "x-logo": {
            "url": "https://blogware.site/public/files/pictures/scriptlog-1200x630.jpg"
        }
    },
    "servers": [
        {
            "url": "/api/v1",
            "description": "Relative to the host serving this specification. The spec itself is served from /api/v1/openapi.json, so this resolves correctly on any install with no URL substitution needed. Human-readable examples elsewhere in this document use http://blogware.site as the example host."
        }
    ],
    "tags": [
        {
            "name": "Posts",
            "description": "Blog posts operations"
        },
        {
            "name": "Categories",
            "description": "Category/topic operations"
        },
        {
            "name": "Comments",
            "description": "Comment operations"
        },
        {
            "name": "Archives",
            "description": "Archive by date operations"
        },
        {
            "name": "Search",
            "description": "Search operations"
        },
        {
            "name": "Query",
            "description": "RFC 10008 QUERY-method search operations (JSON body)"
        },
        {
            "name": "System",
            "description": "Health, OpenAPI spec and CSRF token operations"
        },
        {
            "name": "GDPR",
            "description": "GDPR consent operations"
        },
        {
            "name": "Languages",
            "description": "Internationalization languages"
        },
        {
            "name": "Translations",
            "description": "Internationalization translations"
        },
        {
            "name": "Media",
            "description": "Media upload operations"
        },
        {
            "name": "API Info",
            "description": "API information and metadata"
        }
    ],
    "paths": {
        "/": {
            "get": {
                "tags": [
                    "API Info"
                ],
                "summary": "Get API information",
                "description": "Returns API metadata, available endpoints, and usage information",
                "operationId": "getApiInfo",
                "responses": {
                    "200": {
                        "description": "API information retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiInfo"
                                }
                            }
                        }
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/posts": {
            "get": {
                "tags": [
                    "Posts"
                ],
                "summary": "List published posts",
                "description": "Retrieves a paginated list of published blog posts.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "listPosts",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/SortBy"
                    },
                    {
                        "$ref": "#/components/parameters/SortOrder"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Posts retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/PostListResponse"
                                }
                            }
                        }
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            },
            "post": {
                "tags": [
                    "Posts"
                ],
                "summary": "Create a new post",
                "description": "Creates a new blog post.\nRequires authentication with administrator, editor, or author permissions.\n",
                "operationId": "createPost",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/PostCreate"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Post created successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/PostResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/UnprocessableEntity"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            }
        },
        "/posts/{id}": {
            "get": {
                "tags": [
                    "Posts"
                ],
                "summary": "Get a single post",
                "description": "Retrieves a single blog post by its ID.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "getPost",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/PostId"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Post retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/PostDetailResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            },
            "put": {
                "tags": [
                    "Posts"
                ],
                "summary": "Update a post",
                "description": "Updates an existing blog post.\nRequires authentication with administrator or editor permissions.\n",
                "operationId": "updatePost",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/PostId"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/PostUpdate"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Post updated successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/PostResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Posts"
                ],
                "summary": "Delete a post",
                "description": "Deletes a blog post.\nRequires authentication with administrator permissions.\n",
                "operationId": "deletePost",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/PostId"
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Post deleted successfully (no content)"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Posts"
                ],
                "summary": "Partially update a post",
                "description": "Partially updates an existing blog post. Only send the fields you want to change.\nRequires authentication with administrator or editor permissions.\n",
                "operationId": "patchPost",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/PostId"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/PostUpdate"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Post updated successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/PostResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            }
        },
        "/posts/{id}/comments": {
            "get": {
                "tags": [
                    "Posts"
                ],
                "summary": "Get comments for a post",
                "description": "Retrieves approved comments for a specific blog post.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "getPostComments",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/PostId"
                    },
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Comments retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CommentListResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            }
        },
        "/posts/{id}/verify": {
            "post": {
                "tags": [
                    "Posts"
                ],
                "summary": "Verify protected post password",
                "description": "Verifies the password for a password-protected post without returning content.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "verifyProtectedPost",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/PostId"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ProtectedPostVerify"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Password verified successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ProtectedPostVerifyResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/posts/{id}/unlock": {
            "post": {
                "tags": [
                    "Posts"
                ],
                "summary": "Unlock protected post content",
                "description": "Verifies password and returns decrypted content for a password-protected post.\nThis endpoint is public and does not require authentication.\nRate limited to prevent brute force attacks.\n",
                "operationId": "unlockProtectedPost",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/PostId"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ProtectedPostVerify"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Post unlocked successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ProtectedPostUnlockResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/categories": {
            "get": {
                "tags": [
                    "Categories"
                ],
                "summary": "List all categories",
                "description": "Retrieves a paginated list of all categories/topics.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "listCategories",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/SortBy"
                    },
                    {
                        "$ref": "#/components/parameters/SortOrder"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Categories retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CategoryListResponse"
                                }
                            }
                        }
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            },
            "post": {
                "tags": [
                    "Categories"
                ],
                "summary": "Create a new category",
                "description": "Creates a new category/topic.\nRequires authentication with administrator or editor permissions.\n",
                "operationId": "createCategory",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/CategoryCreate"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Category created successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CategoryResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/UnprocessableEntity"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            }
        },
        "/categories/{id}": {
            "get": {
                "tags": [
                    "Categories"
                ],
                "summary": "Get a single category",
                "description": "Retrieves a single category/topic by its ID.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "getCategory",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/CategoryId"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Category retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CategoryResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            },
            "put": {
                "tags": [
                    "Categories"
                ],
                "summary": "Update a category",
                "description": "Updates an existing category/topic.\nRequires authentication with administrator or editor permissions.\n",
                "operationId": "updateCategory",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/CategoryId"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/CategoryUpdate"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Category updated successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CategoryResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Categories"
                ],
                "summary": "Delete a category",
                "description": "Deletes a category/topic.\nRequires authentication with administrator permissions.\n",
                "operationId": "deleteCategory",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/CategoryId"
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Category deleted successfully (no content)"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Categories"
                ],
                "summary": "Partially update a category",
                "description": "Partially updates an existing category/topic. Only send the fields you want to change.\nRequires authentication with administrator or editor permissions.\n",
                "operationId": "patchCategory",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/CategoryId"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/CategoryUpdate"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Category updated successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CategoryResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            }
        },
        "/categories/{id}/posts": {
            "get": {
                "tags": [
                    "Categories"
                ],
                "summary": "Get posts in a category",
                "description": "Retrieves posts belonging to a specific category.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "getCategoryPosts",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/CategoryId"
                    },
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/SortBy"
                    },
                    {
                        "$ref": "#/components/parameters/SortOrder"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Posts retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CategoryPostsResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            }
        },
        "/comments": {
            "get": {
                "tags": [
                    "Comments"
                ],
                "summary": "List all approved comments",
                "description": "Retrieves a paginated list of approved comments.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "listComments",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/SortBy"
                    },
                    {
                        "$ref": "#/components/parameters/SortOrder"
                    },
                    {
                        "name": "post_id",
                        "in": "query",
                        "description": "Filter comments by post ID",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "example": 1
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Comments retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CommentListResponse"
                                }
                            }
                        }
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            },
            "post": {
                "tags": [
                    "Comments"
                ],
                "summary": "Create a new comment",
                "description": "Creates a new comment on a blog post.\nThis endpoint is public and does not require authentication.\nComments are submitted with 'pending' status for moderation.\n",
                "operationId": "createComment",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/CommentCreate"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Comment created successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CommentResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/UnprocessableEntity"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            }
        },
        "/comments/{id}": {
            "get": {
                "tags": [
                    "Comments"
                ],
                "summary": "Get a single comment",
                "description": "Retrieves a single comment by its ID.\nThis endpoint is public for approved comments.\n",
                "operationId": "getComment",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/CommentId"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Comment retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CommentResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            },
            "put": {
                "tags": [
                    "Comments"
                ],
                "summary": "Update a comment",
                "description": "Updates an existing comment.\nRequires authentication with administrator or editor permissions.\n",
                "operationId": "updateComment",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/CommentId"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/CommentUpdate"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Comment updated successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CommentResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Comments"
                ],
                "summary": "Delete a comment",
                "description": "Deletes a comment.\nRequires authentication with administrator or editor permissions.\n",
                "operationId": "deleteComment",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/CommentId"
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Comment deleted successfully (no content)"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Comments"
                ],
                "summary": "Partially update a comment",
                "description": "Partially updates an existing comment. Only send the fields you want to change.\nRequires authentication with administrator or editor permissions.\n",
                "operationId": "patchComment",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/CommentId"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/CommentUpdate"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Comment updated successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CommentResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            }
        },
        "/archives": {
            "get": {
                "tags": [
                    "Archives"
                ],
                "summary": "List available archive dates",
                "description": "Returns a list of years and months that have published posts.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "listArchives",
                "responses": {
                    "200": {
                        "description": "Archives retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ArchiveListResponse"
                                }
                            }
                        }
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            }
        },
        "/archives/{year}": {
            "get": {
                "tags": [
                    "Archives"
                ],
                "summary": "Get posts from a specific year",
                "description": "Retrieves posts published in a specific year.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "getArchiveYear",
                "parameters": [
                    {
                        "name": "year",
                        "in": "path",
                        "description": "Year (e.g., 2024)",
                        "required": true,
                        "schema": {
                            "type": "integer",
                            "minimum": 1900,
                            "maximum": 2030,
                            "example": 2024
                        }
                    },
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/SortBy"
                    },
                    {
                        "$ref": "#/components/parameters/SortOrder"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Posts retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ArchiveYearResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            }
        },
        "/archives/{year}/{month}": {
            "get": {
                "tags": [
                    "Archives"
                ],
                "summary": "Get posts from a specific month",
                "description": "Retrieves posts published in a specific month and year.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "getArchiveMonth",
                "parameters": [
                    {
                        "name": "year",
                        "in": "path",
                        "description": "Year (e.g., 2024)",
                        "required": true,
                        "schema": {
                            "type": "integer",
                            "minimum": 1900,
                            "maximum": 2030,
                            "example": 2024
                        }
                    },
                    {
                        "name": "month",
                        "in": "path",
                        "description": "Month (1-12)",
                        "required": true,
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 12,
                            "example": 6
                        }
                    },
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/SortBy"
                    },
                    {
                        "$ref": "#/components/parameters/SortOrder"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Posts retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ArchiveMonthResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            }
        },
        "/search": {
            "get": {
                "tags": [
                    "Search"
                ],
                "summary": "Search all content",
                "description": "Searches posts and pages for the given keyword.\nThis endpoint is public and does not require authentication.\nThe keyword may also be passed as `keyword`. Minimum length is\n2 characters. A non-empty `search_verify` parameter (honeypot)\nis rejected with `403`. Besides the global read rate limit, an\nendpoint-local limit of 30 requests per minute applies (`429`).\n",
                "operationId": "searchAll",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "description": "Search keyword (alias `keyword`)",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "minLength": 2,
                            "maxLength": 100
                        }
                    },
                    {
                        "name": "type",
                        "in": "query",
                        "description": "Search scope",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all",
                                "posts",
                                "pages"
                            ],
                            "default": "all"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Search results retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SearchResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            }
        },
        "/search/posts": {
            "get": {
                "tags": [
                    "Search"
                ],
                "summary": "Search posts only",
                "description": "Searches only posts for the given keyword (`type` is forced to\n`posts` by the controller).\nThis endpoint is public and does not require authentication.\nSame honeypot (`403`) and endpoint-local rate limit (`429`) as\n`GET /search` apply.\n",
                "operationId": "searchPosts",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "description": "Search keyword",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "minLength": 2,
                            "maxLength": 100
                        }
                    },
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Search results retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SearchResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            }
        },
        "/search/pages": {
            "get": {
                "tags": [
                    "Search"
                ],
                "summary": "Search pages only",
                "description": "Searches only pages for the given keyword (`type` is forced to\n`pages` by the controller).\nThis endpoint is public and does not require authentication.\nSame honeypot (`403`) and endpoint-local rate limit (`429`) as\n`GET /search` apply.\n",
                "operationId": "searchPages",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "description": "Search keyword",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "minLength": 2,
                            "maxLength": 100
                        }
                    },
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Search results retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SearchResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            }
        },
        "/gdpr/consent": {
            "get": {
                "tags": [
                    "GDPR"
                ],
                "summary": "Get GDPR consent status",
                "description": "Retrieves the GDPR consent status for the calling client IP\naddress and the given consent type.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "getConsentStatus",
                "parameters": [
                    {
                        "name": "type",
                        "in": "query",
                        "description": "Consent type to check",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "default": "cookie",
                            "example": "cookie"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Consent status retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/GdprConsentResponse"
                                }
                            }
                        }
                    },
                    "405": {
                        "$ref": "#/components/responses/MethodNotAllowed"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            },
            "post": {
                "tags": [
                    "GDPR"
                ],
                "summary": "Submit GDPR consent",
                "description": "Records cookie consent (`accepted` or `rejected`) for the calling\nclient IP address together with its user agent.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "submitConsent",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/GdprConsent"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Consent submitted successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/GdprConsentResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "405": {
                        "$ref": "#/components/responses/MethodNotAllowed"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            }
        },
        "/languages": {
            "get": {
                "tags": [
                    "Languages"
                ],
                "summary": "List all languages",
                "description": "Retrieves a list of all available languages.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "listLanguages",
                "responses": {
                    "200": {
                        "description": "Languages retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/LanguageListResponse"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Languages"
                ],
                "summary": "Create a new language",
                "description": "Creates a new language for internationalization.\nRequires authentication with administrator permissions.\n",
                "operationId": "createLanguage",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/LanguageCreate"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Language created successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/LanguageResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/UnprocessableEntity"
                    }
                }
            }
        },
        "/languages/active": {
            "get": {
                "tags": [
                    "Languages"
                ],
                "summary": "List active languages",
                "description": "Retrieves only active languages.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "listActiveLanguages",
                "responses": {
                    "200": {
                        "description": "Active languages retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/LanguageListResponse"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/languages/{code}": {
            "get": {
                "tags": [
                    "Languages"
                ],
                "summary": "Get a single language",
                "description": "Retrieves a single language by its code.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "getLanguage",
                "parameters": [
                    {
                        "name": "code",
                        "in": "path",
                        "description": "Language code (e.g., en, ar, zh)",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "example": "en"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Language retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/LanguageResponse"
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "put": {
                "tags": [
                    "Languages"
                ],
                "summary": "Update a language",
                "description": "Updates an existing language.\nRequires authentication with administrator permissions.\n",
                "operationId": "updateLanguage",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "code",
                        "in": "path",
                        "description": "Language code (e.g., en, ar, zh)",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "example": "en"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/LanguageUpdate"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Language updated successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/LanguageResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Languages"
                ],
                "summary": "Partially update a language",
                "description": "Partially updates an existing language. Only send the fields you want to change.\nRequires authentication with administrator permissions.\n",
                "operationId": "patchLanguage",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "code",
                        "in": "path",
                        "description": "Language code (e.g., en, ar, zh)",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "example": "en"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/LanguageUpdate"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Language updated successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/LanguageResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Languages"
                ],
                "summary": "Delete a language",
                "description": "Deletes a language.\nRequires authentication with administrator permissions.\n",
                "operationId": "deleteLanguage",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "code",
                        "in": "path",
                        "description": "Language code (e.g., en, ar, zh)",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "example": "en"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Language deleted successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/DeleteResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/languages/default": {
            "get": {
                "tags": [
                    "Languages"
                ],
                "summary": "Get default language",
                "description": "Retrieves the default language.\nThis endpoint is public and does not require authentication.\nNOTE: this static path must be registered before `/languages/{code}`\nso that `default` is not mistaken for a language code.\n",
                "operationId": "getDefaultLanguage",
                "responses": {
                    "200": {
                        "description": "Default language retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/LanguageResponse"
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/languages/{code}/default": {
            "put": {
                "tags": [
                    "Languages"
                ],
                "summary": "Set default language",
                "description": "Sets the language identified by `{code}` as the default.\nRequires authentication with administrator permissions.\n",
                "operationId": "setDefaultLanguage",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "code",
                        "in": "path",
                        "description": "Language code (e.g., en, ar, zh)",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "example": "en"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Default language set successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/LanguageResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Languages"
                ],
                "summary": "Set default language (partial)",
                "description": "Alias of `PUT /languages/{code}/default`. Only send the fields you\nwant to change; the `{code}` language becomes the default.\nRequires authentication with administrator permissions.\n",
                "operationId": "patchDefaultLanguage",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "code",
                        "in": "path",
                        "description": "Language code (e.g., en, ar, zh)",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "example": "en"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Default language set successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/LanguageResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/translations/{code}": {
            "get": {
                "tags": [
                    "Translations"
                ],
                "summary": "List translations for a language",
                "description": "Retrieves translations for a specific language.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "listTranslations",
                "parameters": [
                    {
                        "name": "code",
                        "in": "path",
                        "description": "Language code (e.g., en, ar, zh)",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "example": "en"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Translations retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/TranslationListResponse"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Translations"
                ],
                "summary": "Create a translation",
                "description": "Creates a new translation entry.\nRequires authentication with administrator permissions.\n",
                "operationId": "createTranslation",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "code",
                        "in": "path",
                        "description": "Language code (e.g., en, ar, zh)",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "example": "en"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/TranslationCreate"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Translation created successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/TranslationResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/UnprocessableEntity"
                    }
                }
            }
        },
        "/translations/{code}/{key}": {
            "get": {
                "tags": [
                    "Translations"
                ],
                "summary": "Get a single translation",
                "description": "Retrieves a single translation by key.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "getTranslation",
                "parameters": [
                    {
                        "name": "code",
                        "in": "path",
                        "description": "Language code",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "example": "en"
                        }
                    },
                    {
                        "name": "key",
                        "in": "path",
                        "description": "Translation key",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "example": "nav.dashboard"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Translation retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/TranslationResponse"
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/translations/{id}": {
            "put": {
                "tags": [
                    "Translations"
                ],
                "summary": "Update a translation",
                "description": "Updates an existing translation by ID. The request body must\ninclude `translation_value`; `translation_context` and `is_html`\nare optional.\nRequires authentication with administrator permissions.\n",
                "operationId": "updateTranslation",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "description": "Translation ID",
                        "required": true,
                        "schema": {
                            "type": "integer",
                            "example": 1
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/TranslationUpdate"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Translation updated successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/TranslationResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Translations"
                ],
                "summary": "Partially update a translation",
                "description": "Partially updates an existing translation by ID. Only send the\nfields you want to change (`translation_value` is still required\nby the controller).\nRequires authentication with administrator permissions.\n",
                "operationId": "patchTranslation",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "description": "Translation ID",
                        "required": true,
                        "schema": {
                            "type": "integer",
                            "example": 1
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/TranslationUpdate"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Translation updated successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/TranslationResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Translations"
                ],
                "summary": "Delete a translation",
                "description": "Deletes a translation by ID. Returns `200` with a null data\npayload (not `204`).\nRequires authentication with administrator permissions.\n",
                "operationId": "deleteTranslation",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "description": "Translation ID",
                        "required": true,
                        "schema": {
                            "type": "integer",
                            "example": 1
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Translation deleted successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/DeleteResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/translations/{code}/export": {
            "get": {
                "tags": [
                    "Translations"
                ],
                "summary": "Export translations",
                "description": "Exports translations for a language as JSON.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "exportTranslations",
                "parameters": [
                    {
                        "name": "code",
                        "in": "path",
                        "description": "Language code (e.g., en, ar, zh)",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "example": "en"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Translations exported successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/translations/{code}/import": {
            "post": {
                "tags": [
                    "Translations"
                ],
                "summary": "Import translations",
                "description": "Imports translations from JSON.\nRequires authentication with administrator permissions.\n",
                "operationId": "importTranslations",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "code",
                        "in": "path",
                        "description": "Language code (e.g., en, ar, zh)",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "example": "en"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Translations imported successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SuccessResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                }
            }
        },
        "/translations/{code}/cache": {
            "post": {
                "tags": [
                    "Translations"
                ],
                "summary": "Regenerate translation cache",
                "description": "Regenerates the translation cache for a language.\nRequires authentication with administrator permissions.\n",
                "operationId": "regenerateCache",
                "security": [
                    {
                        "ApiKeyAuth": []
                    },
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "code",
                        "in": "path",
                        "description": "Language code (e.g., en, ar, zh)",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "example": "en"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Cache regenerated successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SuccessResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                }
            }
        },
        "/media/upload": {
            "post": {
                "tags": [
                    "Media"
                ],
                "summary": "Upload media file",
                "description": "Uploads an image file for use in posts (used by the Summernote\neditor). Authenticates via the admin panel session or the\n`scriptlog_auth` cookie — API keys and Bearer tokens are NOT\naccepted here. The caller level must be one of\n`administrator`, `manager`, `editor`, `author` or `contributor`,\nand session-authenticated callers must send the `X-CSRF-Token`\nheader. The real MIME type (not the extension) must be one of\nJPEG, PNG, GIF, WebP or BMP; maximum file size is 5 MB. An\noptional `post_id` links the image to a post via `tbl_mediameta`.\n",
                "operationId": "uploadMedia",
                "requestBody": {
                    "required": true,
                    "content": {
                        "multipart/form-data": {
                            "schema": {
                                "$ref": "#/components/schemas/MediaUpload"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Media uploaded successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/MediaUploadResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/UnprocessableEntity"
                    }
                }
            }
        },
        "/query": {
            "x-query": {
                "tags": [
                    "Query"
                ],
                "summary": "Query all content (QUERY method)",
                "description": "Executes a server-side query from a JSON request body, per\nRFC 10008. Send `{\"q\": \"keyword\"}` (`keyword` is accepted as an\nalias) with an optional `type` of `all` (default), `posts` or\n`pages`. Safe and idempotent like GET: cacheable, retryable, and\ncounted under the read rate limit. Responds with\n`Accept-Query: application/json`.\nNOTE: OpenAPI 3.0 defines no `query` operation type, so this\noperation is documented under the `x-query` extension field with\nan otherwise standard operation shape. The real HTTP method is\n`QUERY`, e.g. `curl -X QUERY /api/v1/query -d '{\"q\":\"php\"}'`.\n",
                "operationId": "queryAll",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/QueryRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Query executed successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/QueryResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/query/posts": {
            "x-query": {
                "tags": [
                    "Query"
                ],
                "summary": "Query posts only (QUERY method)",
                "description": "Like `QUERY /query` but restricted to blog posts (`type` is\nforced to `posts`). The real HTTP method is `QUERY`.\n",
                "operationId": "queryPosts",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/QueryRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Post query executed successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/QueryResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/query/pages": {
            "x-query": {
                "tags": [
                    "Query"
                ],
                "summary": "Query pages only (QUERY method)",
                "description": "Like `QUERY /query` but restricted to static pages (`type` is\nforced to `pages`). The real HTTP method is `QUERY`.\n",
                "operationId": "queryPages",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/QueryRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Page query executed successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/QueryResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/health": {
            "get": {
                "tags": [
                    "System"
                ],
                "summary": "Health check",
                "description": "Returns the API health status for monitoring and load balancers.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "healthCheck",
                "responses": {
                    "200": {
                        "description": "API is operational",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/HealthResponse"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/openapi.json": {
            "get": {
                "tags": [
                    "System"
                ],
                "summary": "Get OpenAPI specification",
                "description": "Returns this OpenAPI 3.0 specification. The `servers` entry is a\nrelative URL (`/api/v1`) that resolves on any host without\nsubstitution; only the `info.x-logo` URL is replaced at runtime\nwith the configured app URL. Served dynamically from the\n`openapi.json` file at the project root.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "getOpenApiSpec",
                "responses": {
                    "200": {
                        "description": "OpenAPI specification",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalServerError"
                    }
                }
            }
        },
        "/csrf-token": {
            "get": {
                "tags": [
                    "System"
                ],
                "summary": "Get CSRF token",
                "description": "Issues a CSRF token for session-authenticated write requests.\nSend it back as the `X-CSRF-Token` header. Requests using an\nAPI key or Bearer token are exempt from CSRF validation.\nThis endpoint is public and does not require authentication.\n",
                "operationId": "getCsrfToken",
                "responses": {
                    "200": {
                        "description": "CSRF token generated",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CsrfTokenResponse"
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "ApiKeyAuth": {
                "type": "apiKey",
                "in": "header",
                "name": "X-API-Key",
                "description": "API key authentication. Pass your API key in the X-API-Key header.\n"
            },
            "BearerAuth": {
                "type": "http",
                "scheme": "bearer",
                "bearerFormat": "JWT",
                "description": "Bearer token authentication. Pass your bearer token in the Authorization header.\n"
            }
        },
        "parameters": {
            "Page": {
                "name": "page",
                "in": "query",
                "description": "Page number for pagination",
                "required": false,
                "schema": {
                    "type": "integer",
                    "minimum": 1,
                    "default": 1,
                    "example": 1
                }
            },
            "PerPage": {
                "name": "per_page",
                "in": "query",
                "description": "Number of items per page",
                "required": false,
                "schema": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "default": 10,
                    "example": 10
                }
            },
            "SortBy": {
                "name": "sort_by",
                "in": "query",
                "description": "Field to sort by",
                "required": false,
                "schema": {
                    "type": "string",
                    "default": "ID",
                    "enum": [
                        "ID",
                        "post_date",
                        "post_modified",
                        "post_title",
                        "topic_title",
                        "comment_date"
                    ]
                }
            },
            "SortOrder": {
                "name": "sort_order",
                "in": "query",
                "description": "Sort direction",
                "required": false,
                "schema": {
                    "type": "string",
                    "enum": [
                        "ASC",
                        "DESC"
                    ],
                    "default": "DESC"
                }
            },
            "PostId": {
                "name": "id",
                "in": "path",
                "description": "Post ID",
                "required": true,
                "schema": {
                    "type": "integer",
                    "example": 1
                }
            },
            "CategoryId": {
                "name": "id",
                "in": "path",
                "description": "Category ID",
                "required": true,
                "schema": {
                    "type": "integer",
                    "example": 1
                }
            },
            "CommentId": {
                "name": "id",
                "in": "path",
                "description": "Comment ID",
                "required": true,
                "schema": {
                    "type": "integer",
                    "example": 1
                }
            }
        },
        "schemas": {
            "Error": {
                "type": "object",
                "properties": {
                    "success": {
                        "type": "boolean",
                        "example": false
                    },
                    "status": {
                        "type": "integer",
                        "example": 400
                    },
                    "error": {
                        "type": "object",
                        "properties": {
                            "code": {
                                "type": "string",
                                "example": "BAD_REQUEST"
                            },
                            "message": {
                                "type": "string",
                                "example": "Error description"
                            },
                            "details": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "properties": {
                                        "field": {
                                            "type": "string"
                                        },
                                        "message": {
                                            "type": "string"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "SuccessResponse": {
                "type": "object",
                "properties": {
                    "success": {
                        "type": "boolean",
                        "example": true
                    },
                    "status": {
                        "type": "integer",
                        "example": 200
                    },
                    "message": {
                        "type": "string",
                        "example": "Operation successful"
                    },
                    "data": {
                        "type": "object"
                    },
                    "_links": {
                        "$ref": "#/components/schemas/Links"
                    }
                }
            },
            "Post": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "example": 1
                    },
                    "title": {
                        "type": "string",
                        "example": "My First Blog Post"
                    },
                    "slug": {
                        "type": "string",
                        "example": "my-first-blog-post"
                    },
                    "content": {
                        "type": "string",
                        "example": "Full post content here..."
                    },
                    "summary": {
                        "type": "string",
                        "nullable": true,
                        "example": "Post summary for preview"
                    },
                    "excerpt": {
                        "type": "string",
                        "example": "Generated excerpt..."
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "publish",
                            "draft",
                            "pending",
                            "private"
                        ],
                        "example": "publish"
                    },
                    "visibility": {
                        "type": "string",
                        "enum": [
                            "public",
                            "private",
                            "protected"
                        ],
                        "example": "public"
                    },
                    "tags": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "example": [
                            "php",
                            "rest-api"
                        ]
                    },
                    "comment_status": {
                        "type": "string",
                        "enum": [
                            "open",
                            "closed"
                        ],
                        "example": "open"
                    },
                    "type": {
                        "type": "string",
                        "example": "blog"
                    },
                    "author": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "integer",
                                "example": 1
                            },
                            "login": {
                                "type": "string",
                                "example": "admin"
                            },
                            "name": {
                                "type": "string",
                                "example": "Administrator"
                            }
                        }
                    },
                    "date": {
                        "type": "string",
                        "format": "date-time",
                        "example": "2024-01-15 10:30:00"
                    },
                    "modified": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "example": "2024-01-15 14:20:00"
                    },
                    "url": {
                        "type": "string",
                        "example": "http://blogware.site/post/1/my-first-blog-post"
                    }
                }
            },
            "PostCreate": {
                "type": "object",
                "required": [
                    "post_title",
                    "post_content"
                ],
                "properties": {
                    "post_title": {
                        "type": "string",
                        "maxLength": 200,
                        "example": "My First Blog Post"
                    },
                    "post_content": {
                        "type": "string",
                        "example": "Full post content here..."
                    },
                    "post_summary": {
                        "type": "string",
                        "maxLength": 320,
                        "nullable": true,
                        "example": "Post summary"
                    },
                    "post_status": {
                        "type": "string",
                        "enum": [
                            "publish",
                            "draft"
                        ],
                        "default": "draft"
                    },
                    "post_visibility": {
                        "type": "string",
                        "enum": [
                            "public",
                            "private",
                            "protected"
                        ],
                        "default": "public"
                    },
                    "post_tags": {
                        "type": "string",
                        "nullable": true,
                        "example": "php, api, rest"
                    },
                    "comment_status": {
                        "type": "string",
                        "enum": [
                            "open",
                            "closed"
                        ],
                        "default": "open"
                    },
                    "topics": {
                        "type": "array",
                        "items": {
                            "type": "integer"
                        },
                        "example": [
                            1,
                            2
                        ]
                    }
                }
            },
            "PostUpdate": {
                "type": "object",
                "properties": {
                    "post_title": {
                        "type": "string",
                        "maxLength": 200
                    },
                    "post_content": {
                        "type": "string"
                    },
                    "post_summary": {
                        "type": "string",
                        "maxLength": 320,
                        "nullable": true
                    },
                    "post_status": {
                        "type": "string",
                        "enum": [
                            "publish",
                            "draft",
                            "pending",
                            "private"
                        ]
                    },
                    "post_visibility": {
                        "type": "string",
                        "enum": [
                            "public",
                            "private",
                            "protected"
                        ]
                    },
                    "post_tags": {
                        "type": "string",
                        "nullable": true
                    },
                    "comment_status": {
                        "type": "string",
                        "enum": [
                            "open",
                            "closed"
                        ]
                    },
                    "topics": {
                        "type": "array",
                        "items": {
                            "type": "integer"
                        }
                    }
                }
            },
            "PostListResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/Post"
                                }
                            },
                            "pagination": {
                                "$ref": "#/components/schemas/Pagination"
                            }
                        }
                    }
                ]
            },
            "PostDetailResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "allOf": [
                                    {
                                        "$ref": "#/components/schemas/Post"
                                    },
                                    {
                                        "type": "object",
                                        "properties": {
                                            "topics": {
                                                "type": "array",
                                                "items": {
                                                    "$ref": "#/components/schemas/CategorySummary"
                                                }
                                            },
                                            "featured_image": {
                                                "type": "string",
                                                "nullable": true,
                                                "example": "http://blogware.site/public/files/pictures/featured.jpg"
                                            }
                                        }
                                    }
                                ]
                            }
                        }
                    }
                ]
            },
            "PostResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "$ref": "#/components/schemas/Post"
                            }
                        }
                    }
                ]
            },
            "CategorySummary": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "example": 1
                    },
                    "title": {
                        "type": "string",
                        "example": "Technology"
                    },
                    "slug": {
                        "type": "string",
                        "example": "technology"
                    }
                }
            },
            "Category": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/CategorySummary"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "status": {
                                "type": "string",
                                "enum": [
                                    "Y",
                                    "N"
                                ],
                                "example": "Y"
                            },
                            "post_count": {
                                "type": "integer",
                                "example": 15
                            },
                            "url": {
                                "type": "string",
                                "example": "http://blogware.site/category/technology"
                            }
                        }
                    }
                ]
            },
            "CategoryCreate": {
                "type": "object",
                "required": [
                    "topic_title"
                ],
                "properties": {
                    "topic_title": {
                        "type": "string",
                        "maxLength": 255,
                        "example": "Technology"
                    },
                    "topic_status": {
                        "type": "string",
                        "enum": [
                            "Y",
                            "N"
                        ],
                        "default": "Y"
                    }
                }
            },
            "CategoryUpdate": {
                "type": "object",
                "properties": {
                    "topic_title": {
                        "type": "string",
                        "maxLength": 255
                    },
                    "topic_status": {
                        "type": "string",
                        "enum": [
                            "Y",
                            "N"
                        ]
                    }
                }
            },
            "CategoryListResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/Category"
                                }
                            },
                            "pagination": {
                                "$ref": "#/components/schemas/Pagination"
                            }
                        }
                    }
                ]
            },
            "CategoryResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "$ref": "#/components/schemas/Category"
                            }
                        }
                    }
                ]
            },
            "CategoryPostsResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "object",
                                "properties": {
                                    "category": {
                                        "$ref": "#/components/schemas/CategorySummary"
                                    },
                                    "posts": {
                                        "type": "array",
                                        "items": {
                                            "$ref": "#/components/schemas/Post"
                                        }
                                    }
                                }
                            },
                            "pagination": {
                                "$ref": "#/components/schemas/Pagination"
                            }
                        }
                    }
                ]
            },
            "Comment": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "example": 1
                    },
                    "post_id": {
                        "type": "integer",
                        "example": 1
                    },
                    "parent_id": {
                        "type": "integer",
                        "example": 0
                    },
                    "author": {
                        "type": "object",
                        "properties": {
                            "name": {
                                "type": "string",
                                "example": "John Doe"
                            },
                            "email": {
                                "type": "string",
                                "example": "john@example.com"
                            }
                        }
                    },
                    "content": {
                        "type": "string",
                        "example": "Great article!"
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "approved",
                            "pending",
                            "spam"
                        ],
                        "example": "approved"
                    },
                    "date": {
                        "type": "string",
                        "format": "date-time",
                        "example": "2024-01-15 10:30:00"
                    }
                }
            },
            "CommentCreate": {
                "type": "object",
                "required": [
                    "comment_author_name",
                    "comment_content",
                    "comment_post_id"
                ],
                "properties": {
                    "comment_author_name": {
                        "type": "string",
                        "maxLength": 60,
                        "example": "John Doe"
                    },
                    "comment_author_email": {
                        "type": "string",
                        "format": "email",
                        "nullable": true,
                        "example": "john@example.com"
                    },
                    "comment_content": {
                        "type": "string",
                        "example": "Great article!"
                    },
                    "comment_post_id": {
                        "type": "integer",
                        "example": 1
                    },
                    "comment_parent_id": {
                        "type": "integer",
                        "default": 0,
                        "example": 0
                    }
                }
            },
            "CommentUpdate": {
                "type": "object",
                "properties": {
                    "comment_author_name": {
                        "type": "string",
                        "maxLength": 60
                    },
                    "comment_content": {
                        "type": "string"
                    },
                    "comment_status": {
                        "type": "string",
                        "enum": [
                            "approved",
                            "pending",
                            "spam"
                        ]
                    }
                }
            },
            "CommentListResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/Comment"
                                }
                            },
                            "pagination": {
                                "$ref": "#/components/schemas/Pagination"
                            }
                        }
                    }
                ]
            },
            "CommentResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "allOf": [
                                    {
                                        "$ref": "#/components/schemas/Comment"
                                    },
                                    {
                                        "type": "object",
                                        "properties": {
                                            "post": {
                                                "type": "object",
                                                "properties": {
                                                    "title": {
                                                        "type": "string"
                                                    },
                                                    "slug": {
                                                        "type": "string"
                                                    },
                                                    "url": {
                                                        "type": "string"
                                                    }
                                                },
                                                "nullable": true
                                            }
                                        }
                                    }
                                ]
                            }
                        }
                    }
                ]
            },
            "ArchiveMonth": {
                "type": "object",
                "properties": {
                    "month": {
                        "type": "integer",
                        "example": 6
                    },
                    "month_name": {
                        "type": "string",
                        "example": "June"
                    },
                    "post_count": {
                        "type": "integer",
                        "example": 5
                    }
                }
            },
            "ArchiveYear": {
                "type": "object",
                "properties": {
                    "year": {
                        "type": "integer",
                        "example": 2024
                    },
                    "months": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ArchiveMonth"
                        }
                    },
                    "total_posts": {
                        "type": "integer",
                        "example": 25
                    }
                }
            },
            "ArchiveListResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "object",
                                "properties": {
                                    "archives": {
                                        "type": "array",
                                        "items": {
                                            "$ref": "#/components/schemas/ArchiveYear"
                                        }
                                    },
                                    "total_years": {
                                        "type": "integer",
                                        "example": 3
                                    }
                                }
                            }
                        }
                    }
                ]
            },
            "ArchiveYearResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "object",
                                "properties": {
                                    "year": {
                                        "type": "integer",
                                        "example": 2024
                                    },
                                    "posts": {
                                        "type": "array",
                                        "items": {
                                            "$ref": "#/components/schemas/Post"
                                        }
                                    }
                                }
                            },
                            "pagination": {
                                "$ref": "#/components/schemas/Pagination"
                            }
                        }
                    }
                ]
            },
            "ArchiveMonthResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "object",
                                "properties": {
                                    "year": {
                                        "type": "integer",
                                        "example": 2024
                                    },
                                    "month": {
                                        "type": "integer",
                                        "example": 6
                                    },
                                    "month_name": {
                                        "type": "string",
                                        "example": "June"
                                    },
                                    "posts": {
                                        "type": "array",
                                        "items": {
                                            "$ref": "#/components/schemas/Post"
                                        }
                                    }
                                }
                            },
                            "pagination": {
                                "$ref": "#/components/schemas/Pagination"
                            }
                        }
                    }
                ]
            },
            "Link": {
                "type": "object",
                "description": "HATEOAS link following RFC 5988 (Web Linking)",
                "properties": {
                    "href": {
                        "type": "string",
                        "description": "The URL of the linked resource",
                        "example": "http://blogware.site/api/v1/posts"
                    },
                    "rel": {
                        "type": "string",
                        "description": "The relationship type",
                        "example": "self"
                    },
                    "type": {
                        "type": "string",
                        "description": "The HTTP method or MIME type",
                        "example": "GET"
                    },
                    "templated": {
                        "type": "boolean",
                        "description": "Whether the URL is a URI template",
                        "example": false
                    }
                },
                "required": [
                    "href",
                    "rel"
                ]
            },
            "Links": {
                "type": "object",
                "description": "HATEOAS links for discoverable API navigation",
                "additionalProperties": {
                    "$ref": "#/components/schemas/Link"
                },
                "example": {
                    "self": {
                        "href": "http://blogware.site/api/v1/posts?page=1",
                        "rel": "self",
                        "type": "GET"
                    },
                    "next": {
                        "href": "http://blogware.site/api/v1/posts?page=2",
                        "rel": "next",
                        "type": "GET"
                    },
                    "collection": {
                        "href": "http://blogware.site/api/v1/posts",
                        "rel": "collection",
                        "type": "GET"
                    }
                }
            },
            "Pagination": {
                "type": "object",
                "properties": {
                    "current_page": {
                        "type": "integer",
                        "example": 1
                    },
                    "per_page": {
                        "type": "integer",
                        "example": 10
                    },
                    "total_items": {
                        "type": "integer",
                        "example": 50
                    },
                    "total_pages": {
                        "type": "integer",
                        "example": 5
                    },
                    "has_next_page": {
                        "type": "boolean",
                        "example": true
                    },
                    "has_previous_page": {
                        "type": "boolean",
                        "example": false
                    }
                }
            },
            "DeleteResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": null,
                                "example": null
                            }
                        }
                    }
                ]
            },
            "ApiInfo": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "object",
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "example": "Blogware RESTful API"
                                    },
                                    "version": {
                                        "type": "string",
                                        "example": "1.1.2"
                                    },
                                    "description": {
                                        "type": "string"
                                    },
                                    "base_url": {
                                        "type": "string",
                                        "example": "/api/v1"
                                    },
                                    "authentication": {
                                        "type": "object",
                                        "properties": {
                                            "type": {
                                                "type": "string"
                                            },
                                            "header": {
                                                "type": "string"
                                            },
                                            "required": {
                                                "type": "boolean"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                ]
            },
            "SearchResult": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "example": 1
                    },
                    "title": {
                        "type": "string",
                        "example": "My First Blog Post"
                    },
                    "slug": {
                        "type": "string",
                        "example": "my-first-blog-post"
                    },
                    "excerpt": {
                        "type": "string",
                        "example": "Matching content excerpt..."
                    },
                    "type": {
                        "type": "string",
                        "enum": [
                            "blog",
                            "page"
                        ],
                        "example": "blog"
                    },
                    "date": {
                        "type": "string",
                        "format": "date-time",
                        "example": "2024-01-15 10:30:00"
                    },
                    "url": {
                        "type": "string",
                        "example": "http://blogware.site/post/1/my-first-blog-post"
                    }
                }
            },
            "SearchResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "object",
                                "properties": {
                                    "keyword": {
                                        "type": "string",
                                        "example": "php"
                                    },
                                    "type": {
                                        "type": "string",
                                        "enum": [
                                            "all",
                                            "posts",
                                            "pages"
                                        ],
                                        "example": "all"
                                    },
                                    "total": {
                                        "type": "integer",
                                        "description": "Total result count (also read by the sidebar widget)",
                                        "example": 7
                                    },
                                    "results": {
                                        "type": "array",
                                        "items": {
                                            "$ref": "#/components/schemas/SearchResult"
                                        }
                                    },
                                    "pagination": {
                                        "$ref": "#/components/schemas/Pagination"
                                    }
                                }
                            }
                        }
                    }
                ]
            },
            "QueryRequest": {
                "type": "object",
                "description": "JSON body for QUERY /query, /query/posts and /query/pages",
                "properties": {
                    "q": {
                        "type": "string",
                        "description": "Search keyword (`keyword` is accepted as an alias)",
                        "example": "php"
                    },
                    "keyword": {
                        "type": "string",
                        "description": "Alias of `q`",
                        "example": "php"
                    },
                    "type": {
                        "type": "string",
                        "description": "Search scope (forced by the /posts and /pages variants)",
                        "enum": [
                            "all",
                            "posts",
                            "pages"
                        ],
                        "default": "all",
                        "example": "all"
                    }
                }
            },
            "QueryResult": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "example": 1
                    },
                    "title": {
                        "type": "string",
                        "example": "My First Blog Post"
                    },
                    "slug": {
                        "type": "string",
                        "example": "my-first-blog-post"
                    },
                    "excerpt": {
                        "type": "string",
                        "description": "200-character plain-text excerpt",
                        "example": "Matching content excerpt..."
                    },
                    "type": {
                        "type": "string",
                        "example": "blog"
                    },
                    "date": {
                        "type": "string",
                        "format": "date-time",
                        "example": "2024-01-15 10:30:00"
                    },
                    "status": {
                        "type": "string",
                        "example": "publish"
                    }
                }
            },
            "QueryResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "object",
                                "properties": {
                                    "query": {
                                        "type": "object",
                                        "properties": {
                                            "keyword": {
                                                "type": "string",
                                                "example": "php"
                                            },
                                            "type": {
                                                "type": "string",
                                                "enum": [
                                                    "all",
                                                    "posts",
                                                    "pages"
                                                ],
                                                "example": "all"
                                            }
                                        }
                                    },
                                    "total": {
                                        "type": "integer",
                                        "example": 3
                                    },
                                    "results": {
                                        "type": "array",
                                        "items": {
                                            "$ref": "#/components/schemas/QueryResult"
                                        }
                                    }
                                }
                            }
                        }
                    }
                ]
            },
            "ProtectedPostVerify": {
                "type": "object",
                "required": [
                    "password"
                ],
                "properties": {
                    "password": {
                        "type": "string",
                        "description": "Password of the protected post",
                        "example": "post-password"
                    }
                }
            },
            "ProtectedPostVerifyResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "object",
                                "properties": {
                                    "valid": {
                                        "type": "boolean",
                                        "example": true
                                    }
                                }
                            }
                        }
                    }
                ]
            },
            "ProtectedPostUnlockResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "object",
                                "properties": {
                                    "content": {
                                        "type": "string",
                                        "description": "Sanitized decrypted post content",
                                        "example": "<p>Secret content...</p>"
                                    }
                                }
                            }
                        }
                    }
                ]
            },
            "GdprConsent": {
                "type": "object",
                "required": [
                    "status"
                ],
                "properties": {
                    "status": {
                        "type": "string",
                        "description": "Consent decision recorded with the client IP and user agent",
                        "enum": [
                            "accepted",
                            "rejected"
                        ],
                        "example": "accepted"
                    }
                }
            },
            "GdprConsentResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "object",
                                "properties": {
                                    "consent_given": {
                                        "type": "boolean",
                                        "description": "Present on GET /gdpr/consent",
                                        "example": true
                                    },
                                    "consent_type": {
                                        "type": "string",
                                        "description": "Present on GET /gdpr/consent",
                                        "example": "cookie"
                                    },
                                    "status": {
                                        "type": "string",
                                        "description": "Present on POST /gdpr/consent",
                                        "enum": [
                                            "accepted",
                                            "rejected"
                                        ],
                                        "example": "accepted"
                                    },
                                    "message": {
                                        "type": "string",
                                        "description": "Present on POST /gdpr/consent",
                                        "example": "Consent recorded successfully"
                                    },
                                    "timestamp": {
                                        "type": "string",
                                        "description": "Present on POST /gdpr/consent",
                                        "format": "date-time",
                                        "example": "2026-07-30 12:00:00"
                                    }
                                }
                            }
                        }
                    }
                ]
            },
            "Language": {
                "type": "object",
                "properties": {
                    "ID": {
                        "type": "integer",
                        "example": 1
                    },
                    "lang_code": {
                        "type": "string",
                        "example": "en"
                    },
                    "lang_name": {
                        "type": "string",
                        "example": "English"
                    },
                    "lang_native": {
                        "type": "string",
                        "example": "English"
                    },
                    "lang_locale": {
                        "type": "string",
                        "nullable": true,
                        "example": "en_US"
                    },
                    "lang_direction": {
                        "type": "string",
                        "enum": [
                            "ltr",
                            "rtl"
                        ],
                        "example": "ltr"
                    },
                    "lang_sort": {
                        "type": "integer",
                        "example": 0
                    },
                    "lang_is_default": {
                        "type": "integer",
                        "enum": [
                            0,
                            1
                        ],
                        "example": 1
                    }
                }
            },
            "LanguageCreate": {
                "type": "object",
                "required": [
                    "lang_code",
                    "lang_name",
                    "lang_native"
                ],
                "properties": {
                    "lang_code": {
                        "type": "string",
                        "example": "de"
                    },
                    "lang_name": {
                        "type": "string",
                        "example": "German"
                    },
                    "lang_native": {
                        "type": "string",
                        "example": "Deutsch"
                    },
                    "lang_locale": {
                        "type": "string",
                        "nullable": true,
                        "example": "de_DE"
                    },
                    "lang_direction": {
                        "type": "string",
                        "enum": [
                            "ltr",
                            "rtl"
                        ],
                        "default": "ltr"
                    },
                    "lang_sort": {
                        "type": "integer",
                        "default": 0
                    },
                    "lang_is_default": {
                        "type": "integer",
                        "enum": [
                            0,
                            1
                        ],
                        "default": 0
                    }
                }
            },
            "LanguageUpdate": {
                "type": "object",
                "description": "Partial language fields; passed straight to the service layer.",
                "properties": {
                    "lang_name": {
                        "type": "string"
                    },
                    "lang_native": {
                        "type": "string"
                    },
                    "lang_locale": {
                        "type": "string",
                        "nullable": true
                    },
                    "lang_direction": {
                        "type": "string",
                        "enum": [
                            "ltr",
                            "rtl"
                        ]
                    },
                    "lang_sort": {
                        "type": "integer"
                    },
                    "lang_is_default": {
                        "type": "integer",
                        "enum": [
                            0,
                            1
                        ]
                    }
                }
            },
            "LanguageResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "$ref": "#/components/schemas/Language"
                            }
                        }
                    }
                ]
            },
            "LanguageListResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/Language"
                                }
                            },
                            "pagination": {
                                "$ref": "#/components/schemas/Pagination"
                            }
                        }
                    }
                ]
            },
            "Translation": {
                "type": "object",
                "properties": {
                    "ID": {
                        "type": "integer",
                        "example": 1
                    },
                    "lang_code": {
                        "type": "string",
                        "example": "en"
                    },
                    "translation_key": {
                        "type": "string",
                        "example": "nav.dashboard"
                    },
                    "translation_value": {
                        "type": "string",
                        "example": "Dashboard"
                    },
                    "translation_context": {
                        "type": "string",
                        "nullable": true
                    },
                    "is_html": {
                        "type": "integer",
                        "enum": [
                            0,
                            1
                        ],
                        "example": 0
                    }
                }
            },
            "TranslationCreate": {
                "type": "object",
                "required": [
                    "lang_code",
                    "translation_key",
                    "translation_value"
                ],
                "properties": {
                    "lang_code": {
                        "type": "string",
                        "example": "en"
                    },
                    "translation_key": {
                        "type": "string",
                        "example": "nav.dashboard"
                    },
                    "translation_value": {
                        "type": "string",
                        "example": "Dashboard"
                    },
                    "translation_context": {
                        "type": "string",
                        "nullable": true
                    },
                    "is_html": {
                        "type": "integer",
                        "enum": [
                            0,
                            1
                        ],
                        "default": 0
                    }
                }
            },
            "TranslationUpdate": {
                "type": "object",
                "required": [
                    "translation_value"
                ],
                "properties": {
                    "translation_value": {
                        "type": "string",
                        "example": "Dashboard"
                    },
                    "translation_context": {
                        "type": "string",
                        "nullable": true
                    },
                    "is_html": {
                        "type": "integer",
                        "enum": [
                            0,
                            1
                        ]
                    }
                }
            },
            "TranslationResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "$ref": "#/components/schemas/Translation"
                            }
                        }
                    }
                ]
            },
            "TranslationListResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/Translation"
                                }
                            },
                            "pagination": {
                                "$ref": "#/components/schemas/Pagination"
                            }
                        }
                    }
                ]
            },
            "MediaUpload": {
                "type": "object",
                "required": [
                    "image"
                ],
                "properties": {
                    "image": {
                        "type": "string",
                        "format": "binary",
                        "description": "Image file (JPEG, PNG, GIF, WebP or BMP; max 5 MB)"
                    },
                    "post_id": {
                        "type": "integer",
                        "description": "Optional post ID to link the image to via tbl_mediameta",
                        "example": 1
                    }
                }
            },
            "MediaUploadResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "object",
                                "properties": {
                                    "url": {
                                        "type": "string",
                                        "example": "http://blogware.site/public/files/pictures/abc123_1720000000.jpg"
                                    },
                                    "filename": {
                                        "type": "string",
                                        "example": "abc123_1720000000.jpg"
                                    },
                                    "media_id": {
                                        "type": "integer",
                                        "example": 42
                                    },
                                    "post_id": {
                                        "type": "integer",
                                        "nullable": true,
                                        "example": 1
                                    }
                                }
                            }
                        }
                    }
                ]
            },
            "HealthResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "object",
                                "required": [
                                    "status",
                                    "timestamp",
                                    "php_version"
                                ],
                                "properties": {
                                    "status": {
                                        "type": "string",
                                        "example": "healthy"
                                    },
                                    "timestamp": {
                                        "type": "string",
                                        "example": "2026-07-30 12:00:00"
                                    },
                                    "php_version": {
                                        "type": "string",
                                        "example": "8.1.2"
                                    }
                                }
                            }
                        }
                    }
                ]
            },
            "CsrfTokenResponse": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SuccessResponse"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "object",
                                "required": [
                                    "csrf_token",
                                    "expires_in"
                                ],
                                "properties": {
                                    "csrf_token": {
                                        "type": "string",
                                        "example": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4"
                                    },
                                    "expires_in": {
                                        "type": "integer",
                                        "description": "Token lifetime in seconds",
                                        "example": 3600
                                    }
                                }
                            }
                        }
                    }
                ]
            }
        },
        "responses": {
            "BadRequest": {
                "description": "Bad Request - Invalid parameters",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "Unauthorized": {
                "description": "Unauthorized - Authentication required",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "Forbidden": {
                "description": "Forbidden - Insufficient permissions",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "NotFound": {
                "description": "Not Found - Resource does not exist",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "Conflict": {
                "description": "Conflict - Resource already exists",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "UnprocessableEntity": {
                "description": "Unprocessable Entity - Validation failed",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "InternalServerError": {
                "description": "Internal Server Error",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "TooManyRequests": {
                "description": "Too Many Requests - Rate limit exceeded",
                "headers": {
                    "Retry-After": {
                        "description": "Seconds to wait before retrying",
                        "schema": {
                            "type": "integer",
                            "example": 60
                        }
                    }
                },
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "NotAcceptable": {
                "description": "Not Acceptable - Requested media type not supported",
                "headers": {
                    "Accept": {
                        "description": "Supported media types",
                        "schema": {
                            "type": "string",
                            "example": "application/json"
                        }
                    }
                },
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "MethodNotAllowed": {
                "description": "Method Not Allowed - HTTP method not supported for this path",
                "headers": {
                    "Allow": {
                        "description": "Methods registered for this path",
                        "schema": {
                            "type": "string",
                            "example": "GET, POST, PUT, PATCH, DELETE, QUERY, OPTIONS"
                        }
                    }
                },
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "UnsupportedMediaType": {
                "description": "Unsupported Media Type - write requests must send application/json",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "NotModified": {
                "description": "Not Modified - Resource has not changed (use cached version)",
                "headers": {
                    "ETag": {
                        "description": "Entity tag for the resource",
                        "schema": {
                            "type": "string",
                            "example": "\"abc123\""
                        }
                    },
                    "Last-Modified": {
                        "description": "Last modification timestamp",
                        "schema": {
                            "type": "string",
                            "format": "date-time"
                        }
                    },
                    "Cache-Control": {
                        "description": "Cache directives",
                        "schema": {
                            "type": "string",
                            "example": "public, max-age=300"
                        }
                    }
                }
            }
        }
    },
    "externalDocs": {
        "description": "Blogware Documentation",
        "url": "https://blogware.site/docs"
    },
    "x-tagGroups": [
        {
            "name": "Core",
            "tags": [
                "API Info",
                "System"
            ]
        },
        {
            "name": "Content",
            "tags": [
                "Posts",
                "Categories",
                "Comments",
                "Archives"
            ]
        },
        {
            "name": "Discovery",
            "tags": [
                "Search",
                "Query"
            ]
        },
        {
            "name": "Internationalization",
            "tags": [
                "Languages",
                "Translations"
            ]
        },
        {
            "name": "Compliance & Media",
            "tags": [
                "GDPR",
                "Media"
            ]
        }
    ]
}