{
  "openapi": "3.1.0",
  "info": {
    "title": "FOWOCO Server API",
    "description": "E-9 외국인근로자 고용 사업장의 HR 업무카드와 승인 Workflow API",
    "version": "0.1.0"
  },
  "tags": [
    {
      "name": "Health",
      "description": "서버 실행 상태 확인"
    },
    {
      "name": "Task",
      "description": "업무카드·체크리스트·상태 전이"
    },
    {
      "name": "Authentication",
      "description": "사업장 회원가입·로그인과 현재 인증 정보"
    },
    {
      "name": "Approval",
      "description": "업무 승인·반려·제출·증빙·완료"
    },
    {
      "name": "Audit",
      "description": "업무 활동 이력과 사업장 감사 조회"
    },
    {
      "name": "Workflow Catalog",
      "description": "Knowledge release에서 투영한 업무 정의 조회"
    },
    {
      "name": "Worker",
      "description": "근로자 기본정보 등록·조회·수정"
    },
    {
      "name": "Worker Document",
      "description": "근로자 서류 상태 등록·수정"
    }
  ],
  "paths": {
    "/api/v1/workers": {
      "get": {
        "tags": [
          "Worker"
        ],
        "summary": "근로자 목록 조회",
        "description": "JWT 사업장에 소속된 근로자 요약 목록을 페이지로 조회합니다.",
        "operationId": "listWorkers",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "근무 상태 필터",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "ACTIVE",
                "ON_LEAVE",
                "RESIGNED",
                "TERMINATED"
              ]
            }
          },
          {
            "name": "language",
            "in": "query",
            "description": "선호 언어 필터",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expiryBefore",
            "in": "query",
            "description": "체류 만료일 이전 필터",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "페이지 번호 (0부터 시작)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "minimum": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "description": "페이지당 항목 수 (1~100)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 20,
              "maximum": 100,
              "minimum": 1
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "조회 성공",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkerPageResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "tags": [
          "Worker"
        ],
        "summary": "근로자 등록",
        "description": "업무에 필요한 최소 개인정보로 근로자를 등록합니다. 여권번호·외국인등록번호·전화번호·계좌번호는 이 API로 수집하지 않습니다.",
        "operationId": "registerWorker",
        "parameters": [
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WorkerCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "등록 성공",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkerResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/workers/{workerId}/documents": {
      "post": {
        "tags": [
          "Worker Document"
        ],
        "summary": "서류 상태 등록",
        "description": "근로자 서류의 제출·유효기간·제출처 상태를 등록합니다.",
        "operationId": "registerWorkerDocument",
        "parameters": [
          {
            "name": "workerId",
            "in": "path",
            "description": "근로자 ID",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WorkerDocumentCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "등록 성공",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkerDocumentResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/tasks": {
      "get": {
        "tags": [
          "Task"
        ],
        "summary": "업무카드 목록 조회",
        "operationId": "listTasks",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "DRAFT",
                "NEEDS_INFO",
                "READY_FOR_REVIEW",
                "APPROVED",
                "WAITING_WORKER",
                "WAITING_EXTERNAL",
                "COMPLETED",
                "CANCELLED"
              ]
            }
          },
          {
            "name": "taskType",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "RECONTRACT",
                "EMPLOYMENT_PERIOD_EXTENSION",
                "STAY_PERIOD_EXTENSION"
              ]
            }
          },
          {
            "name": "workerId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "dueFrom",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "dueTo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "keyword",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "minimum": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 20,
              "maximum": 100,
              "minimum": 1
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "사업장 범위 업무카드 목록",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskPageResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "tags": [
          "Task"
        ],
        "summary": "수동 업무카드 생성",
        "operationId": "createTask",
        "parameters": [
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTaskRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "업무카드 생성",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskDetailResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/tasks/{taskId}/reject": {
      "post": {
        "tags": [
          "Approval"
        ],
        "summary": "업무 반려",
        "description": "승인 요청을 종료하고 Task를 DRAFT로 되돌립니다.",
        "operationId": "rejectTask",
        "parameters": [
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RejectTaskRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "반려 완료",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApprovalResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/tasks/{taskId}/external-submissions": {
      "post": {
        "tags": [
          "Approval"
        ],
        "summary": "외부기관 제출 기록",
        "description": "서버가 기관에 대신 제출하지 않고 HR이 수행한 제출 결과만 기록합니다.",
        "operationId": "recordExternalSubmission",
        "parameters": [
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExternalSubmissionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "외부 제출 기록 생성",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskActionResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/tasks/{taskId}/evidence": {
      "post": {
        "tags": [
          "Approval"
        ],
        "summary": "업무 증빙 기록",
        "operationId": "recordTaskEvidence",
        "parameters": [
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EvidenceRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "증빙 기록 생성",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskActionResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/tasks/{taskId}/complete": {
      "post": {
        "tags": [
          "Approval"
        ],
        "summary": "업무 완료",
        "operationId": "completeTask",
        "parameters": [
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompleteTaskRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "업무 완료",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskActionResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/tasks/{taskId}/cancel": {
      "post": {
        "tags": [
          "Task"
        ],
        "summary": "업무카드 취소",
        "operationId": "cancelTask",
        "parameters": [
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CancelTaskRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "취소된 업무카드",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskDetailResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/tasks/{taskId}/approve": {
      "post": {
        "tags": [
          "Approval"
        ],
        "summary": "업무 승인",
        "operationId": "approveTask",
        "parameters": [
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApproveTaskRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "현재 Task version 승인",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApprovalResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/tasks/{taskId}/approval-requests": {
      "post": {
        "tags": [
          "Approval"
        ],
        "summary": "업무 승인 요청",
        "description": "필수정보를 확인하고 AI 원본·HR 최종본·출처 버전을 snapshot으로 고정합니다.",
        "operationId": "requestTaskApproval",
        "parameters": [
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalRequestBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "승인 요청 생성",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApprovalResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/auth/signup": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "사업장과 최초 관리자 회원가입",
        "description": "사업장과 최초 ADMIN 계정을 하나의 transaction으로 생성합니다. 자동 로그인하거나 Token을 발급하지 않으며, 성공 후 기존 로그인 API를 사용합니다.",
        "operationId": "signup",
        "parameters": [
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SignupRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "사업장과 최초 ADMIN 계정 생성 성공",
            "headers": {
              "Cache-Control": {
                "description": "회원가입 응답 저장 방지",
                "style": "simple",
                "schema": {
                  "type": "string",
                  "example": "no-store"
                }
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Pragma": {
                "description": "구형 캐시의 회원가입 응답 저장 방지",
                "style": "simple",
                "schema": {
                  "type": "string",
                  "example": "no-cache"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SignupResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "409": {
            "$ref": "#/components/responses/EmailAlreadyRegistered"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/v1/auth/refresh": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Access Token 재발급",
        "description": "HttpOnly 쿠키의 Refresh Token을 한 번 사용하고 새 Access Token과 새 Refresh Token 쿠키로 회전합니다. 요청 본문과 Bearer Access Token은 사용하지 않습니다. 누락·만료·폐기·재사용은 같은 401로 응답하며 Client는 재발급 요청을 한 번에 하나만 보냅니다.",
        "operationId": "refreshAccessToken",
        "parameters": [
          {
            "name": "fowoco_refresh_token",
            "in": "cookie",
            "description": "로그인 또는 직전 재발급 응답에서 받은 HttpOnly Refresh Token 쿠키",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "토큰 회전 성공",
            "headers": {
              "Cache-Control": {
                "description": "토큰 응답 저장 방지",
                "style": "simple",
                "schema": {
                  "type": "string",
                  "example": "no-store"
                }
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Set-Cookie": {
                "$ref": "#/components/headers/RefreshTokenCookie",
                "style": "simple"
              },
              "Pragma": {
                "description": "구형 캐시의 토큰 응답 저장 방지",
                "style": "simple",
                "schema": {
                  "type": "string",
                  "example": "no-cache"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RefreshResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/InvalidRefreshToken"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "refreshCookie": []
          }
        ]
      }
    },
    "/api/v1/auth/logout": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "로그아웃",
        "description": "Refresh Token 묶음을 폐기하고 쿠키를 삭제합니다. 요청 본문과 Bearer Access Token은 사용하지 않으며, 토큰이 없거나 이미 폐기되었어도 같은 204로 응답합니다. 기존 Access Token은 현재 기본 설정에서 만료까지 최대 15분간 유효하므로 Client가 즉시 삭제해야 합니다.",
        "operationId": "logout",
        "parameters": [
          {
            "name": "fowoco_refresh_token",
            "in": "cookie",
            "description": "있으면 해당 토큰 묶음을 폐기합니다. 없어도 로그아웃은 204로 성공합니다.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "로그아웃 처리 완료",
            "headers": {
              "Cache-Control": {
                "description": "로그아웃 응답 저장 방지",
                "style": "simple",
                "schema": {
                  "type": "string",
                  "example": "no-store"
                }
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Set-Cookie": {
                "$ref": "#/components/headers/ExpiredRefreshTokenCookie",
                "style": "simple"
              },
              "Pragma": {
                "description": "구형 캐시의 로그아웃 응답 저장 방지",
                "style": "simple",
                "schema": {
                  "type": "string",
                  "example": "no-cache"
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/v1/auth/login": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "사업장 사용자 로그인",
        "description": "이메일과 비밀번호를 검증해 Access Token을 응답 본문에, Refresh Token을 HttpOnly 쿠키에 발급합니다. 실패 원인은 하나의 메시지로 통일합니다.",
        "operationId": "login",
        "parameters": [
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "로그인 성공",
            "headers": {
              "Cache-Control": {
                "description": "토큰 응답 저장 방지",
                "style": "simple",
                "schema": {
                  "type": "string",
                  "example": "no-store"
                }
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Set-Cookie": {
                "$ref": "#/components/headers/RefreshTokenCookie",
                "style": "simple"
              },
              "Pragma": {
                "description": "구형 캐시의 토큰 응답 저장 방지",
                "style": "simple",
                "schema": {
                  "type": "string",
                  "example": "no-cache"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoginResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/InvalidCredentials"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/v1/workers/{workerId}": {
      "get": {
        "tags": [
          "Worker"
        ],
        "summary": "근로자 상세 조회",
        "description": "근로자 기본정보와 체류·계약기간, 서류 상태 요약을 조회합니다. 타 사업장 소속 근로자 ID는 404로 응답합니다.",
        "operationId": "getWorkerDetail",
        "parameters": [
          {
            "name": "workerId",
            "in": "path",
            "description": "근로자 ID",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "조회 성공",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkerResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "tags": [
          "Worker"
        ],
        "summary": "근로자 수정",
        "description": "근무상태·언어·체류일·계약기간을 부분 수정합니다. expected_version이 현재 값과 다르면 409로 응답합니다.",
        "operationId": "patchWorker",
        "parameters": [
          {
            "name": "workerId",
            "in": "path",
            "description": "근로자 ID",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WorkerPatchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "수정 성공",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkerResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "409": {
            "description": "expected_version이 현재 값과 달라 다른 사용자의 수정과 충돌함. OpenApiConfig에 공통 Conflict 응답이 아직 없어 인라인으로 정의함",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/workers/{workerId}/documents/{documentId}": {
      "patch": {
        "tags": [
          "Worker Document"
        ],
        "summary": "서류 상태 수정",
        "description": "서류 제출·검증·만료 상태와 유효기간을 수정합니다. expected_version이 현재 값과 다르면 409로 응답합니다.",
        "operationId": "patchWorkerDocument",
        "parameters": [
          {
            "name": "workerId",
            "in": "path",
            "description": "근로자 ID",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "documentId",
            "in": "path",
            "description": "서류 ID",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WorkerDocumentPatchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "수정 성공",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkerDocumentResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "409": {
            "description": "expected_version 충돌. OpenApiConfig에 공통 Conflict 응답이 아직 없어 인라인으로 정의함",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/tasks/{taskId}": {
      "get": {
        "tags": [
          "Task"
        ],
        "summary": "업무카드 상세 조회",
        "operationId": "getTask",
        "parameters": [
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "업무카드와 체크리스트",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskDetailResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "tags": [
          "Task"
        ],
        "summary": "업무카드 내용 수정",
        "description": "상태를 직접 받지 않으며 중요값 변경 시 기존 승인을 무효화합니다.",
        "operationId": "updateTask",
        "parameters": [
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTaskRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "수정된 업무카드",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskDetailResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/tasks/{taskId}/checklist-items/{itemId}": {
      "patch": {
        "tags": [
          "Task"
        ],
        "summary": "체크리스트 항목 수정",
        "operationId": "updateTaskChecklistItem",
        "parameters": [
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "itemId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateChecklistItemRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "체크리스트와 재평가된 업무 상태",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskDetailResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/health": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "서버 상태 확인",
        "description": "인증 없이 서버가 요청을 받을 수 있는지 확인합니다.",
        "operationId": "health",
        "parameters": [
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "정상",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "example": "OK"
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/v1/workflow-catalogs": {
      "get": {
        "tags": [
          "Workflow Catalog"
        ],
        "summary": "활성 Workflow Catalog 조회",
        "description": "Server가 검증하고 고정한 Knowledge projection과 source version을 반환합니다.",
        "operationId": "getActiveWorkflowCatalog",
        "parameters": [
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowCatalogResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/tasks/{taskId}/activities": {
      "get": {
        "tags": [
          "Audit"
        ],
        "summary": "업무 활동 타임라인",
        "description": "내부 감사 기록에서 화면에 안전하게 표시할 필드만 시간순으로 반환합니다.",
        "operationId": "getTaskActivities",
        "parameters": [
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "업무 활동 목록",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AuditEventResponse"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/auth/me": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "현재 인증 사용자 확인",
        "description": "검증된 Access Token에서 user_id, company_id, roles만 반환합니다.",
        "operationId": "getCurrentActor",
        "parameters": [
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "현재 인증 사용자",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CurrentActorResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/audit-events": {
      "get": {
        "tags": [
          "Audit"
        ],
        "summary": "사업장 감사 이벤트 검색",
        "description": "ADMIN만 자신의 사업장 범위에서 필터와 불투명 cursor로 검색할 수 있습니다.",
        "operationId": "searchAuditEvents",
        "parameters": [
          {
            "name": "actor_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "HR_USER",
                "WORKER_LINK",
                "AI_AGENT",
                "SYSTEM_RULE"
              ]
            }
          },
          {
            "name": "action",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "TASK_CREATED",
                "TASK_UPDATED",
                "CHECKLIST_ITEM_UPDATED",
                "TASK_CANCELLED",
                "APPROVAL_REQUESTED",
                "TASK_APPROVED",
                "TASK_REJECTED",
                "APPROVAL_INVALIDATED",
                "EXTERNAL_SUBMISSION_RECORDED",
                "EVIDENCE_RECORDED",
                "TASK_COMPLETED"
              ]
            }
          },
          {
            "name": "target_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "TASK",
                "APPROVAL_REQUEST",
                "EXTERNAL_SUBMISSION",
                "EVIDENCE"
              ]
            }
          },
          {
            "name": "target_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "trace_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{32}$"
            }
          },
          {
            "name": "created_from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "직전 응답의 next_cursor. 내용을 해석하거나 수정하지 않습니다.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 50,
              "maximum": 100,
              "minimum": 1
            }
          },
          {
            "name": "X-Request-Id",
            "in": "header",
            "description": "생략하면 서버가 생성하며 응답 헤더와 오류 본문에 반환합니다.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "감사 이벤트 페이지",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditPageResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "ApiErrorResponse": {
        "type": "object",
        "properties": {
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "type": "integer",
            "format": "int32"
          },
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "request_id": {
            "type": "string"
          },
          "field_errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FieldErrorResponse"
            }
          }
        }
      },
      "WorkerCreateRequest": {
        "type": "object",
        "description": "근로자 등록 요청. 여권번호·외국인등록번호·전화번호·계좌번호는 이 API로 수집하지 않습니다.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "화면 표시용 근로자 이름",
            "example": "응웬반A",
            "maxLength": 120,
            "minLength": 0
          },
          "nationality_code": {
            "type": "string",
            "description": "국적 코드",
            "example": "VN",
            "maxLength": 10,
            "minLength": 0
          },
          "preferred_language": {
            "type": "string",
            "description": "선호 언어",
            "example": "vi",
            "maxLength": 20,
            "minLength": 0
          },
          "stay_expiry_date": {
            "type": "string",
            "format": "date",
            "description": "체류 만료일",
            "example": "2027-03-01"
          },
          "contract_start_date": {
            "type": "string",
            "format": "date",
            "description": "계약 시작일",
            "example": "2026-01-01"
          },
          "contract_end_date": {
            "type": "string",
            "format": "date",
            "description": "계약 종료일. contract_start_date보다 빠를 수 없습니다.",
            "example": "2027-12-31"
          }
        },
        "required": [
          "display_name"
        ]
      },
      "WorkerResponse": {
        "type": "object",
        "description": "근로자 상세 응답. legal_name, phone 등 worker_sensitive_data 필드는 포함하지 않습니다.",
        "properties": {
          "worker_id": {
            "type": "string",
            "format": "uuid",
            "description": "근로자 ID"
          },
          "company_id": {
            "type": "string",
            "format": "uuid",
            "description": "소속 사업장 ID"
          },
          "display_name": {
            "type": "string",
            "description": "화면 표시용 근로자 이름",
            "example": "응웬반A"
          },
          "nationality_code": {
            "type": "string",
            "description": "국적 코드",
            "example": "VN"
          },
          "preferred_language": {
            "type": "string",
            "description": "선호 언어",
            "example": "vi"
          },
          "work_status": {
            "type": "string",
            "description": "근무 상태",
            "enum": [
              "ACTIVE",
              "ON_LEAVE",
              "RESIGNED",
              "TERMINATED"
            ]
          },
          "stay_expiry_date": {
            "type": "string",
            "format": "date",
            "description": "체류 만료일"
          },
          "contract_start_date": {
            "type": "string",
            "format": "date",
            "description": "계약 시작일"
          },
          "contract_end_date": {
            "type": "string",
            "format": "date",
            "description": "계약 종료일"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "근로자 등록 시각(UTC)"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "마지막 수정 시각(UTC)"
          },
          "version": {
            "type": "integer",
            "format": "int64",
            "description": "낙관적 잠금 버전. PATCH 요청 시 expected_version으로 그대로 보내야 합니다.",
            "example": 0,
            "minimum": 0
          }
        },
        "required": [
          "company_id",
          "created_at",
          "display_name",
          "updated_at",
          "version",
          "work_status",
          "worker_id"
        ]
      },
      "WorkerDocumentCreateRequest": {
        "type": "object",
        "description": "근로자 서류 상태 등록 요청. MVP는 메타데이터 중심이며 파일 실체는 file_id로만 연결",
        "properties": {
          "document_type": {
            "type": "string",
            "description": "서류 유형",
            "enum": [
              "PASSPORT_COPY",
              "ARC",
              "CONTRACT",
              "PERMIT"
            ]
          },
          "submission_status": {
            "type": "string",
            "description": "제출 상태",
            "enum": [
              "MISSING",
              "SUBMITTED",
              "VERIFIED"
            ]
          },
          "expiry_date": {
            "type": "string",
            "format": "date",
            "description": "서류 유효기간",
            "example": "2027-03-01"
          },
          "destination": {
            "type": "string",
            "description": "제출처",
            "example": "출입국관리사무소",
            "maxLength": 120,
            "minLength": 0
          },
          "note": {
            "type": "string",
            "description": "메모",
            "maxLength": 500,
            "minLength": 0
          }
        },
        "required": [
          "document_type",
          "submission_status"
        ]
      },
      "WorkerDocumentResponse": {
        "type": "object",
        "description": "근로자 서류 상태 응답",
        "properties": {
          "worker_document_id": {
            "type": "string",
            "format": "uuid"
          },
          "worker_id": {
            "type": "string",
            "format": "uuid"
          },
          "document_type": {
            "type": "string",
            "enum": [
              "PASSPORT_COPY",
              "ARC",
              "CONTRACT",
              "PERMIT"
            ]
          },
          "submission_status": {
            "type": "string",
            "enum": [
              "MISSING",
              "SUBMITTED",
              "VERIFIED"
            ]
          },
          "expiry_date": {
            "type": "string",
            "format": "date"
          },
          "destination": {
            "type": "string"
          },
          "note": {
            "type": "string"
          },
          "file_id": {
            "type": "string",
            "format": "uuid"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "version": {
            "type": "integer",
            "format": "int64"
          }
        },
        "required": [
          "created_at",
          "document_type",
          "submission_status",
          "updated_at",
          "version",
          "worker_document_id",
          "worker_id"
        ]
      },
      "CreateTaskRequest": {
        "type": "object",
        "properties": {
          "worker_id": {
            "type": "string",
            "format": "uuid"
          },
          "case_id": {
            "type": "string",
            "format": "uuid"
          },
          "task_type": {
            "type": "string",
            "enum": [
              "RECONTRACT",
              "EMPLOYMENT_PERIOD_EXTENSION",
              "STAY_PERIOD_EXTENSION"
            ]
          },
          "workflow_id": {
            "type": "string",
            "maxLength": 100,
            "minLength": 0
          },
          "title": {
            "type": "string",
            "maxLength": 160,
            "minLength": 0
          },
          "description": {
            "type": "string",
            "maxLength": 2000,
            "minLength": 0
          },
          "due_date": {
            "type": "string",
            "format": "date"
          },
          "business_data": {
            "type": "object",
            "additionalProperties": {}
          }
        },
        "required": [
          "task_type",
          "title",
          "worker_id",
          "workflow_id"
        ]
      },
      "TaskChecklistItemResponse": {
        "type": "object",
        "properties": {
          "checklist_item_id": {
            "type": "string",
            "format": "uuid"
          },
          "item_code": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "required": {
            "type": "boolean"
          },
          "completed": {
            "type": "boolean"
          },
          "completed_by": {
            "type": "string",
            "format": "uuid"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time"
          },
          "version": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "TaskDetailResponse": {
        "type": "object",
        "properties": {
          "task_id": {
            "type": "string",
            "format": "uuid"
          },
          "worker_id": {
            "type": "string",
            "format": "uuid"
          },
          "case_id": {
            "type": "string",
            "format": "uuid"
          },
          "task_type": {
            "type": "string",
            "enum": [
              "RECONTRACT",
              "EMPLOYMENT_PERIOD_EXTENSION",
              "STAY_PERIOD_EXTENSION"
            ]
          },
          "workflow_id": {
            "type": "string"
          },
          "workflow_catalog_version": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "business_data": {
            "type": "object",
            "additionalProperties": {}
          },
          "source": {
            "type": "string",
            "enum": [
              "MANUAL",
              "SYSTEM_DDAY",
              "AI_CANDIDATE"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "DRAFT",
              "NEEDS_INFO",
              "READY_FOR_REVIEW",
              "APPROVED",
              "WAITING_WORKER",
              "WAITING_EXTERNAL",
              "COMPLETED",
              "CANCELLED"
            ]
          },
          "due_date": {
            "type": "string",
            "format": "date"
          },
          "content_revision": {
            "type": "integer",
            "format": "int64"
          },
          "version": {
            "type": "integer",
            "format": "int64"
          },
          "missing_required_slots": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "checklist_items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaskChecklistItemResponse"
            }
          },
          "created_by": {
            "type": "string",
            "format": "uuid"
          },
          "updated_by": {
            "type": "string",
            "format": "uuid"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "RejectTaskRequest": {
        "type": "object",
        "properties": {
          "expected_version": {
            "type": "integer",
            "format": "int64"
          },
          "reason": {
            "type": "string",
            "maxLength": 500,
            "minLength": 0
          }
        },
        "required": [
          "reason"
        ]
      },
      "ApprovalResponse": {
        "type": "object",
        "properties": {
          "approval_request_id": {
            "type": "string",
            "format": "uuid"
          },
          "task_id": {
            "type": "string",
            "format": "uuid"
          },
          "approval_status": {
            "type": "string",
            "enum": [
              "PENDING",
              "APPROVED",
              "REJECTED",
              "INVALIDATED"
            ]
          },
          "task_status": {
            "type": "string",
            "enum": [
              "DRAFT",
              "NEEDS_INFO",
              "READY_FOR_REVIEW",
              "APPROVED",
              "WAITING_WORKER",
              "WAITING_EXTERNAL",
              "COMPLETED",
              "CANCELLED"
            ]
          },
          "content_revision": {
            "type": "integer",
            "format": "int64"
          },
          "task_version": {
            "type": "integer",
            "format": "int64"
          },
          "requested_at": {
            "type": "string",
            "format": "date-time"
          },
          "decided_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ExternalSubmissionRequest": {
        "type": "object",
        "properties": {
          "expected_version": {
            "type": "integer",
            "format": "int64"
          },
          "destination": {
            "type": "string",
            "maxLength": 160,
            "minLength": 0
          },
          "safe_reference": {
            "type": "string",
            "maxLength": 300,
            "minLength": 0
          },
          "submitted_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "destination",
          "safe_reference"
        ]
      },
      "TaskActionResponse": {
        "type": "object",
        "properties": {
          "resource_id": {
            "type": "string",
            "format": "uuid"
          },
          "task_id": {
            "type": "string",
            "format": "uuid"
          },
          "task_status": {
            "type": "string",
            "enum": [
              "DRAFT",
              "NEEDS_INFO",
              "READY_FOR_REVIEW",
              "APPROVED",
              "WAITING_WORKER",
              "WAITING_EXTERNAL",
              "COMPLETED",
              "CANCELLED"
            ]
          },
          "task_version": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "EvidenceRequest": {
        "type": "object",
        "properties": {
          "evidence_type": {
            "type": "string",
            "enum": [
              "DOCUMENT",
              "RECEIPT",
              "OFFICIAL_RESULT",
              "HR_CONFIRMATION"
            ]
          },
          "file_reference": {
            "type": "string",
            "maxLength": 300,
            "minLength": 0
          },
          "note": {
            "type": "string",
            "maxLength": 500,
            "minLength": 0
          },
          "recorded_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "evidence_type"
        ]
      },
      "CompleteTaskRequest": {
        "type": "object",
        "properties": {
          "expected_version": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "CancelTaskRequest": {
        "type": "object",
        "properties": {
          "expected_version": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "reason": {
            "type": "string",
            "maxLength": 500,
            "minLength": 0
          }
        },
        "required": [
          "expected_version",
          "reason"
        ]
      },
      "ApproveTaskRequest": {
        "type": "object",
        "properties": {
          "expected_version": {
            "type": "integer",
            "format": "int64"
          },
          "reason": {
            "type": "string",
            "maxLength": 500,
            "minLength": 0
          }
        }
      },
      "ApprovalRequestBody": {
        "type": "object",
        "properties": {
          "expected_version": {
            "type": "integer",
            "format": "int64"
          },
          "ai_snapshot": {
            "type": "object",
            "additionalProperties": {}
          },
          "hr_snapshot": {
            "type": "object",
            "additionalProperties": {}
          },
          "changed_fields": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 120,
              "minLength": 0
            },
            "maxItems": 100,
            "minItems": 0
          },
          "source_versions": {
            "type": "object",
            "additionalProperties": {}
          }
        },
        "required": [
          "changed_fields",
          "hr_snapshot",
          "source_versions"
        ]
      },
      "SignupRequest": {
        "type": "object",
        "description": "사업장과 최초 ADMIN 계정 생성 요청",
        "properties": {
          "company_name": {
            "type": "string",
            "description": "가입할 사업장 표시 이름",
            "example": "한빛정밀",
            "maxLength": 120,
            "minLength": 0,
            "pattern": "^[^\\p{Cc}]+$"
          },
          "display_name": {
            "type": "string",
            "description": "최초 담당자의 화면 표시 이름",
            "example": "김경민",
            "maxLength": 80,
            "minLength": 0,
            "pattern": "^[^\\p{Cc}]+$"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "로그인에 사용할 이메일. 앞뒤 공백 제거 후 소문자로 정규화합니다.",
            "example": "name@company.com",
            "maxLength": 254,
            "minLength": 0
          },
          "password": {
            "type": "string",
            "format": "password",
            "description": "로그인 비밀번호. UTF-8 기준 72바이트 이하이며 원문은 저장하지 않고 BCrypt hash만 저장합니다.",
            "maxLength": 128,
            "minLength": 8,
            "writeOnly": true
          }
        },
        "required": [
          "company_name",
          "display_name",
          "email",
          "password"
        ]
      },
      "SignupResponse": {
        "type": "object",
        "description": "사업장과 최초 ADMIN 계정 생성 결과. Token은 발급하지 않습니다.",
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "등록된 로그인 이메일",
            "example": "name@company.com"
          },
          "role": {
            "type": "string",
            "description": "최초 계정 역할. Client 입력이 아니라 Server가 결정합니다.",
            "enum": [
              "ADMIN"
            ],
            "example": "ADMIN"
          },
          "user_id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "company_name": {
            "type": "string",
            "example": "한빛정밀"
          },
          "display_name": {
            "type": "string",
            "example": "김경민"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "company_id",
          "company_name",
          "created_at",
          "display_name",
          "email",
          "role",
          "user_id"
        ]
      },
      "RefreshResponse": {
        "type": "object",
        "description": "Refresh Token 회전 성공 응답. 새 Refresh Token은 HttpOnly 쿠키로만 전달됩니다.",
        "properties": {
          "access_token": {
            "type": "string",
            "description": "새로 발급한 JWT Access Token"
          },
          "token_type": {
            "type": "string",
            "enum": [
              "Bearer"
            ],
            "example": "Bearer"
          },
          "expires_in_seconds": {
            "type": "integer",
            "format": "int64",
            "description": "새 Access Token 만료까지 남은 초",
            "example": 900,
            "minimum": 1
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "새 Access Token 만료 시각(UTC)"
          }
        },
        "required": [
          "access_token",
          "expires_at",
          "expires_in_seconds",
          "token_type"
        ]
      },
      "LoginRequest": {
        "type": "object",
        "description": "사업장 사용자 로그인 요청",
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "로그인 이메일. 앞뒤 공백을 제거하고 소문자로 정규화해 조회합니다.",
            "example": "hr@example.com",
            "maxLength": 254,
            "minLength": 0
          },
          "password": {
            "type": "string",
            "format": "password",
            "description": "로그인 비밀번호. 128자 및 UTF-8 기준 72바이트 이하여야 하며 로그에 남기지 않습니다.",
            "maxLength": 128,
            "minLength": 0,
            "writeOnly": true
          }
        },
        "required": [
          "email",
          "password"
        ]
      },
      "LoginResponse": {
        "type": "object",
        "description": "로그인 성공 응답. Refresh Token은 본문이 아니라 HttpOnly 쿠키로 전달됩니다.",
        "properties": {
          "role": {
            "type": "string",
            "description": "사용자 역할",
            "enum": [
              "ADMIN",
              "HR",
              "VIEWER"
            ],
            "example": "HR"
          },
          "user_id": {
            "type": "string",
            "format": "uuid",
            "description": "로그인한 사용자 ID"
          },
          "company_id": {
            "type": "string",
            "format": "uuid",
            "description": "JWT로 고정되는 사업장 ID"
          },
          "company_name": {
            "type": "string",
            "description": "화면 표시용 사업장 이름",
            "example": "포우코 제조"
          },
          "display_name": {
            "type": "string",
            "description": "로그인한 담당자의 화면 표시 이름",
            "example": "김경민"
          },
          "access_token": {
            "type": "string",
            "description": "보호 API의 Authorization 헤더에 넣는 JWT Access Token",
            "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.<payload>.<signature>"
          },
          "token_type": {
            "type": "string",
            "description": "Authorization 헤더의 인증 방식",
            "enum": [
              "Bearer"
            ],
            "example": "Bearer"
          },
          "expires_in_seconds": {
            "type": "integer",
            "format": "int64",
            "description": "Access Token 만료까지 남은 초",
            "example": 900,
            "minimum": 1
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "Access Token 만료 시각(UTC)",
            "example": "2026-07-22T01:15:00Z"
          }
        },
        "required": [
          "access_token",
          "company_id",
          "company_name",
          "display_name",
          "expires_at",
          "expires_in_seconds",
          "role",
          "token_type",
          "user_id"
        ]
      },
      "WorkerPatchRequest": {
        "type": "object",
        "description": "근로자 부분 수정 요청. 보낸 필드만 갱신되며, 생략한 필드는 값이 없어도 변경하지 않습니다.",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "화면 표시용 근로자 이름. 생략 시 변경하지 않습니다.",
            "example": "응우옌반A",
            "maxLength": 120,
            "minLength": 0
          },
          "nationality_code": {
            "type": "string",
            "description": "국적 코드. 생략 시 변경하지 않습니다.",
            "example": "VN",
            "maxLength": 10,
            "minLength": 0
          },
          "preferred_language": {
            "type": "string",
            "description": "선호 언어. 생략 시 변경하지 않습니다.",
            "example": "vi",
            "maxLength": 20,
            "minLength": 0
          },
          "work_status": {
            "type": "string",
            "description": "근무 상태. 생략 시 변경하지 않습니다.",
            "enum": [
              "ACTIVE",
              "ON_LEAVE",
              "RESIGNED",
              "TERMINATED"
            ]
          },
          "stay_expiry_date": {
            "type": "string",
            "format": "date",
            "description": "체류 만료일. 생략 시 변경하지 않습니다.",
            "example": "2027-03-01"
          },
          "contract_start_date": {
            "type": "string",
            "format": "date",
            "description": "계약 시작일. 생략 시 변경하지 않습니다.",
            "example": "2026-01-01"
          },
          "contract_end_date": {
            "type": "string",
            "format": "date",
            "description": "계약 종료일. 생략 시 변경하지 않습니다.",
            "example": "2027-12-31"
          },
          "expected_version": {
            "type": "integer",
            "format": "int64",
            "description": "낙관적 잠금 버전. 마지막으로 조회한 WorkerResponse.version을 그대로 보내야 합니다.",
            "example": 0,
            "minimum": 0
          }
        },
        "required": [
          "expected_version"
        ]
      },
      "FieldErrorResponse": {
        "type": "object",
        "properties": {
          "field": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "WorkerDocumentPatchRequest": {
        "type": "object",
        "description": "근로자 서류 제출·검증·만료 상태와 유효기간을 부분 수정합니다.",
        "properties": {
          "document_type": {
            "type": "string",
            "description": "서류 유형. 생략 시 변경하지 않습니다.",
            "enum": [
              "PASSPORT_COPY",
              "ARC",
              "CONTRACT",
              "PERMIT"
            ]
          },
          "submission_status": {
            "type": "string",
            "description": "제출 상태. 생략 시 변경하지 않습니다.",
            "enum": [
              "MISSING",
              "SUBMITTED",
              "VERIFIED"
            ]
          },
          "expiry_date": {
            "type": "string",
            "format": "date",
            "description": "서류 유효기간. 생략 시 변경하지 않습니다."
          },
          "destination": {
            "type": "string",
            "description": "제출처. 생략 시 변경하지 않습니다.",
            "maxLength": 120,
            "minLength": 0
          },
          "note": {
            "type": "string",
            "description": "메모. 생략 시 변경하지 않습니다.",
            "maxLength": 500,
            "minLength": 0
          },
          "expected_version": {
            "type": "integer",
            "format": "int64",
            "description": "낙관적 잠금 버전. 마지막으로 조회한 WorkerDocumentResponse.version을 그대로 보내야 합니다."
          }
        },
        "required": [
          "expected_version"
        ]
      },
      "UpdateTaskRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 160,
            "minLength": 0
          },
          "description": {
            "type": "string",
            "maxLength": 2000,
            "minLength": 0
          },
          "due_date": {
            "type": "string",
            "format": "date"
          },
          "business_data": {
            "type": "object",
            "additionalProperties": {}
          },
          "expected_version": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        },
        "required": [
          "business_data",
          "expected_version",
          "title"
        ]
      },
      "UpdateChecklistItemRequest": {
        "type": "object",
        "properties": {
          "completed": {
            "type": "boolean"
          },
          "expected_version": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "expected_task_version": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        },
        "required": [
          "completed",
          "expected_task_version",
          "expected_version"
        ]
      },
      "WorkflowCatalogResponse": {
        "type": "object",
        "properties": {
          "bundle_id": {
            "type": "string"
          },
          "bundle_version": {
            "type": "string"
          },
          "bundle_status": {
            "type": "string"
          },
          "source_repository": {
            "type": "string"
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          },
          "workflows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowDefinitionResponse"
            }
          }
        }
      },
      "WorkflowChecklistResponse": {
        "type": "object",
        "properties": {
          "item_code": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "required": {
            "type": "boolean"
          }
        }
      },
      "WorkflowDefinitionResponse": {
        "type": "object",
        "properties": {
          "workflow_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "intent": {
            "type": "string"
          },
          "sensitivity": {
            "type": "string"
          },
          "supported_task_types": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "RECONTRACT",
                "EMPLOYMENT_PERIOD_EXTENSION",
                "STAY_PERIOD_EXTENSION"
              ]
            },
            "uniqueItems": true
          },
          "required_slots": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "uniqueItems": true
          },
          "checklist_items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowChecklistResponse"
            }
          },
          "completion_evidence": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "source_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "WorkerPageResponse": {
        "type": "object",
        "description": "근로자 목록 페이지 응답",
        "properties": {
          "items": {
            "type": "array",
            "description": "이번 페이지의 근로자 목록",
            "items": {
              "$ref": "#/components/schemas/WorkerResponse"
            }
          },
          "page": {
            "type": "integer",
            "format": "int32",
            "description": "현재 페이지 번호 (0부터 시작)",
            "example": 0
          },
          "size": {
            "type": "integer",
            "format": "int32",
            "description": "페이지당 항목 수",
            "example": 20
          },
          "total_elements": {
            "type": "integer",
            "format": "int64",
            "description": "전체 근로자 수",
            "example": 42
          }
        },
        "required": [
          "items",
          "page",
          "size",
          "total_elements"
        ]
      },
      "TaskPageResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaskSummaryResponse"
            }
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "size": {
            "type": "integer",
            "format": "int32"
          },
          "total_elements": {
            "type": "integer",
            "format": "int64"
          },
          "total_pages": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "TaskSummaryResponse": {
        "type": "object",
        "properties": {
          "task_id": {
            "type": "string",
            "format": "uuid"
          },
          "worker_id": {
            "type": "string",
            "format": "uuid"
          },
          "case_id": {
            "type": "string",
            "format": "uuid"
          },
          "task_type": {
            "type": "string",
            "enum": [
              "RECONTRACT",
              "EMPLOYMENT_PERIOD_EXTENSION",
              "STAY_PERIOD_EXTENSION"
            ]
          },
          "workflow_id": {
            "type": "string"
          },
          "workflow_catalog_version": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "enum": [
              "MANUAL",
              "SYSTEM_DDAY",
              "AI_CANDIDATE"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "DRAFT",
              "NEEDS_INFO",
              "READY_FOR_REVIEW",
              "APPROVED",
              "WAITING_WORKER",
              "WAITING_EXTERNAL",
              "COMPLETED",
              "CANCELLED"
            ]
          },
          "due_date": {
            "type": "string",
            "format": "date"
          },
          "content_revision": {
            "type": "integer",
            "format": "int64"
          },
          "version": {
            "type": "integer",
            "format": "int64"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AuditEventResponse": {
        "type": "object",
        "properties": {
          "audit_event_id": {
            "type": "string",
            "format": "uuid"
          },
          "actor_type": {
            "type": "string",
            "enum": [
              "HR_USER",
              "WORKER_LINK",
              "AI_AGENT",
              "SYSTEM_RULE"
            ]
          },
          "actor_id": {
            "type": "string",
            "format": "uuid"
          },
          "user_role": {
            "type": "string",
            "enum": [
              "ADMIN",
              "HR",
              "VIEWER"
            ]
          },
          "action": {
            "type": "string",
            "enum": [
              "TASK_CREATED",
              "TASK_UPDATED",
              "CHECKLIST_ITEM_UPDATED",
              "TASK_CANCELLED",
              "APPROVAL_REQUESTED",
              "TASK_APPROVED",
              "TASK_REJECTED",
              "APPROVAL_INVALIDATED",
              "EXTERNAL_SUBMISSION_RECORDED",
              "EVIDENCE_RECORDED",
              "TASK_COMPLETED"
            ]
          },
          "target_type": {
            "type": "string",
            "enum": [
              "TASK",
              "APPROVAL_REQUEST",
              "EXTERNAL_SUBMISSION",
              "EVIDENCE"
            ]
          },
          "target_id": {
            "type": "string",
            "format": "uuid"
          },
          "request_id": {
            "type": "string"
          },
          "trace_id": {
            "type": "string"
          },
          "event_version": {
            "type": "string"
          },
          "change_summary": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CurrentActorResponse": {
        "type": "object",
        "description": "검증된 Access Token에서 확인한 현재 사용자 Context",
        "properties": {
          "user_id": {
            "type": "string",
            "format": "uuid",
            "description": "현재 사용자 ID"
          },
          "company_id": {
            "type": "string",
            "format": "uuid",
            "description": "현재 요청에 고정된 사업장 ID"
          },
          "roles": {
            "type": "array",
            "description": "현재 사용자의 역할",
            "example": [
              "HR"
            ],
            "items": {
              "type": "string"
            }
          }
        }
      },
      "AuditPageResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AuditEventResponse"
            }
          },
          "next_cursor": {
            "type": "string"
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "요청 형식 또는 입력값 오류",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "$ref": "#/components/schemas/ApiErrorResponse"
            }
          }
        }
      },
      "EmailAlreadyRegistered": {
        "description": "이미 등록된 이메일로 가입할 수 없음",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "$ref": "#/components/schemas/ApiErrorResponse"
            },
            "example": {
              "path": "/api/v1/auth/signup",
              "request_id": "01-example-request-id",
              "status": 409,
              "code": "EMAIL_ALREADY_REGISTERED",
              "message": "이미 가입된 이메일입니다.",
              "field_errors": [],
              "timestamp": "2026-07-24T04:00:00Z"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "인증 필요",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "$ref": "#/components/schemas/ApiErrorResponse"
            }
          }
        }
      },
      "InvalidCredentials": {
        "description": "이메일·비밀번호·계정 또는 사업장 상태로 인한 로그인 실패",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "$ref": "#/components/schemas/ApiErrorResponse"
            },
            "example": {
              "path": "/api/v1/auth/login",
              "request_id": "01-example-request-id",
              "status": 401,
              "code": "INVALID_CREDENTIALS",
              "message": "이메일 또는 비밀번호를 확인해 주세요.",
              "field_errors": [],
              "timestamp": "2026-07-22T01:00:00Z"
            }
          }
        }
      },
      "InvalidRefreshToken": {
        "description": "Refresh Token이 없거나 유효하지 않아 재발급할 수 없음",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Set-Cookie": {
            "$ref": "#/components/headers/ExpiredRefreshTokenCookie"
          },
          "Cache-Control": {
            "description": "오류 응답 저장 방지",
            "schema": {
              "type": "string",
              "example": "no-store"
            }
          },
          "Pragma": {
            "description": "구형 캐시의 오류 응답 저장 방지",
            "schema": {
              "type": "string",
              "example": "no-cache"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "$ref": "#/components/schemas/ApiErrorResponse"
            },
            "example": {
              "path": "/api/v1/auth/refresh",
              "request_id": "01-example-request-id",
              "status": 401,
              "code": "INVALID_REFRESH_TOKEN",
              "message": "로그인 정보를 갱신할 수 없습니다. 다시 로그인해 주세요.",
              "field_errors": [],
              "timestamp": "2026-07-22T01:10:00Z"
            }
          }
        }
      },
      "Forbidden": {
        "description": "권한 부족",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "$ref": "#/components/schemas/ApiErrorResponse"
            }
          }
        }
      },
      "NotFound": {
        "description": "리소스를 찾을 수 없음",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "$ref": "#/components/schemas/ApiErrorResponse"
            }
          }
        }
      },
      "Conflict": {
        "description": "동시성 또는 현재 상태 충돌",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "$ref": "#/components/schemas/ApiErrorResponse"
            }
          }
        }
      },
      "UnprocessableEntity": {
        "description": "업무 규칙 또는 상태 전이 위반",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "$ref": "#/components/schemas/ApiErrorResponse"
            }
          }
        }
      },
      "MethodNotAllowed": {
        "description": "지원하지 않는 HTTP 메서드",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "$ref": "#/components/schemas/ApiErrorResponse"
            }
          }
        }
      },
      "NotAcceptable": {
        "description": "제공할 수 없는 응답 형식",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "$ref": "#/components/schemas/ApiErrorResponse"
            }
          }
        }
      },
      "UnsupportedMediaType": {
        "description": "지원하지 않는 요청 형식",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "$ref": "#/components/schemas/ApiErrorResponse"
            }
          }
        }
      },
      "InternalServerError": {
        "description": "서버 내부 오류",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "$ref": "#/components/schemas/ApiErrorResponse"
            }
          }
        }
      }
    },
    "headers": {
      "RequestId": {
        "description": "요청과 로그를 함께 찾기 위한 추적 ID",
        "schema": {
          "type": "string"
        }
      },
      "RefreshTokenCookie": {
        "description": "Refresh Token을 전달하는 HttpOnly 쿠키입니다. 원문은 JSON 응답에 포함하지 않습니다. MVP는 same-site 배포에서 SameSite=Strict 또는 Lax만 허용하며, SameSite=None은 CSRF 또는 신뢰 Origin 검증을 갖추기 전에는 사용하지 않습니다.",
        "schema": {
          "type": "string",
          "example": "fowoco_refresh_token=<opaque-token>; Path=/api/v1/auth; Max-Age=1209600; HttpOnly; SameSite=Strict"
        }
      },
      "ExpiredRefreshTokenCookie": {
        "description": "브라우저에 저장된 Refresh Token을 삭제하는 만료 쿠키입니다. 발급 쿠키와 같은 이름과 Path를 사용하고 Max-Age=0으로 만료시킵니다.",
        "schema": {
          "type": "string",
          "example": "fowoco_refresh_token=; Path=/api/v1/auth; Max-Age=0; HttpOnly; SameSite=Strict"
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "description": "로그인 응답의 Access Token을 Authorization: Bearer <access_token> 형식으로 전달합니다. JWT에는 sub(user_id), company_id, roles, token_type, iss, aud, exp, jti가 포함됩니다.",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      },
      "refreshCookie": {
        "type": "apiKey",
        "description": "Refresh·Logout에서만 사용하는 HttpOnly 쿠키입니다. JSON 본문이나 Authorization 헤더로 전송하지 않습니다.",
        "name": "fowoco_refresh_token",
        "in": "cookie"
      }
    }
  }
}
