{
  "openapi": "3.0.3",
  "info": {
    "title": "NMS SMSolution API",
    "description": "REST API untuk NMS SMSolution — Network Management System untuk monitoring perangkat OLT/ONT dan Mikrotik.\n\n## Authentication\n\nDua cara autentikasi:\n1. **Sanctum Token** — POST `/auth/login` untuk mendapatkan token\n2. **API Key** — Generate di halaman /api-keys di web UI\n\nKedua jenis dikirim via header: `Authorization: Bearer <token>`\n\n## Rate Limiting\n\nSetiap API key memiliki quota berbeda tergantung plan. Lihat `GET /stats/usage` untuk detail. Header `X-RateLimit-Remaining` disertakan di setiap response.\n\n## Scopes (API Key only)\n\n- `*` — Full access (default)\n- `read:olt`, `read:ont` — Read-only access\n- `write:olt`, `write:ont` — Create/update access\n- `delete:olt`, `delete:ont` — Delete access\n\n## Destructive Actions\n\nSemua endpoint DELETE dengan middleware `confirm.delete` wajib menyertakan header:\n```\nX-Confirm-Delete: yes\n```\nTanpa header ini, request akan ditolak dengan HTTP 400.",
    "version": "1.0.0",
    "contact": {
      "name": "NMS SMSolution Support",
      "email": "support@smsolution.id"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "/api/v1",
      "description": "Current server"
    }
  ],
  "tags": [
    { "name": "Meta", "description": "Health check & metadata" },
    { "name": "Authentication", "description": "Login, logout, token management" },
    { "name": "OLT Devices", "description": "OLT CRUD, polling, connection test, history" },
    { "name": "ONT", "description": "ONT lookup, history, rename, reboot, delete" },
    { "name": "Vendor", "description": "OLT vendor & firmware catalog (read-only)" },
    { "name": "Telegram Bots", "description": "Telegram alert bot configuration" },
    { "name": "Stats", "description": "Dashboard metrics, subscription, usage & performance" },
    { "name": "Audit Logs", "description": "Audit trail — super_admin only" }
  ],
  "components": {
    "securitySchemes": {
      "SanctumToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Sanctum",
        "description": "Sanctum personal access token obtained from POST /auth/login. Token format: `nms_<hex>`."
      },
      "ApiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key generated at /api-keys in the web UI. Sent as Bearer token identical to Sanctum."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code":    { "type": "string", "example": "RESOURCE_NOT_FOUND" },
              "message": { "type": "string", "example": "OLT device not found" },
              "details": { "nullable": true }
            },
            "required": ["code", "message"]
          }
        },
        "required": ["error"]
      },
      "ValidationError": {
        "type": "object",
        "properties": {
          "message": { "type": "string", "example": "The given data was invalid." },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": { "type": "string" }
            },
            "example": { "name": ["The name field is required."] }
          }
        }
      },
      "PaginationMeta": {
        "type": "object",
        "properties": {
          "total":     { "type": "integer", "example": 128 },
          "page":      { "type": "integer", "example": 1 },
          "per_page":  { "type": "integer", "example": 25 },
          "last_page": { "type": "integer", "example": 6 },
          "from":      { "type": "integer", "nullable": true, "example": 1 },
          "to":        { "type": "integer", "nullable": true, "example": 25 }
        }
      },
      "OltVendor": {
        "type": "object",
        "properties": {
          "id":   { "type": "integer", "example": 1 },
          "name": { "type": "string",  "example": "HSGQ" },
          "slug": { "type": "string",  "example": "hsgq" }
        }
      },
      "OltFirmware": {
        "type": "object",
        "properties": {
          "id":      { "type": "integer", "example": 1 },
          "name":    { "type": "string",  "example": "V1014 ID" },
          "version": { "type": "string",  "nullable": true, "example": null },
          "type":    { "type": "string",  "enum": ["gpon", "epon"], "example": "gpon" }
        }
      },
      "OltDevice": {
        "type": "object",
        "properties": {
          "id":               { "type": "integer", "example": 1 },
          "name":             { "type": "string",  "example": "OLT Jakarta Pusat" },
          "host":             { "type": "string",  "example": "192.168.1.1" },
          "port":             { "type": "integer", "example": 80 },
          "vendor":           {
            "nullable": true,
            "allOf": [{ "$ref": "#/components/schemas/OltVendor" }]
          },
          "firmware":         {
            "nullable": true,
            "allOf": [{ "$ref": "#/components/schemas/OltFirmware" }]
          },
          "is_active":        { "type": "boolean", "example": true },
          "alert_enabled":    { "type": "boolean", "example": true },
          "polling_interval": { "type": "integer", "example": 5, "description": "Minutes between polls" },
          "last_polled_at":   { "type": "string",  "format": "date-time", "nullable": true },
          "status":           {
            "type": "string",
            "enum": ["ok", "unreachable", "scrape_failed", "no_driver", "unknown"],
            "example": "ok"
          },
          "last_status": {
            "type": "object",
            "description": "Raw last-poll result (shape varies by driver)",
            "example": {
              "status": "ok",
              "total_ont": 128,
              "online": 120,
              "offline": 8,
              "duration_ms": 3200
            }
          },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" },
          "deleted_at": { "type": "string", "format": "date-time", "nullable": true }
        }
      },
      "OntData": {
        "description": "Latest ONT snapshot (deduplicated per SN)",
        "type": "object",
        "properties": {
          "sn":             { "type": "string",  "example": "HWTC1A2B3C4D" },
          "name":           { "type": "string",  "nullable": true, "example": "Customer Budi" },
          "port":           { "type": "string",  "nullable": true, "example": "0/1/1" },
          "status":         { "type": "string",  "enum": ["up", "down"], "example": "up" },
          "rx_power":       { "type": "number",  "format": "float", "nullable": true, "example": -22.5 },
          "tx_power":       { "type": "number",  "format": "float", "nullable": true, "example": null },
          "distance_m":     { "type": "integer", "nullable": true,  "example": null },
          "uptime_seconds": { "type": "integer", "nullable": true,  "example": null },
          "down_reason":    { "type": "string",  "nullable": true,  "example": null },
          "olt_device_id":  { "type": "integer", "example": 1 },
          "recorded_at":    { "type": "string",  "format": "date-time" }
        }
      },
      "OntSnapshot": {
        "description": "Single point-in-time ONT snapshot (raw history record)",
        "type": "object",
        "properties": {
          "id":             { "type": "integer", "example": 98765 },
          "olt_device_id":  { "type": "integer", "example": 1 },
          "sn":             { "type": "string",  "example": "HWTC1A2B3C4D" },
          "name":           { "type": "string",  "nullable": true, "example": "Customer Budi" },
          "port":           { "type": "string",  "nullable": true, "example": "0/1/1" },
          "status":         { "type": "string",  "enum": ["up", "down"], "example": "up" },
          "rx_power":       { "type": "number",  "format": "float", "nullable": true, "example": -22.5 },
          "tx_power":       { "type": "number",  "format": "float", "nullable": true, "example": null },
          "down_reason":    { "type": "string",  "nullable": true,  "example": null },
          "uptime_seconds": { "type": "integer", "nullable": true,  "example": null },
          "recorded_at":    { "type": "string",  "format": "date-time" }
        }
      },
      "OltHistoryBucket": {
        "description": "Hourly aggregated ONT counts from OLT polling history",
        "type": "object",
        "properties": {
          "period":  { "type": "string", "example": "2026-05-17 10:00:00", "description": "Hour bucket (Y-m-d H:00:00)" },
          "total":   { "type": "integer", "example": 128 },
          "online":  { "type": "integer", "example": 120 },
          "offline": { "type": "integer", "example": 8 },
          "avg_rx":  { "type": "number", "format": "float", "nullable": true, "example": -22.3 }
        }
      },
      "TelegramBot": {
        "type": "object",
        "properties": {
          "id":                      { "type": "integer", "example": 1 },
          "alert_status":            { "type": "string",  "enum": ["on", "off"], "example": "on" },
          "is_active":               { "type": "boolean", "example": true },
          "chat_ids":                { "type": "array", "items": { "type": "string" }, "example": ["-100123456789"] },
          "alert_types":             {
            "type": "array",
            "items": {
              "type": "string",
              "enum": ["ont_down", "ont_up", "olt_unreachable", "olt_recovered", "weak_signal", "daily_summary"]
            },
            "example": ["ont_down", "ont_up", "olt_unreachable", "olt_recovered", "weak_signal"]
          },
          "weak_signal_threshold":   { "type": "number",  "format": "float", "example": -28.0 },
          "alert_interval_minutes":  { "type": "integer", "example": 5 },
          "failure_count":           { "type": "integer", "example": 0 },
          "last_alert_sent_at":      { "type": "string",  "format": "date-time", "nullable": true },
          "auto_disabled_at":        { "type": "string",  "format": "date-time", "nullable": true },
          "has_token":               { "type": "boolean", "example": true, "description": "Whether a bot token is configured (token itself is never exposed)" }
        }
      },
      "Plan": {
        "type": "object",
        "properties": {
          "id":            { "type": "integer", "example": 2 },
          "name":          { "type": "string",  "example": "Basic" },
          "slug":          { "type": "string",  "example": "basic" },
          "price":         { "type": "number",  "format": "float", "example": 50000.0 },
          "duration_days": { "type": "integer", "example": 30 },
          "max_olt":       { "type": "integer", "example": 5 },
          "max_mikrotik":  { "type": "integer", "example": 5 },
          "features":      { "type": "object",  "additionalProperties": true, "example": { "api_rate_limit": 1000, "api_access": true } }
        }
      },
      "Subscription": {
        "type": "object",
        "properties": {
          "id":               { "type": "integer", "example": 42 },
          "status":           { "type": "string", "enum": ["pending", "active", "grace", "suspended", "expired", "cancelled"], "example": "active" },
          "is_trial":         { "type": "boolean", "example": false },
          "plan":             { "$ref": "#/components/schemas/Plan" },
          "started_at":       { "type": "string", "format": "date-time", "nullable": true },
          "expires_at":       { "type": "string", "format": "date-time", "nullable": true },
          "trial_expires_at": { "type": "string", "format": "date-time", "nullable": true },
          "auto_renew":       { "type": "boolean", "example": false }
        }
      },
      "AuditLog": {
        "type": "object",
        "properties": {
          "id":            { "type": "integer", "example": 5001 },
          "actor_type":    { "type": "string",  "example": "user" },
          "actor_id":      { "type": "integer", "nullable": true, "example": 1 },
          "action":        { "type": "string",  "enum": ["create", "update", "delete", "login", "logout"], "example": "create" },
          "resource_type": { "type": "string",  "example": "olt_device" },
          "resource_id":   { "nullable": true,  "example": 3 },
          "changes":       { "type": "object",  "additionalProperties": true, "nullable": true },
          "ip_address":    { "type": "string",  "example": "203.0.113.45" },
          "created_at":    { "type": "string",  "format": "date-time" }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid authentication token",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "error": { "code": "UNAUTHENTICATED", "message": "Unauthenticated." } }
          }
        }
      },
      "Forbidden": {
        "description": "Authenticated but lacking required scope or role",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "error": { "code": "FORBIDDEN", "message": "Required scope: write:olt" } }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "error": { "code": "RESOURCE_NOT_FOUND", "message": "OLT device not found" } }
          }
        }
      },
      "ValidationError": {
        "description": "Request validation failed",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ValidationError" },
            "example": {
              "message": "The given data was invalid.",
              "errors": { "name": ["The name field is required."] }
            }
          }
        }
      },
      "DeleteNotConfirmed": {
        "description": "Missing required X-Confirm-Delete: yes header",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "error": { "code": "DELETE_NOT_CONFIRMED", "message": "Send header X-Confirm-Delete: yes to confirm." } }
          }
        }
      },
      "TooManyRequests": {
        "description": "Rate limit exceeded",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Too Many Attempts." } }
          }
        }
      },
      "AccountDisabled": {
        "description": "Account is disabled",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "error": { "code": "ACCOUNT_DISABLED", "message": "This account has been disabled." } }
          }
        }
      }
    }
  },
  "security": [
    { "SanctumToken": [] },
    { "ApiKey": [] }
  ],
  "paths": {
    "/ping": {
      "get": {
        "tags": ["Meta"],
        "summary": "Health check",
        "description": "Returns pong. No authentication required. Use this to verify the API is reachable.",
        "security": [],
        "operationId": "ping",
        "responses": {
          "200": {
            "description": "API is reachable",
            "content": {
              "application/json": {
                "example": {
                  "data": { "pong": true, "timestamp": "2026-05-17T10:00:00+07:00", "version": "v1" }
                }
              }
            }
          }
        }
      }
    },
    "/version": {
      "get": {
        "tags": ["Meta"],
        "summary": "API version",
        "description": "Returns the current API version and application name. No authentication required.",
        "security": [],
        "operationId": "getVersion",
        "responses": {
          "200": {
            "description": "Version info",
            "content": {
              "application/json": {
                "example": {
                  "data": { "version": "v1", "app": "NMS SMSolution" }
                }
              }
            }
          }
        }
      }
    },
    "/auth/login": {
      "post": {
        "tags": ["Authentication"],
        "summary": "Login and obtain Sanctum token",
        "description": "Accepts email or username + password. Returns a Sanctum personal access token prefixed with `nms_`.",
        "security": [],
        "operationId": "login",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email", "password", "device_name"],
                "properties": {
                  "email":       { "type": "string", "example": "admin@nms.local", "description": "Email address or username" },
                  "password":    { "type": "string", "format": "password", "example": "secret123" },
                  "device_name": { "type": "string", "maxLength": 255, "example": "Postman / Monitoring Script" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token issued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "token":      { "type": "string", "example": "nms_4a7b2c..." },
                        "expires_at": { "type": "string", "format": "date-time", "nullable": true },
                        "user": {
                          "type": "object",
                          "properties": {
                            "id":    { "type": "integer" },
                            "name":  { "type": "string" },
                            "email": { "type": "string" },
                            "role":  { "type": "string", "enum": ["super_admin", "admin", "user"] }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": { "$ref": "#/components/responses/AccountDisabled" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/auth/logout": {
      "post": {
        "tags": ["Authentication"],
        "summary": "Logout and revoke current token",
        "description": "Deletes the current Sanctum token (or marks the API key session as ended). Token becomes invalid immediately.",
        "operationId": "logout",
        "responses": {
          "200": {
            "description": "Token revoked",
            "content": {
              "application/json": {
                "example": { "data": { "logged_out": true } }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/auth/refresh": {
      "post": {
        "tags": ["Authentication"],
        "summary": "Rotate token",
        "description": "Issues a new Sanctum token with a fresh expiry and revokes the old one. Useful for long-running scripts.",
        "operationId": "refreshToken",
        "responses": {
          "200": {
            "description": "New token issued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "token":      { "type": "string", "example": "nms_9f3d1e..." },
                        "expires_at": { "type": "string", "format": "date-time", "nullable": true }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/auth/me": {
      "get": {
        "tags": ["Authentication"],
        "summary": "Get current authenticated user",
        "description": "Returns the authenticated user's profile, tenant info, active plan, and auth type.",
        "operationId": "me",
        "responses": {
          "200": {
            "description": "User profile",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id":        { "type": "integer", "example": 1 },
                        "name":      { "type": "string",  "example": "Aa Sodik" },
                        "email":     { "type": "string",  "example": "admin@nms.local" },
                        "username":  { "type": "string",  "example": "aasodik" },
                        "role":      { "type": "string",  "enum": ["super_admin", "admin", "user"], "example": "admin" },
                        "tenant": {
                          "type": "object",
                          "properties": {
                            "id":   { "type": "string", "format": "uuid" },
                            "name": { "type": "string", "example": "ISP Maju Jaya" }
                          }
                        },
                        "plan":      { "type": "string", "example": "basic" },
                        "auth_type": { "type": "string", "enum": ["sanctum", "api_key"], "example": "sanctum" }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/olt": {
      "get": {
        "tags": ["OLT Devices"],
        "summary": "List OLT devices",
        "description": "Returns a paginated list of OLT devices belonging to the authenticated tenant.",
        "operationId": "listOlt",
        "parameters": [
          { "in": "query", "name": "search",   "schema": { "type": "string" },  "description": "Filter by name or host" },
          { "in": "query", "name": "vendor",   "schema": { "type": "string" },  "description": "Filter by vendor slug", "example": "hsgq" },
          { "in": "query", "name": "status",   "schema": { "type": "string", "enum": ["active", "inactive"] } },
          { "in": "query", "name": "sort",     "schema": { "type": "string", "default": "name" } },
          { "in": "query", "name": "order",    "schema": { "type": "string", "enum": ["asc", "desc"], "default": "asc" } },
          { "in": "query", "name": "page",     "schema": { "type": "integer", "default": 1 } },
          { "in": "query", "name": "per_page", "schema": { "type": "integer", "default": 25, "maximum": 100 } }
        ],
        "responses": {
          "200": {
            "description": "Paginated OLT list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/OltDevice" } },
                    "meta": { "$ref": "#/components/schemas/PaginationMeta" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      },
      "post": {
        "tags": ["OLT Devices"],
        "summary": "Create OLT device",
        "description": "Creates a new OLT device. Requires `write:olt` scope for API key auth. Subject to plan OLT limit.",
        "operationId": "createOlt",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name", "vendor_slug", "firmware_slug", "host", "username", "password"],
                "properties": {
                  "name":             { "type": "string",  "maxLength": 100, "example": "OLT Jakarta Pusat" },
                  "vendor_slug":      { "type": "string",  "example": "hsgq" },
                  "firmware_slug":    { "type": "string",  "example": "v1014id" },
                  "host":             { "type": "string",  "maxLength": 100, "example": "192.168.1.1" },
                  "port":             { "type": "integer", "minimum": 1, "maximum": 65535, "default": 80, "example": 80 },
                  "username":         { "type": "string",  "maxLength": 100, "example": "admin" },
                  "password":         { "type": "string",  "example": "password123" },
                  "polling_interval": { "type": "integer", "minimum": 1, "maximum": 1440, "default": 5, "example": 5 },
                  "alert_enabled":    { "type": "boolean", "default": true }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OLT created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "data": { "$ref": "#/components/schemas/OltDevice" } }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": {
            "description": "Plan limit reached or insufficient scope",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": { "error": { "code": "PLAN_LIMIT_REACHED", "message": "OLT limit for your plan reached. Upgrade to add more." } }
              }
            }
          },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/olt/{id}": {
      "get": {
        "tags": ["OLT Devices"],
        "summary": "Get OLT device detail",
        "operationId": "getOlt",
        "parameters": [
          { "in": "path", "name": "id", "required": true, "schema": { "type": "integer" }, "example": 1 }
        ],
        "responses": {
          "200": {
            "description": "OLT detail",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "data": { "$ref": "#/components/schemas/OltDevice" } }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "put": {
        "tags": ["OLT Devices"],
        "summary": "Update OLT device",
        "description": "Partial update — only include fields you want to change. Requires `write:olt` scope.",
        "operationId": "updateOlt",
        "parameters": [
          { "in": "path", "name": "id", "required": true, "schema": { "type": "integer" }, "example": 1 }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name":             { "type": "string",  "maxLength": 100 },
                  "host":             { "type": "string",  "maxLength": 100 },
                  "port":             { "type": "integer", "minimum": 1, "maximum": 65535 },
                  "username":         { "type": "string",  "maxLength": 100 },
                  "password":         { "type": "string" },
                  "polling_interval": { "type": "integer", "minimum": 1, "maximum": 1440 },
                  "alert_enabled":    { "type": "boolean" },
                  "is_active":        { "type": "boolean" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OLT updated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "data": { "$ref": "#/components/schemas/OltDevice" } }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      },
      "delete": {
        "tags": ["OLT Devices"],
        "summary": "Soft delete OLT device",
        "description": "Soft-deletes the OLT (can be restored). Requires `delete:olt` scope and `X-Confirm-Delete: yes` header.",
        "operationId": "deleteOlt",
        "parameters": [
          { "in": "path", "name": "id", "required": true, "schema": { "type": "integer" }, "example": 1 },
          {
            "in": "header",
            "name": "X-Confirm-Delete",
            "required": true,
            "schema": { "type": "string", "enum": ["yes"] },
            "description": "Must be 'yes' to confirm the destructive action."
          }
        ],
        "responses": {
          "204": { "description": "OLT deleted" },
          "400": { "$ref": "#/components/responses/DeleteNotConfirmed" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/olt/{id}/restore": {
      "post": {
        "tags": ["OLT Devices"],
        "summary": "Restore soft-deleted OLT device",
        "description": "Restores a previously soft-deleted OLT. Returns 422 if the device is not currently deleted.",
        "operationId": "restoreOlt",
        "parameters": [
          { "in": "path", "name": "id", "required": true, "schema": { "type": "integer" }, "example": 1 }
        ],
        "responses": {
          "200": {
            "description": "OLT restored",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "data": { "$ref": "#/components/schemas/OltDevice" } }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": {
            "description": "OLT is not deleted",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": { "error": { "code": "NOT_DELETED", "message": "OLT is not deleted." } }
              }
            }
          }
        }
      }
    },
    "/olt/{id}/poll": {
      "post": {
        "tags": ["OLT Devices"],
        "summary": "Trigger manual OLT poll",
        "description": "Dispatches a polling job. Idempotent — returns `queued: false` if polled within the last minute.",
        "operationId": "pollOlt",
        "parameters": [
          { "in": "path", "name": "id", "required": true, "schema": { "type": "integer" }, "example": 1 }
        ],
        "responses": {
          "200": {
            "description": "Poll queued or skipped",
            "content": {
              "application/json": {
                "examples": {
                  "queued": {
                    "summary": "Job dispatched",
                    "value": { "data": { "queued": true } }
                  },
                  "skipped": {
                    "summary": "Skipped — polled recently",
                    "value": { "data": { "queued": false, "reason": "polled recently", "last_polled_at": "2026-05-17T10:00:00Z" } }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/olt/{id}/test": {
      "post": {
        "tags": ["OLT Devices"],
        "summary": "Test OLT connection",
        "description": "Performs a live connection test to the OLT using the configured driver. Does not poll or scrape ONT data.",
        "operationId": "testOltConnection",
        "parameters": [
          { "in": "path", "name": "id", "required": true, "schema": { "type": "integer" }, "example": 1 }
        ],
        "responses": {
          "200": {
            "description": "Test result",
            "content": {
              "application/json": {
                "examples": {
                  "success": {
                    "summary": "Connected",
                    "value": { "data": { "connected": true, "duration_ms": 420 } }
                  },
                  "failure": {
                    "summary": "Failed",
                    "value": { "data": { "connected": false, "error": "Connection refused", "duration_ms": 0 } }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/olt/{id}/onts": {
      "get": {
        "tags": ["OLT Devices"],
        "summary": "List ONTs on a specific OLT",
        "description": "Returns the latest snapshot per ONT SN for the given OLT, paginated.",
        "operationId": "listOltOnts",
        "parameters": [
          { "in": "path", "name": "id", "required": true, "schema": { "type": "integer" }, "example": 1 },
          { "in": "query", "name": "status",   "schema": { "type": "string", "enum": ["up", "down"] } },
          { "in": "query", "name": "page",     "schema": { "type": "integer", "default": 1 } },
          { "in": "query", "name": "per_page", "schema": { "type": "integer", "default": 25, "maximum": 100 } }
        ],
        "responses": {
          "200": {
            "description": "Paginated ONT list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/OntData" } },
                    "meta": { "$ref": "#/components/schemas/PaginationMeta" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/olt/{id}/history": {
      "get": {
        "tags": ["OLT Devices"],
        "summary": "OLT polling history (hourly buckets)",
        "description": "Returns hourly aggregated ONT counts for the given OLT within a time range. Useful for uptime charts.",
        "operationId": "getOltHistory",
        "parameters": [
          { "in": "path", "name": "id", "required": true, "schema": { "type": "integer" }, "example": 1 },
          {
            "in": "query", "name": "from", "required": false,
            "schema": { "type": "string", "format": "date-time" },
            "description": "Start of range (defaults to 24 hours ago)",
            "example": "2026-05-16T00:00:00Z"
          },
          {
            "in": "query", "name": "to", "required": false,
            "schema": { "type": "string", "format": "date-time" },
            "description": "End of range (defaults to now)",
            "example": "2026-05-17T00:00:00Z"
          }
        ],
        "responses": {
          "200": {
            "description": "Hourly aggregated history",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/OltHistoryBucket" } }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/onts": {
      "get": {
        "tags": ["ONT"],
        "summary": "List all ONTs (cross-OLT)",
        "description": "Returns the latest snapshot per ONT SN across all OLTs of the tenant. Supports filtering and pagination.",
        "operationId": "listOnts",
        "parameters": [
          { "in": "query", "name": "sn",       "schema": { "type": "string" },  "description": "Filter by serial number (partial match)" },
          { "in": "query", "name": "search",   "schema": { "type": "string" },  "description": "Filter by ONT name (partial match)" },
          { "in": "query", "name": "status",   "schema": { "type": "string", "enum": ["up", "down"] } },
          { "in": "query", "name": "olt_id",   "schema": { "type": "integer" }, "description": "Filter by specific OLT ID" },
          { "in": "query", "name": "page",     "schema": { "type": "integer", "default": 1 } },
          { "in": "query", "name": "per_page", "schema": { "type": "integer", "default": 25, "maximum": 100 } }
        ],
        "responses": {
          "200": {
            "description": "Paginated ONT list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/OntData" } },
                    "meta": { "$ref": "#/components/schemas/PaginationMeta" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/onts/{sn}": {
      "get": {
        "tags": ["ONT"],
        "summary": "Get latest ONT snapshot",
        "description": "Returns the most recent snapshot for the given serial number. Use `olt_id` to disambiguate if the SN appears on multiple OLTs.",
        "operationId": "getOnt",
        "parameters": [
          { "in": "path",  "name": "sn",     "required": true,  "schema": { "type": "string" }, "example": "HWTC1A2B3C4D" },
          { "in": "query", "name": "olt_id", "required": false, "schema": { "type": "integer" }, "description": "Disambiguate when SN exists on multiple OLTs" }
        ],
        "responses": {
          "200": {
            "description": "ONT latest snapshot",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "data": { "$ref": "#/components/schemas/OntData" } }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "tags": ["ONT"],
        "summary": "Delete all ONT snapshots",
        "description": "Permanently deletes all snapshots for this SN on the specified OLT. Requires `delete:ont` scope and `X-Confirm-Delete: yes` header.",
        "operationId": "deleteOnt",
        "parameters": [
          { "in": "path", "name": "sn", "required": true, "schema": { "type": "string" }, "example": "HWTC1A2B3C4D" },
          {
            "in": "header",
            "name": "X-Confirm-Delete",
            "required": true,
            "schema": { "type": "string", "enum": ["yes"] },
            "description": "Must be 'yes' to confirm."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["olt_id"],
                "properties": {
                  "olt_id": { "type": "integer", "example": 1, "description": "ID of the OLT this ONT belongs to" }
                }
              }
            }
          }
        },
        "responses": {
          "204": { "description": "ONT snapshots deleted" },
          "400": { "$ref": "#/components/responses/DeleteNotConfirmed" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/onts/{sn}/history": {
      "get": {
        "tags": ["ONT"],
        "summary": "Get ONT snapshot history",
        "description": "Returns paginated time-series of snapshots for the given SN. Useful for charting signal quality over time.",
        "operationId": "getOntHistory",
        "parameters": [
          { "in": "path",  "name": "sn",       "required": true,  "schema": { "type": "string" }, "example": "HWTC1A2B3C4D" },
          {
            "in": "query", "name": "from", "required": false,
            "schema": { "type": "string", "format": "date-time" },
            "description": "Start of range (defaults to 7 days ago)",
            "example": "2026-05-10T00:00:00Z"
          },
          {
            "in": "query", "name": "to", "required": false,
            "schema": { "type": "string", "format": "date-time" },
            "description": "End of range (defaults to now)",
            "example": "2026-05-17T00:00:00Z"
          },
          { "in": "query", "name": "olt_id",   "required": false, "schema": { "type": "integer" } },
          { "in": "query", "name": "page",     "schema": { "type": "integer", "default": 1 } },
          { "in": "query", "name": "per_page", "schema": { "type": "integer", "default": 25, "maximum": 100 } }
        ],
        "responses": {
          "200": {
            "description": "Snapshot history",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/OntSnapshot" } },
                    "meta": { "$ref": "#/components/schemas/PaginationMeta" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/onts/{sn}/reboot": {
      "post": {
        "tags": ["ONT"],
        "summary": "Reboot ONT",
        "description": "Queues a reboot command for the ONT via the OLT driver. Requires `write:ont` scope. A follow-up poll is also dispatched.",
        "operationId": "rebootOnt",
        "parameters": [
          { "in": "path", "name": "sn", "required": true, "schema": { "type": "string" }, "example": "HWTC1A2B3C4D" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["olt_id"],
                "properties": {
                  "olt_id": { "type": "integer", "example": 1, "description": "OLT device ID that manages this ONT" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reboot queued",
            "content": {
              "application/json": {
                "example": { "data": { "queued": true, "action": "reboot", "sn": "HWTC1A2B3C4D" } }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/onts/{sn}/rename": {
      "post": {
        "tags": ["ONT"],
        "summary": "Rename ONT",
        "description": "Updates the display name for all snapshots of this ONT on the specified OLT. Requires `write:ont` scope.",
        "operationId": "renameOnt",
        "parameters": [
          { "in": "path", "name": "sn", "required": true, "schema": { "type": "string" }, "example": "HWTC1A2B3C4D" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["olt_id", "new_name"],
                "properties": {
                  "olt_id":   { "type": "integer", "example": 1 },
                  "new_name": { "type": "string",  "maxLength": 100, "example": "Customer Budi - Cipanas" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "ONT renamed",
            "content": {
              "application/json": {
                "example": { "data": { "renamed": true, "sn": "HWTC1A2B3C4D", "new_name": "Customer Budi - Cipanas" } }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/vendors": {
      "get": {
        "tags": ["Vendor"],
        "summary": "List OLT vendors",
        "description": "Returns all supported OLT vendors. Use vendor slug when creating OLT devices.",
        "operationId": "listVendors",
        "responses": {
          "200": {
            "description": "Vendor list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/OltVendor" } }
                  }
                },
                "example": {
                  "data": [
                    { "id": 1, "name": "HSGQ", "slug": "hsgq" },
                    { "id": 2, "name": "ZTE",  "slug": "zte" }
                  ]
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/vendors/{slug}/firmwares": {
      "get": {
        "tags": ["Vendor"],
        "summary": "List firmwares for a vendor",
        "description": "Returns all active firmware/driver entries for the given vendor slug. Use firmware slug when creating OLT devices.",
        "operationId": "listVendorFirmwares",
        "parameters": [
          { "in": "path", "name": "slug", "required": true, "schema": { "type": "string" }, "example": "hsgq" }
        ],
        "responses": {
          "200": {
            "description": "Firmware list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/OltFirmware" } }
                  }
                },
                "example": {
                  "data": [
                    { "id": 1, "name": "V1014 ID", "version": null, "type": "gpon", "driver_class": "App\\Services\\Olt\\Drivers\\HsgqGpon\\V1014IdDriver", "slug": "v1014id" }
                  ]
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/telegram-bots": {
      "get": {
        "tags": ["Telegram Bots"],
        "summary": "List Telegram bot configurations",
        "description": "Returns all Telegram bot configurations for the authenticated tenant. Bot token is never exposed.",
        "operationId": "listTelegramBots",
        "responses": {
          "200": {
            "description": "Bot list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/TelegramBot" } }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "post": {
        "tags": ["Telegram Bots"],
        "summary": "Create or replace bot configuration",
        "description": "Creates or replaces the tenant's Telegram bot configuration (upsert — one bot per tenant). Alert status is set to `off` on creation; enable it via PUT.",
        "operationId": "createTelegramBot",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["bot_token", "chat_ids"],
                "properties": {
                  "bot_token":              { "type": "string", "example": "7123456789:AAH..." },
                  "chat_ids":               {
                    "type": "array",
                    "minItems": 1,
                    "items": { "type": "string" },
                    "example": ["-100123456789", "88765432"]
                  },
                  "alert_types":            {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": ["ont_down", "ont_up", "olt_unreachable", "olt_recovered", "weak_signal", "daily_summary"]
                    },
                    "default": ["ont_down", "olt_unreachable"]
                  },
                  "weak_signal_threshold":  { "type": "number", "format": "float", "minimum": -50, "maximum": 0, "default": -28.0 },
                  "alert_interval_minutes": { "type": "integer", "minimum": 1, "maximum": 1440, "default": 5 }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Bot created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "data": { "$ref": "#/components/schemas/TelegramBot" } }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/telegram-bots/{id}": {
      "put": {
        "tags": ["Telegram Bots"],
        "summary": "Update bot configuration",
        "description": "Partial update for the bot. Use `alert_status: 'on'` to enable alerts.",
        "operationId": "updateTelegramBot",
        "parameters": [
          { "in": "path", "name": "id", "required": true, "schema": { "type": "integer" }, "example": 1 }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "bot_token":              { "type": "string" },
                  "chat_ids":               { "type": "array", "items": { "type": "string" } },
                  "alert_types":            {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": ["ont_down", "ont_up", "olt_unreachable", "olt_recovered", "weak_signal", "daily_summary"]
                    }
                  },
                  "alert_status":           { "type": "string", "enum": ["on", "off"] },
                  "weak_signal_threshold":  { "type": "number", "format": "float", "minimum": -50, "maximum": 0 },
                  "alert_interval_minutes": { "type": "integer", "minimum": 1, "maximum": 1440 }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Bot updated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "data": { "$ref": "#/components/schemas/TelegramBot" } }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      },
      "delete": {
        "tags": ["Telegram Bots"],
        "summary": "Delete bot configuration",
        "description": "Deletes the bot configuration. Requires `X-Confirm-Delete: yes` header.",
        "operationId": "deleteTelegramBot",
        "parameters": [
          { "in": "path", "name": "id", "required": true, "schema": { "type": "integer" }, "example": 1 },
          {
            "in": "header",
            "name": "X-Confirm-Delete",
            "required": true,
            "schema": { "type": "string", "enum": ["yes"] }
          }
        ],
        "responses": {
          "204": { "description": "Bot deleted" },
          "400": { "$ref": "#/components/responses/DeleteNotConfirmed" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/telegram-bots/{id}/test": {
      "post": {
        "tags": ["Telegram Bots"],
        "summary": "Send test alert",
        "description": "Dispatches a test message to all configured chat IDs for this bot. Returns the number of recipients.",
        "operationId": "testTelegramBot",
        "parameters": [
          { "in": "path", "name": "id", "required": true, "schema": { "type": "integer" }, "example": 1 }
        ],
        "responses": {
          "200": {
            "description": "Test message dispatched",
            "content": {
              "application/json": {
                "example": { "data": { "sent": true, "recipients": 2 } }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/subscription": {
      "get": {
        "tags": ["Stats"],
        "summary": "Get active subscription",
        "description": "Returns the tenant's current active subscription with plan details.",
        "operationId": "getSubscription",
        "responses": {
          "200": {
            "description": "Active subscription",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "data": { "$ref": "#/components/schemas/Subscription" } }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": {
            "description": "No active subscription found",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": { "error": { "code": "RESOURCE_NOT_FOUND", "message": "No active subscription" } }
              }
            }
          }
        }
      }
    },
    "/stats/dashboard": {
      "get": {
        "tags": ["Stats"],
        "summary": "Dashboard aggregated stats",
        "description": "Returns summary ONT counts for the tenant. Cached for 60 seconds.",
        "operationId": "getDashboardStats",
        "responses": {
          "200": {
            "description": "Dashboard stats",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "total_olts":    { "type": "integer", "example": 3 },
                        "online_onts":   { "type": "integer", "example": 120 },
                        "offline_onts":  { "type": "integer", "example": 8 }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/stats/usage": {
      "get": {
        "tags": ["Stats"],
        "summary": "Subscription usage",
        "description": "Returns OLT usage vs. plan limits.",
        "operationId": "getUsageStats",
        "responses": {
          "200": {
            "description": "Usage info",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "olt": {
                          "type": "object",
                          "properties": {
                            "used":  { "type": "integer", "example": 3 },
                            "limit": { "type": "integer", "example": 5 }
                          }
                        },
                        "plan": { "type": "string", "example": "basic" }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/stats/performance": {
      "get": {
        "tags": ["Stats"],
        "summary": "OLT performance summary",
        "description": "Returns last-poll performance data for each active OLT: status, duration, ONT counts.",
        "operationId": "getPerformanceStats",
        "responses": {
          "200": {
            "description": "Per-OLT performance",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "olt_id":         { "type": "integer", "example": 1 },
                          "name":           { "type": "string",  "example": "OLT Jakarta Pusat" },
                          "status":         { "type": "string",  "enum": ["ok", "unreachable", "scrape_failed", "no_driver", "unknown"] },
                          "last_polled_at": { "type": "string",  "format": "date-time", "nullable": true },
                          "duration_ms":    { "type": "integer", "nullable": true, "example": 3200 },
                          "total_ont":      { "type": "integer", "example": 128 },
                          "online":         { "type": "integer", "example": 120 }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/audit-logs": {
      "get": {
        "tags": ["Audit Logs"],
        "summary": "List audit logs",
        "description": "Returns paginated audit trail. **Requires `super_admin` role** — returns 403 for all other users.",
        "operationId": "listAuditLogs",
        "parameters": [
          { "in": "query", "name": "actor_type",    "schema": { "type": "string" },  "example": "user" },
          { "in": "query", "name": "action",        "schema": { "type": "string", "enum": ["create", "update", "delete", "login", "logout"] } },
          { "in": "query", "name": "resource_type", "schema": { "type": "string" },  "example": "olt_device" },
          { "in": "query", "name": "tenant_id",     "schema": { "type": "string", "format": "uuid" } },
          {
            "in": "query", "name": "from",
            "schema": { "type": "string", "format": "date-time" },
            "example": "2026-05-01T00:00:00Z"
          },
          {
            "in": "query", "name": "to",
            "schema": { "type": "string", "format": "date-time" },
            "example": "2026-05-17T23:59:59Z"
          },
          { "in": "query", "name": "page",     "schema": { "type": "integer", "default": 1 } },
          { "in": "query", "name": "per_page", "schema": { "type": "integer", "default": 25, "maximum": 100 } }
        ],
        "responses": {
          "200": {
            "description": "Paginated audit log",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/AuditLog" } },
                    "meta": { "$ref": "#/components/schemas/PaginationMeta" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    }
  }
}
