{
  "openapi": "3.0.3",
  "info": {
    "title": "DMZ Edge Status API",
    "version": "1.0.0",
    "description": "DMZ 엣지(nginx reverse proxy)의 인증서 현황과 배포 적용 상태를 제공하는 읽기 전용 API. 데이터는 배포 옵저버(NginxGitDeploy)가 1분 주기로 갱신하는 정적 JSON 이며, 내부 토폴로지(업스트림 IP/포트)는 포함하지 않는다."
  },
  "servers": [
    { "url": "https://dmz.lumir.space", "description": "DMZ 엣지" }
  ],
  "tags": [
    { "name": "status", "description": "통합 상태" },
    { "name": "certificates", "description": "TLS 인증서" },
    { "name": "deployment", "description": "배포/컨테이너" }
  ],
  "paths": {
    "/api/health": {
      "get": {
        "tags": ["status"],
        "summary": "헬스체크",
        "description": "모니터링용 경량 엔드포인트. 컨테이너가 떠 있고 배포가 원격과 동기화돼 있으면 ok, 아니면 degraded.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Health" },
                "example": { "status": "ok", "generatedAt": "2026-09-15T12:00:00+09:00", "server": "T21001" }
              }
            }
          }
        }
      }
    },
    "/api/status": {
      "get": {
        "tags": ["status"],
        "summary": "통합 상태",
        "description": "인증서·도메인·배포·컨테이너를 한 번에 반환한다.",
        "responses": {
          "200": {
            "description": "OK",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Status" } } }
          }
        }
      }
    },
    "/api/certificates": {
      "get": {
        "tags": ["certificates"],
        "summary": "인증서 현황",
        "description": "Let's Encrypt(자동갱신)와 상용 인증서를 모두 포함한다. 만료일 임박 순으로 정렬된다.",
        "responses": {
          "200": {
            "description": "OK",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CertificateList" } } }
          }
        }
      }
    },
    "/api/domains": {
      "get": {
        "tags": ["status"],
        "summary": "도메인 목록",
        "description": "nginx.conf 에 설정된 공개 도메인과 각 도메인이 쓰는 인증서 이름. tls=false 는 :80 ACME 목록에만 있고 HTTPS server 블록이 없는 상태를 뜻한다.",
        "responses": {
          "200": {
            "description": "OK",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DomainList" } } }
          }
        }
      }
    },
    "/api/deployment": {
      "get": {
        "tags": ["deployment"],
        "summary": "배포 적용 상태",
        "description": "현재 반영된 커밋, 원격과의 동기화 여부, 마지막 자동 배포 시각, 실행 중 컨테이너.",
        "responses": {
          "200": {
            "description": "OK",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Deployment" } } }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Health": {
        "type": "object",
        "properties": {
          "status": { "type": "string", "enum": ["ok", "degraded"] },
          "generatedAt": { "type": "string", "format": "date-time" },
          "server": { "type": "string" }
        }
      },
      "Certificate": {
        "type": "object",
        "properties": {
          "name": { "type": "string", "description": "인증서 이름(certbot live 디렉터리명 또는 파일명)" },
          "source": { "type": "string", "enum": ["letsencrypt", "commercial"] },
          "domains": { "type": "array", "items": { "type": "string" }, "description": "SAN 목록" },
          "issuer": { "type": "string" },
          "notBefore": { "type": "string", "format": "date-time" },
          "notAfter": { "type": "string", "format": "date-time" },
          "daysRemaining": { "type": "integer", "description": "음수면 이미 만료" },
          "status": { "type": "string", "enum": ["valid", "expiring_soon", "expired"], "description": "expiring_soon 기준은 21일" },
          "autoRenew": { "type": "boolean", "description": "Let's Encrypt 만 true (12시간 주기 자동갱신)" }
        }
      },
      "CertificateList": {
        "type": "object",
        "properties": {
          "generatedAt": { "type": "string", "format": "date-time" },
          "count": { "type": "integer" },
          "expiringSoon": { "type": "integer", "description": "expiring_soon + expired 합계" },
          "certificates": { "type": "array", "items": { "$ref": "#/components/schemas/Certificate" } }
        }
      },
      "Domain": {
        "type": "object",
        "properties": {
          "domain": { "type": "string" },
          "tls": { "type": "boolean", "description": "HTTPS server 블록 존재 여부" },
          "certificate": { "type": "string", "nullable": true }
        }
      },
      "DomainList": {
        "type": "object",
        "properties": {
          "generatedAt": { "type": "string", "format": "date-time" },
          "count": { "type": "integer" },
          "domains": { "type": "array", "items": { "$ref": "#/components/schemas/Domain" } }
        }
      },
      "Container": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "state": { "type": "string" },
          "status": { "type": "string" }
        }
      },
      "DeploymentInfo": {
        "type": "object",
        "properties": {
          "commit": { "type": "string", "description": "현재 반영된 커밋 (short)" },
          "commitFull": { "type": "string" },
          "subject": { "type": "string" },
          "commitDate": { "type": "string", "format": "date-time" },
          "remoteCommit": { "type": "string", "description": "origin/main (short)" },
          "inSync": { "type": "boolean", "description": "false 면 아직 반영되지 않은 커밋이 있다" },
          "workingTreeClean": { "type": "boolean", "description": "false 면 서버 로컬 수정 때문에 자동 배포가 중단된 상태" },
          "lastDeployAt": { "type": "string", "format": "date-time", "nullable": true },
          "mode": { "type": "string" }
        }
      },
      "Deployment": {
        "type": "object",
        "properties": {
          "generatedAt": { "type": "string", "format": "date-time" },
          "deployment": { "$ref": "#/components/schemas/DeploymentInfo" },
          "containers": { "type": "array", "items": { "$ref": "#/components/schemas/Container" } }
        }
      },
      "Status": {
        "type": "object",
        "properties": {
          "generatedAt": { "type": "string", "format": "date-time" },
          "server": { "type": "string" },
          "summary": {
            "type": "object",
            "properties": {
              "domains": { "type": "integer" },
              "certificates": { "type": "integer" },
              "expiringSoon": { "type": "integer" },
              "deploymentInSync": { "type": "boolean" },
              "containersRunning": { "type": "integer" }
            }
          },
          "deployment": { "$ref": "#/components/schemas/DeploymentInfo" },
          "certificates": { "type": "array", "items": { "$ref": "#/components/schemas/Certificate" } },
          "domains": { "type": "array", "items": { "$ref": "#/components/schemas/Domain" } },
          "containers": { "type": "array", "items": { "$ref": "#/components/schemas/Container" } }
        }
      }
    }
  }
}
